class TestLocalVerifier(unittest.TestCase): def setUp(self): self.verifier = LocalVerifier() def test_expired_assertion(self): # It is invalid because it is expired. self.assertRaises(ValueError, self.verifier.verify, EXPIRED_ASSERTION) # But it'll verify OK if we wind back the clock. data = self.verifier.verify(EXPIRED_ASSERTION, now=0) self.assertEquals(data["audience"], "http://myfavoritebeer.org") # And will fail if we give the wrong audience. self.assertRaises(ValueError, self.verifier.verify, EXPIRED_ASSERTION, "h", 0) def test_expired_assertion_dev(self): # It is invalid because it is expired. self.assertRaises(ValueError, self.verifier.verify, EXPIRED_ASSERTION_DEV) # But it'll verify OK if we wind back the clock. data = self.verifier.verify(EXPIRED_ASSERTION_DEV, now=0) self.assertEquals(data["audience"], "http://dev.myfavoritebeer.org") # And will fail if we give the wrong audience. self.assertRaises(ValueError, self.verifier.verify, EXPIRED_ASSERTION_DEV, "h", 0) def test_junk(self): self.assertRaises(ValueError, self.verifier.verify, "JUNK") self.assertRaises(ValueError, self.verifier.verify, "J") self.assertRaises(ValueError, self.verifier.verify, "\x01\x02")
def test_cache_eviction_based_on_time(self): certs = CertificatesManager(FIFOCache(cache_timeout=0.1)) verifier = LocalVerifier(certs=certs, warning=False) # Prime the cache by verifying an assertion. assertion = make_assertion("*****@*****.**", "") self.assertTrue(verifier.verify(assertion)) # Make it error out if re-fetching the keys with patched_key_fetching(exc=RuntimeError("key fetch disabled")): verifier.fetch_public_key = fetch_public_key # It should be in the cache, so this works fine. verifier.verify(assertion) # But after sleeping it gets evicted and the error is triggered. time.sleep(0.1) self.assertRaises(RuntimeError, verifier.verify, assertion)
def test_cache_eviction_during_write(self): certs = CertificatesManager(cache_timeout=0.1) verifier = LocalVerifier(certs=certs, warning=False) # Prime the cache by verifying an assertion. assertion1 = make_assertion("*****@*****.**", "", "1.com") self.assertTrue(verifier.verify(assertion1)) self.assertEquals(len(certs.cache), 1) # Let that cached key expire time.sleep(0.1) # Now grab a different key; caching it should purge the expired key. assertion2 = make_assertion("*****@*****.**", "", "2.com") self.assertTrue(verifier.verify(assertion2)) self.assertEquals(len(certs.cache), 1) # Check that only the second entry is in cache. with patched_key_fetching(exc=RuntimeError("key fetch disabled")): self.assertTrue(verifier.verify(assertion2)) self.assertRaises(RuntimeError, verifier.verify, assertion1)
def test_cache_eviction_based_on_size(self): certs = CertificatesManager(max_size=2) verifier = LocalVerifier(certs=certs, warning=False) # Prime the cache by verifying some assertions. assertion1 = make_assertion("*****@*****.**", "", "1.com") self.assertTrue(verifier.verify(assertion1)) assertion2 = make_assertion("*****@*****.**", "", "2.com") self.assertTrue(verifier.verify(assertion2)) self.assertEquals(len(certs.cache), 2) # Hitting a third host should evict the first public key. assertion3 = make_assertion("*****@*****.**", "", "3.com") self.assertTrue(verifier.verify(assertion3)) self.assertEquals(len(certs.cache), 2) # Make it error out if re-fetching any keys with patched_key_fetching(exc=RuntimeError("key fetch disabled")): # It should have to re-fetch for 1, but not 2. self.assertTrue(verifier.verify(assertion2)) self.assertRaises(RuntimeError, verifier.verify, assertion1)
class TestLocalVerifier(unittest.TestCase): def setUp(self): self.verifier = LocalVerifier() def test_expired_assertion(self): # It is invalid because it is expired. self.assertRaises(ValueError, self.verifier.verify, EXPIRED_ASSERTION) # But it'll verify OK if we find back the clock. data = self.verifier.verify(EXPIRED_ASSERTION, now=0) self.assertEquals(data["audience"], "http://myfavoritebeer.org") self.assertEquals(data["email"], "*****@*****.**") def test_junk(self): self.assertRaises(ValueError, self.verifier.verify, "JUNK") self.assertRaises(ValueError, self.verifier.verify, "J") self.assertRaises(ValueError, self.verifier.verify, "\x01\x02")
def setUp(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") self.verifier = LocalVerifier() # There should be a warning about using this verifier. self.assertEquals(w[0].category, FutureWarning)
class TestLocalVerifier(unittest.TestCase, VerifierTestCases): def setUp(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") self.verifier = LocalVerifier() # There should be a warning about using this verifier. self.assertEquals(w[0].category, FutureWarning) def test_error_while_fetching_public_key(self): def urlopen(*args, **kwds): raise RuntimeError("TESTING") self.verifier.urlopen = urlopen self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_missing_well_known_document(self): def urlopen(url, data): raise RuntimeError("404 Not Found") self.verifier.urlopen = urlopen self.assertRaises(InvalidIssuerError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_malformed_well_known_document(self): def urlopen(url, data): class response(object): @staticmethod def read(): return "I AINT NO JSON, FOOL!" return response self.verifier.urlopen = urlopen self.assertRaises(InvalidIssuerError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_malformed_pub_key_document(self): called = [] def urlopen(url, data): # First call must raise 404 so it will look for /pk. # Second call must return invalid JSON. class response(object): @staticmethod def read(): if not called: called.append(True) raise ValueError("404 Not Found") return "I AINT NO JSON, FOOL!" return response self.verifier.urlopen = urlopen self.assertRaises(InvalidIssuerError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_well_known_doc_with_no_public_key(self): def urlopen(url, data): class response(object): @staticmethod def read(): return "{}" return response self.verifier.urlopen = urlopen self.assertRaises(InvalidIssuerError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_well_known_doc_with_public_key(self): # The browserid.org server doesn't currently have /.well-known/vep. # This simulates it with a dummy key. def urlopen(url, data): # NOQA class response(object): @staticmethod def read(): key = DummyVerifier.fetch_public_key("browserid.org") return json.dumps({"public-key": key}) return response self.verifier.urlopen = urlopen assertion = DummyVerifier.make_assertion("*****@*****.**", "http://e.com") self.assertTrue(self.verifier.verify(assertion)) def test_handling_of_invalid_content_length_header_from_server(self): def urlopen(url, data): class response(object): @staticmethod def info(): return {"Content-Length": "forty-two"} @staticmethod # NOQA def read(size): raise RuntimeError # pragma: nocover return response self.verifier.urlopen = urlopen self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_error_handling_in_verify_certificate_chain(self): self.assertRaises(ValueError, self.verifier.verify_certificate_chain, []) certs = decode_json_bytes(EXPIRED_ASSERTION)["certificates"] certs = [jwt.parse(cert) for cert in certs] self.assertRaises(ExpiredSignatureError, self.verifier.verify_certificate_chain, certs)
def setUp(self): self.verifier = LocalVerifier()
def setUp(self): with warnings.catch_warnings(record=True): warnings.simplefilter("default") self.verifier = LocalVerifier()
class TestLocalVerifier(unittest.TestCase, VerifierTestCases): def setUp(self): with warnings.catch_warnings(record=True): warnings.simplefilter("default") self.verifier = LocalVerifier() def test_expired_assertion(self): super(TestLocalVerifier, self).test_expired_assertion() # It'll verify OK if we wind back the clock. data = self.verifier.verify(EXPIRED_ASSERTION, now=0) self.assertEquals(data["audience"], "http://myfavoritebeer.org") # And will fail if we give the wrong audience. self.assertRaises(AudienceMismatchError, self.verifier.verify, EXPIRED_ASSERTION, "h", 0) def test_expired_assertion_dev(self): super(TestLocalVerifier, self).test_expired_assertion_dev() # It'll verify OK if we wind back the clock. data = self.verifier.verify(EXPIRED_ASSERTION_DEV, now=0) self.assertEquals(data["audience"], "http://dev.myfavoritebeer.org") # And will fail if we give the wrong audience. self.assertRaises(AudienceMismatchError, self.verifier.verify, EXPIRED_ASSERTION_DEV, "h", 0) def test_error_while_fetching_public_key(self): def fetch_public_key(hostname): raise RuntimeError("TESTING") self.verifier.fetch_public_key = fetch_public_key self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_missing_host_meta_document(self): def urlopen(url, data): raise RuntimeError("404 Not Found") self.verifier.urlopen = urlopen self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_malformed_host_meta_document(self): def urlopen(url, data): class response(object): @staticmethod def read(): return "I AINT NO XML, FOOL!" return response self.verifier.urlopen = urlopen self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_host_meta_with_no_key_link(self): def urlopen(url, data): class response(object): @staticmethod def read(): return "<Meta>"\ " <Link rel='not the key link' href='haha' />"\ "</Meta>" return response self.verifier.urlopen = urlopen self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_host_meta_with_key_link(self): # The browserid.org server doesn't currently have host-meta. # This simulates it with a link to the known public key URL. called = [] orig_urlopen = self.verifier.urlopen def urlopen(url, data): if called: return orig_urlopen("https://browserid.org/pk") called.append(True) class response(object): @staticmethod def read(): rel = self.verifier.HOST_META_REL_PUBKEY return "<Meta>"\ " <Link rel='" + rel + "' href='haha' />"\ "</Meta>" return response self.verifier.urlopen = urlopen self.assertTrue(self.verifier.verify(EXPIRED_ASSERTION, now=0)) def test_handling_of_invalid_content_length_header_from_server(self): def urlopen(url, data): class response(object): @staticmethod def info(): return {"Content-Length": "forty-two"} @staticmethod def read(size): raise RuntimeError # pragma: nocover return response self.verifier.urlopen = urlopen self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_error_handling_in_verify_certificate_chain(self): self.assertRaises(ValueError, self.verifier.verify_certificate_chain, []) certs = decode_json_bytes(EXPIRED_ASSERTION)["certificates"] certs = [JWT.parse(cert) for cert in certs] self.assertRaises(ExpiredSignatureError, self.verifier.verify_certificate_chain, certs) self.assertTrue(self.verifier.verify_certificate_chain(certs, 0))
def setUp(self): self.patched = patched_key_fetching() self.patched.__enter__() self.verifier = LocalVerifier(warning=False)
class TestDummyVerifier(unittest.TestCase, VerifierTestCases): def setUp(self): self.patched = patched_key_fetching() self.patched.__enter__() self.verifier = LocalVerifier(warning=False) def tearDown(self): self.patched.__exit__(None, None, None) def test_verification_of_valid_dummy_assertion(self): audience = "http://example.com" assertion = make_assertion("*****@*****.**", audience) self.assertTrue(self.verifier.verify(assertion)) self.assertTrue(self.verifier.verify(assertion, audience)) self.assertRaises(AudienceMismatchError, self.verifier.verify, assertion, "http://moz.com") def test_verification_of_oldstyle_dummy_assertion(self): audience = "http://example.com" assertion = make_assertion("*****@*****.**", audience, new_style=False) self.assertTrue(self.verifier.verify(assertion)) self.assertTrue(self.verifier.verify(assertion, audience)) self.assertRaises(AudienceMismatchError, self.verifier.verify, assertion, "http://moz.com") def test_verification_of_untrusted_issuer(self): audience = "http://example.com" issuer = "moz.com" # Assertions for @moz.com addresses can come from moz.com assertion = make_assertion("*****@*****.**", audience, issuer=issuer) self.assertTrue(self.verifier.verify(assertion, audience)) # But assertions for other addresses cannot. assertion = make_assertion("*****@*****.**", audience, issuer=issuer) self.assertRaises(InvalidSignatureError, self.verifier.verify, assertion, audience) def test_verification_of_expired_dummy_assertion(self): audience = "http://example.com" now = time.time() * 1000 assertion = make_assertion("*****@*****.**", audience, exp=now - 1) self.assertTrue(self.verifier.verify(assertion, now=now - 2)) self.assertRaises(ExpiredSignatureError, self.verifier.verify, assertion) def test_verification_of_dummy_assertion_with_bad_assertion_sig(self): audience = "http://example.com" assertion = make_assertion("*****@*****.**", audience, assertion_sig="BADTOTHEBONE") self.assertRaises(InvalidSignatureError, self.verifier.verify, assertion) def test_verification_of_dummy_assertion_with_bad_certificate_sig(self): audience = "http://example.com" assertion = make_assertion("*****@*****.**", audience, certificate_sig="CORRUPTUS") self.assertRaises(InvalidSignatureError, self.verifier.verify, assertion) def test_cache_eviction_based_on_time(self): certs = CertificatesManager(FIFOCache(cache_timeout=0.1)) verifier = LocalVerifier(certs=certs, warning=False) # Prime the cache by verifying an assertion. assertion = make_assertion("*****@*****.**", "") self.assertTrue(verifier.verify(assertion)) # Make it error out if re-fetching the keys with patched_key_fetching(exc=RuntimeError("key fetch disabled")): verifier.fetch_public_key = fetch_public_key # It should be in the cache, so this works fine. verifier.verify(assertion) # But after sleeping it gets evicted and the error is triggered. time.sleep(0.1) self.assertRaises(RuntimeError, verifier.verify, assertion) def test_cache_eviction_based_on_size(self): certs = CertificatesManager(max_size=2) verifier = LocalVerifier(certs=certs, warning=False) # Prime the cache by verifying some assertions. assertion1 = make_assertion("*****@*****.**", "", "1.com") self.assertTrue(verifier.verify(assertion1)) assertion2 = make_assertion("*****@*****.**", "", "2.com") self.assertTrue(verifier.verify(assertion2)) self.assertEquals(len(certs.cache), 2) # Hitting a third host should evict the first public key. assertion3 = make_assertion("*****@*****.**", "", "3.com") self.assertTrue(verifier.verify(assertion3)) self.assertEquals(len(certs.cache), 2) # Make it error out if re-fetching any keys with patched_key_fetching(exc=RuntimeError("key fetch disabled")): # It should have to re-fetch for 1, but not 2. self.assertTrue(verifier.verify(assertion2)) self.assertRaises(RuntimeError, verifier.verify, assertion1) def test_cache_eviction_during_write(self): certs = CertificatesManager(cache_timeout=0.1) verifier = LocalVerifier(certs=certs, warning=False) # Prime the cache by verifying an assertion. assertion1 = make_assertion("*****@*****.**", "", "1.com") self.assertTrue(verifier.verify(assertion1)) self.assertEquals(len(certs.cache), 1) # Let that cached key expire time.sleep(0.1) # Now grab a different key; caching it should purge the expired key. assertion2 = make_assertion("*****@*****.**", "", "2.com") self.assertTrue(verifier.verify(assertion2)) self.assertEquals(len(certs.cache), 1) # Check that only the second entry is in cache. with patched_key_fetching(exc=RuntimeError("key fetch disabled")): self.assertTrue(verifier.verify(assertion2)) self.assertRaises(RuntimeError, verifier.verify, assertion1)