class Provider(object): """ Interfaces with setup and bootstrapping operations for a provider """ zope.interface.implements(ILEAPComponent) PROBLEM_SIGNAL = "prov_problem_with_provider" def __init__(self, signaler=None, bypass_checks=False): """ Constructor for the Provider component :param signaler: Object in charge of handling communication back to the frontend :type signaler: Signaler :param bypass_checks: Set to true if the app should bypass first round of checks for CA certificates at bootstrap :type bypass_checks: bool """ object.__init__(self) self.key = "provider" self._provider_bootstrapper = ProviderBootstrapper(signaler, bypass_checks) self._download_provider_defer = None self._provider_config = ProviderConfig() def setup_provider(self, provider): """ Initiates the setup for a provider :param provider: URL for the provider :type provider: unicode :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ log.msg("Setting up provider %s..." % (provider.encode("idna"),)) pb = self._provider_bootstrapper d = pb.run_provider_select_checks(provider, download_if_needed=True) self._download_provider_defer = d return d def cancel_setup_provider(self): """ Cancel the ongoing setup provider defer (if any). """ d = self._download_provider_defer if d is not None: d.cancel() def bootstrap(self, provider): """ Second stage of bootstrapping for a provider. :param provider: URL for the provider :type provider: unicode :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ d = None # If there's no loaded provider or # we want to connect to other provider... if (not self._provider_config.loaded() or self._provider_config.get_domain() != provider): self._provider_config.load(get_provider_path(provider)) if self._provider_config.loaded(): d = self._provider_bootstrapper.run_provider_setup_checks( self._provider_config, download_if_needed=True) else: if self._signaler is not None: self._signaler.signal(self.PROBLEM_SIGNAL) logger.error("Could not load provider configuration.") self._login_widget.set_enabled(True) if d is None: d = defer.Deferred() return d
class ProviderBootstrapperTest(BaseLeapTest): def setUp(self): self.pb = ProviderBootstrapper() def tearDown(self): pass def test_name_resolution_check(self): # Something highly likely to success self.pb._domain = "google.com" self.pb._check_name_resolution() # Something highly likely to fail self.pb._domain = "uquhqweuihowquie.abc.def" # In python 2.7.4 raises socket.error # In python 2.7.5 raises socket.gaierror with self.assertRaises((socket.gaierror, socket.error)): self.pb._check_name_resolution() @deferred() def test_run_provider_select_checks(self): self.pb._check_name_resolution = mock.MagicMock() self.pb._check_https = mock.MagicMock() self.pb._download_provider_info = mock.MagicMock() d = self.pb.run_provider_select_checks("somedomain") def check(*args): self.pb._check_name_resolution.assert_called_once_with() self.pb._check_https.assert_called_once_with(None) self.pb._download_provider_info.assert_called_once_with(None) d.addCallback(check) return d @deferred() def test_run_provider_setup_checks(self): self.pb._download_ca_cert = mock.MagicMock() self.pb._check_ca_fingerprint = mock.MagicMock() self.pb._check_api_certificate = mock.MagicMock() d = self.pb.run_provider_setup_checks(ProviderConfig()) def check(*args): self.pb._download_ca_cert.assert_called_once_with() self.pb._check_ca_fingerprint.assert_called_once_with(None) self.pb._check_api_certificate.assert_called_once_with(None) d.addCallback(check) return d def test_should_proceed_cert(self): self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=where("cacert.pem")) self.pb._download_if_needed = False self.assertTrue(self.pb._should_proceed_cert()) self.pb._download_if_needed = True self.assertFalse(self.pb._should_proceed_cert()) self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=where("somefilethatdoesntexist.pem")) self.assertTrue(self.pb._should_proceed_cert()) def _check_download_ca_cert(self, should_proceed): """ Helper to check different paths easily for the download ca cert check :param should_proceed: sets the _should_proceed_cert in the provider bootstrapper being tested :type should_proceed: bool :returns: The contents of the certificate, the expected content depending on should_proceed, and the mode of the file to be checked by the caller :rtype: tuple of str, str, int """ old_content = "NOT THE NEW CERT" new_content = "NEW CERT" new_cert_path = os.path.join(tempfile.mkdtemp(), "mynewcert.pem") with open(new_cert_path, "w") as c: c.write(old_content) self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=new_cert_path) self.pb._domain = "somedomain" self.pb._should_proceed_cert = mock.MagicMock( return_value=should_proceed) read = None content_to_check = None mode = None with mock.patch('requests.models.Response.content', new_callable=mock.PropertyMock) as \ content: content.return_value = new_content response_obj = Response() response_obj.raise_for_status = mock.MagicMock() self.pb._session.get = mock.MagicMock(return_value=response_obj) self.pb._download_ca_cert() with open(new_cert_path, "r") as nc: read = nc.read() if should_proceed: content_to_check = new_content else: content_to_check = old_content mode = stat.S_IMODE(os.stat(new_cert_path).st_mode) os.unlink(new_cert_path) return read, content_to_check, mode def test_download_ca_cert_no_saving(self): read, expected_read, mode = self._check_download_ca_cert(False) self.assertEqual(read, expected_read) self.assertEqual(mode, int("600", 8)) def test_download_ca_cert_saving(self): read, expected_read, mode = self._check_download_ca_cert(True) self.assertEqual(read, expected_read) self.assertEqual(mode, int("600", 8)) def test_check_ca_fingerprint_skips(self): self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_fingerprint = mock.MagicMock( return_value="") self.pb._domain = "somedomain" self.pb._should_proceed_cert = mock.MagicMock(return_value=False) self.pb._check_ca_fingerprint() self.assertFalse(self.pb._provider_config. get_ca_cert_fingerprint.called) def test_check_ca_cert_fingerprint_raises_bad_format(self): self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_fingerprint = mock.MagicMock( return_value="wrongfprformat!!") self.pb._domain = "somedomain" self.pb._should_proceed_cert = mock.MagicMock(return_value=True) with self.assertRaises(WrongFingerprint): self.pb._check_ca_fingerprint() # This two hashes different in the last byte, but that's good enough # for the tests KNOWN_BAD_HASH = "SHA256: 0f17c033115f6b76ff67871872303ff65034efe" \ "7dd1b910062ca323eb4da5c7f" KNOWN_GOOD_HASH = "SHA256: 0f17c033115f6b76ff67871872303ff65034ef" \ "e7dd1b910062ca323eb4da5c7e" KNOWN_GOOD_CERT = """ -----BEGIN CERTIFICATE----- MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB 7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84 CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+ znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4 MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4 lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0 bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d 69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e yV8e -----END CERTIFICATE----- """ def _prepare_provider_config_with(self, cert_path, cert_hash): """ Mocks the provider config to give the cert_path and cert_hash specified :param cert_path: path for the certificate :type cert_path: str :param cert_hash: hash for the certificate as it would appear in the provider config json :type cert_hash: str """ self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_fingerprint = mock.MagicMock( return_value=cert_hash) self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=cert_path) self.pb._domain = "somedomain" def test_check_ca_fingerprint_checksout(self): cert_path = os.path.join(tempfile.mkdtemp(), "mynewcert.pem") with open(cert_path, "w") as c: c.write(self.KNOWN_GOOD_CERT) self._prepare_provider_config_with(cert_path, self.KNOWN_GOOD_HASH) self.pb._should_proceed_cert = mock.MagicMock(return_value=True) self.pb._check_ca_fingerprint() os.unlink(cert_path) def test_check_ca_fingerprint_fails(self): cert_path = os.path.join(tempfile.mkdtemp(), "mynewcert.pem") with open(cert_path, "w") as c: c.write(self.KNOWN_GOOD_CERT) self._prepare_provider_config_with(cert_path, self.KNOWN_BAD_HASH) self.pb._should_proceed_cert = mock.MagicMock(return_value=True) with self.assertRaises(WrongFingerprint): self.pb._check_ca_fingerprint() os.unlink(cert_path)
class Provider(object): """ Interfaces with setup and bootstrapping operations for a provider """ zope.interface.implements(ILEAPComponent) def __init__(self, signaler=None, bypass_checks=False): """ Constructor for the Provider component :param signaler: Object in charge of handling communication back to the frontend :type signaler: Signaler :param bypass_checks: Set to true if the app should bypass first round of checks for CA certificates at bootstrap :type bypass_checks: bool """ self.key = "provider" self._signaler = signaler self._provider_bootstrapper = ProviderBootstrapper( signaler, bypass_checks) self._download_provider_defer = None self._provider_config = ProviderConfig() def setup_provider(self, provider): """ Initiate the setup for a provider :param provider: URL for the provider :type provider: unicode :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ log.msg("Setting up provider %s..." % (provider.encode("idna"), )) pb = self._provider_bootstrapper d = pb.run_provider_select_checks(provider, download_if_needed=True) self._download_provider_defer = d return d def cancel_setup_provider(self): """ Cancel the ongoing setup provider defer (if any). """ d = self._download_provider_defer if d is not None: d.cancel() def bootstrap(self, provider): """ Second stage of bootstrapping for a provider. :param provider: URL for the provider :type provider: unicode :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ d = None config = ProviderConfig.get_provider_config(provider) self._provider_config = config if config is not None: d = self._provider_bootstrapper.run_provider_setup_checks( config, download_if_needed=True) else: if self._signaler is not None: self._signaler.signal( self._signaler.prov_problem_with_provider) logger.error("Could not load provider configuration.") self._login_widget.set_enabled(True) if d is None: d = defer.Deferred() return d def _get_services(self, domain): """ Returns a list of services provided by the given provider. :param domain: the provider to get the services from. :type domain: str :rtype: list of str """ services = [] provider_config = ProviderConfig.get_provider_config(domain) if provider_config is not None: services = provider_config.get_services() return services def get_supported_services(self, domain): """ Signal a list of supported services provided by the given provider. :param domain: the provider to get the services from. :type domain: str Signals: prov_get_supported_services -> list of unicode """ services = get_supported(self._get_services(domain)) self._signaler.signal(self._signaler.prov_get_supported_services, services) def get_all_services(self, providers): """ Signal a list of services provided by all the configured providers. :param providers: the list of providers to get the services. :type providers: list Signals: prov_get_all_services -> list of unicode """ services_all = set() for domain in providers: services = self._get_services(domain) services_all = services_all.union(set(services)) self._signaler.signal(self._signaler.prov_get_all_services, list(services_all)) def get_details(self, domain, lang=None): """ Signal a dict with the current ProviderConfig settings. :param domain: the domain name of the provider. :type domain: str :param lang: the language to use for localized strings. :type lang: str Signals: prov_get_details -> dict """ self._signaler.signal( self._signaler.prov_get_details, self._provider_config.get_light_config(domain, lang)) def get_pinned_providers(self): """ Signal the list of pinned provider domains. Signals: prov_get_pinned_providers -> list of provider domains """ self._signaler.signal(self._signaler.prov_get_pinned_providers, PinnedProviders.domains())
class Provider(object): """ Interfaces with setup and bootstrapping operations for a provider """ zope.interface.implements(ILEAPComponent) def __init__(self, signaler=None, bypass_checks=False): """ Constructor for the Provider component :param signaler: Object in charge of handling communication back to the frontend :type signaler: Signaler :param bypass_checks: Set to true if the app should bypass first round of checks for CA certificates at bootstrap :type bypass_checks: bool """ self.key = "provider" self._signaler = signaler self._provider_bootstrapper = ProviderBootstrapper(signaler, bypass_checks) self._download_provider_defer = None self._provider_config = ProviderConfig() def setup_provider(self, provider): """ Initiate the setup for a provider :param provider: URL for the provider :type provider: unicode :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ log.msg("Setting up provider %s..." % (provider.encode("idna"),)) pb = self._provider_bootstrapper d = pb.run_provider_select_checks(provider, download_if_needed=True) self._download_provider_defer = d return d def cancel_setup_provider(self): """ Cancel the ongoing setup provider defer (if any). """ d = self._download_provider_defer if d is not None: d.cancel() def bootstrap(self, provider): """ Second stage of bootstrapping for a provider. :param provider: URL for the provider :type provider: unicode :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ d = None config = ProviderConfig.get_provider_config(provider) self._provider_config = config if config is not None: d = self._provider_bootstrapper.run_provider_setup_checks( config, download_if_needed=True) else: if self._signaler is not None: self._signaler.signal( self._signaler.prov_problem_with_provider) logger.error("Could not load provider configuration.") self._login_widget.set_enabled(True) if d is None: d = defer.Deferred() return d def _get_services(self, domain): """ Returns a list of services provided by the given provider. :param domain: the provider to get the services from. :type domain: str :rtype: list of str """ services = [] provider_config = ProviderConfig.get_provider_config(domain) if provider_config is not None: services = provider_config.get_services() return services def get_supported_services(self, domain): """ Signal a list of supported services provided by the given provider. :param domain: the provider to get the services from. :type domain: str Signals: prov_get_supported_services -> list of unicode """ services = get_supported(self._get_services(domain)) self._signaler.signal( self._signaler.prov_get_supported_services, services) def get_all_services(self, providers): """ Signal a list of services provided by all the configured providers. :param providers: the list of providers to get the services. :type providers: list Signals: prov_get_all_services -> list of unicode """ services_all = set() for domain in providers: services = self._get_services(domain) services_all = services_all.union(set(services)) self._signaler.signal( self._signaler.prov_get_all_services, list(services_all)) def get_details(self, domain, lang=None): """ Signal a dict with the current ProviderConfig settings. :param domain: the domain name of the provider. :type domain: str :param lang: the language to use for localized strings. :type lang: str Signals: prov_get_details -> dict """ self._signaler.signal( self._signaler.prov_get_details, self._provider_config.get_light_config(domain, lang)) def get_pinned_providers(self): """ Signal the list of pinned provider domains. Signals: prov_get_pinned_providers -> list of provider domains """ self._signaler.signal( self._signaler.prov_get_pinned_providers, PinnedProviders.domains())
class ProviderBootstrapperTest(BaseLeapTest): def setUp(self): self.pb = ProviderBootstrapper() def tearDown(self): pass def test_name_resolution_check(self): # Something highly likely to success self.pb._domain = "google.com" self.pb._check_name_resolution() # Something highly likely to fail self.pb._domain = "uquhqweuihowquie.abc.def" # In python 2.7.4 raises socket.error # In python 2.7.5 raises socket.gaierror with self.assertRaises((socket.gaierror, socket.error)): self.pb._check_name_resolution() @deferred() def test_run_provider_select_checks(self): self.pb._check_name_resolution = mock.MagicMock() self.pb._check_https = mock.MagicMock() self.pb._download_provider_info = mock.MagicMock() d = self.pb.run_provider_select_checks("somedomain") def check(*args): self.pb._check_name_resolution.assert_called_once_with() self.pb._check_https.assert_called_once_with(None) self.pb._download_provider_info.assert_called_once_with(None) d.addCallback(check) return d @deferred() def test_run_provider_setup_checks(self): self.pb._download_ca_cert = mock.MagicMock() self.pb._check_ca_fingerprint = mock.MagicMock() self.pb._check_api_certificate = mock.MagicMock() d = self.pb.run_provider_setup_checks(ProviderConfig()) def check(*args): self.pb._download_ca_cert.assert_called_once_with() self.pb._check_ca_fingerprint.assert_called_once_with(None) self.pb._check_api_certificate.assert_called_once_with(None) d.addCallback(check) return d def test_should_proceed_cert(self): self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=where("cacert.pem")) self.pb._download_if_needed = False self.assertTrue(self.pb._should_proceed_cert()) self.pb._download_if_needed = True self.assertFalse(self.pb._should_proceed_cert()) self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=where("somefilethatdoesntexist.pem")) self.assertTrue(self.pb._should_proceed_cert()) def _check_download_ca_cert(self, should_proceed): """ Helper to check different paths easily for the download ca cert check :param should_proceed: sets the _should_proceed_cert in the provider bootstrapper being tested :type should_proceed: bool :returns: The contents of the certificate, the expected content depending on should_proceed, and the mode of the file to be checked by the caller :rtype: tuple of str, str, int """ old_content = "NOT THE NEW CERT" new_content = "NEW CERT" new_cert_path = os.path.join(tempfile.mkdtemp(), "mynewcert.pem") with open(new_cert_path, "w") as c: c.write(old_content) self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=new_cert_path) self.pb._domain = "somedomain" self.pb._should_proceed_cert = mock.MagicMock( return_value=should_proceed) read = None content_to_check = None mode = None with mock.patch('requests.models.Response.content', new_callable=mock.PropertyMock) as \ content: content.return_value = new_content response_obj = Response() response_obj.raise_for_status = mock.MagicMock() self.pb._session.get = mock.MagicMock(return_value=response_obj) self.pb._download_ca_cert() with open(new_cert_path, "r") as nc: read = nc.read() if should_proceed: content_to_check = new_content else: content_to_check = old_content mode = stat.S_IMODE(os.stat(new_cert_path).st_mode) os.unlink(new_cert_path) return read, content_to_check, mode def test_download_ca_cert_no_saving(self): read, expected_read, mode = self._check_download_ca_cert(False) self.assertEqual(read, expected_read) self.assertEqual(mode, int("600", 8)) def test_download_ca_cert_saving(self): read, expected_read, mode = self._check_download_ca_cert(True) self.assertEqual(read, expected_read) self.assertEqual(mode, int("600", 8)) def test_check_ca_fingerprint_skips(self): self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_fingerprint = mock.MagicMock( return_value="") self.pb._domain = "somedomain" self.pb._should_proceed_cert = mock.MagicMock(return_value=False) self.pb._check_ca_fingerprint() self.assertFalse( self.pb._provider_config.get_ca_cert_fingerprint.called) def test_check_ca_cert_fingerprint_raises_bad_format(self): self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_fingerprint = mock.MagicMock( return_value="wrongfprformat!!") self.pb._domain = "somedomain" self.pb._should_proceed_cert = mock.MagicMock(return_value=True) with self.assertRaises(WrongFingerprint): self.pb._check_ca_fingerprint() # This two hashes different in the last byte, but that's good enough # for the tests KNOWN_BAD_HASH = "SHA256: 0f17c033115f6b76ff67871872303ff65034efe" \ "7dd1b910062ca323eb4da5c7f" KNOWN_GOOD_HASH = "SHA256: 0f17c033115f6b76ff67871872303ff65034ef" \ "e7dd1b910062ca323eb4da5c7e" KNOWN_GOOD_CERT = """ -----BEGIN CERTIFICATE----- MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB 7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84 CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+ znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4 MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4 lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0 bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d 69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e yV8e -----END CERTIFICATE----- """ def _prepare_provider_config_with(self, cert_path, cert_hash): """ Mocks the provider config to give the cert_path and cert_hash specified :param cert_path: path for the certificate :type cert_path: str :param cert_hash: hash for the certificate as it would appear in the provider config json :type cert_hash: str """ self.pb._provider_config = mock.Mock() self.pb._provider_config.get_ca_cert_fingerprint = mock.MagicMock( return_value=cert_hash) self.pb._provider_config.get_ca_cert_path = mock.MagicMock( return_value=cert_path) self.pb._domain = "somedomain" def test_check_ca_fingerprint_checksout(self): cert_path = os.path.join(tempfile.mkdtemp(), "mynewcert.pem") with open(cert_path, "w") as c: c.write(self.KNOWN_GOOD_CERT) self._prepare_provider_config_with(cert_path, self.KNOWN_GOOD_HASH) self.pb._should_proceed_cert = mock.MagicMock(return_value=True) self.pb._check_ca_fingerprint() os.unlink(cert_path) def test_check_ca_fingerprint_fails(self): cert_path = os.path.join(tempfile.mkdtemp(), "mynewcert.pem") with open(cert_path, "w") as c: c.write(self.KNOWN_GOOD_CERT) self._prepare_provider_config_with(cert_path, self.KNOWN_BAD_HASH) self.pb._should_proceed_cert = mock.MagicMock(return_value=True) with self.assertRaises(WrongFingerprint): self.pb._check_ca_fingerprint() os.unlink(cert_path)