def test_cache_eviction_based_on_time(self): supportdocs = SupportDocumentManager(FIFOCache(cache_timeout=0.1)) verifier = LocalVerifier(["*"], supportdocs=supportdocs) # Prime the cache by verifying an assertion. assertion = make_assertion("*****@*****.**", "") self.assertTrue(verifier.verify(assertion)) # Make it error out if re-fetching the keys exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): # It should be in the cache, so this works fine. self.assertTrue(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_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 verifyBackedAssertion(audience, assertion): if True: from browserid import LocalVerifier v = LocalVerifier(["*"], warning=False) print "local verification", v.verify(assertion) return else: url = "https://verifier.accounts.firefox.com/v2" headers = {"content-type": "application/json"} r = requests.post(url, headers=headers, data=json.dumps({"audience": audience, "assertion": assertion})) if r.status_code != 200: raise WebError(r) return r.json()
def test_audience_verification(self): # create an assertion with the audience set to http://persona.org for # the tests. This assertion is only valid for this audience. assertion = make_assertion("*****@*****.**", "http://persona.org") # we don't set any audience explicitely here verifier = LocalVerifier() # specifying the audience on verifier.verify uses it. self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # if we change the audience to the expected one, the assertion is # considered valid self.assertTrue(verifier.verify(assertion, audience="persona.org")) # specifying the audience when creating the verifier AND when calling # verifier.verify. verifier = LocalVerifier(["*.example.com"]) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # specifying a different audience at instanciation and at verification, # only the last one is used. self.assertTrue(verifier.verify(assertion, audience="persona.org")) # overwritting the audience with an invalid one (we are waiting for # persona.org but getting example.com) raises an error self.assertRaises(AudienceMismatchError, verifier.verify, audience="persona.org", assertion=make_assertion("*****@*****.**", "http://example.com")) # the assertion is valid for http://persona.org; the verifier is # configured to accept this audience so it should validate verifier = LocalVerifier(["persona.org"]) self.assertTrue(verifier.verify(assertion)) # but if we ask explicitely for a different audience (the assertion is # not accepted, even if the instance is configured so) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="example.com")
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 verifyBackedAssertion(audience, assertion): if True: from browserid import LocalVerifier v = LocalVerifier(["*"], warning=False) print "local verification", v.verify(assertion) return else: url = "https://verifier.accounts.firefox.com/v2" headers = {"content-type": "application/json"} r = requests.post(url, headers=headers, data=json.dumps({ "audience": audience, "assertion": assertion })) if r.status_code != 200: raise WebError(r) return r.json()
def test_cache_eviction_during_write(self): supportdocs = SupportDocumentManager(cache_timeout=0.1) verifier = LocalVerifier(["*"], supportdocs=supportdocs) # Prime the cache by verifying an assertion. assertion1 = make_assertion("*****@*****.**", "", "1.com") self.assertTrue(verifier.verify(assertion1)) self.assertEquals(len(supportdocs.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(supportdocs.cache), 1) # Check that only the second entry is in cache. exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): 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)
def test_cache_eviction_based_on_size(self): supportdocs = SupportDocumentManager(max_size=2) verifier = LocalVerifier(["*"], supportdocs=supportdocs) # 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(supportdocs.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(supportdocs.cache), 2) # Make it error out if re-fetching any keys exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): # It should have to re-fetch for 1, but not 2. self.assertTrue(verifier.verify(assertion2)) self.assertRaises(RuntimeError, verifier.verify, assertion1)
def verify_assertion(audience, assertion, local=True): if local: v = LocalVerifier(["*"], warning=False) result = v.verify(assertion) else: url = "https://verifier.accounts.firefox.com/v2" payload = json.dumps({"audience": audience, "assertion": assertion}) req = urllib2.Request(url, data=payload) req.add_header("Content-Type", "application/json") req.get_method = lambda: 'POST' try: f = opener.open(req) result = json.loads(f.read()) f.close() except urllib2.URLError, e: raise WeaveException("FxA sync auth token request failed: " + str(e) + " " + e.read())
def test_account_login_persona(self): from floof.views.account import account_login_persona as view def verify(request, next_url, flash_msg): response = view(request.context, request) flashes = request.session['_f_'] assert len(flashes) == 1 assert flash_msg in flashes[0] assert response['redirect-to'] == next_url audience = 'https://localhost' self.config.add_settings({'auth.persona.audience': audience}) request = self._make_request() request.method = 'POST' request.user = sim.sim_user(credentials=[('persona', OLD_ASSERTION_ADDR)]) # Test failures trials = ((None, 'unspecified error'), ('', 'unspecified error'), (self._randstr(), 'unspecified error'), (OLD_ASSERTION, 'signature was invalid')) for a, f in trials: request.POST = MultiDict({'assertion': a}) verify(request, next_url=request.route_url('account.login'), flash_msg=f) request.session.clear() # Test success email = self._randstr() + '@example.com' verifier = LocalVerifier([audience], warning=False) a = make_assertion(email, audience) request.POST = MultiDict({'assertion': a}) request.user = sim.sim_user(credentials=[('persona', email)]) request.environ['paste.testing'] = True request.environ['tests.auth.persona.verifier'] = verifier request.environ['tests.auth.persona.audience'] = audience with patched_supportdoc_fetching(): verify(request, next_url=request.route_url('root'), flash_msg='Re-authentication successful')
def test_audience_pattern_checking(self): verifier = LocalVerifier(["*.moz.com", "www.test.com"], warning=False) # Domains like *.moz.com should be valid audiences. # They will work with both the implicit patterns and explicit audience. assertion = make_assertion("*****@*****.**", "www.moz.com") self.assertTrue(verifier.verify(assertion)) self.assertTrue(verifier.verify(assertion, "www.moz.com")) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, "www.test.com") # The specific domain www.test.com should be a valid audience. # It will work with both the implicit patterns and explicit audience. assertion = make_assertion("*****@*****.**", "www.test.com") self.assertTrue(verifier.verify(assertion)) self.assertTrue(verifier.verify(assertion, "www.test.com")) self.assertTrue(verifier.verify(assertion, "*.test.com")) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, "www.moz.com") # Domains not matching any patterns should not be valid audiences. # They will fail unless given as an explicit argument. assertion = make_assertion("*****@*****.**", "www.evil.com") self.assertRaises(AudienceMismatchError, verifier.verify, assertion) self.assertTrue(verifier.verify(assertion, "www.evil.com")) self.assertTrue(verifier.verify(assertion, "*.evil.com"))
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_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) @patch('browserid.certificates.fetch_public_key', fetch_public_key) def test_well_known_doc_with_public_key(self): assertion = make_assertion("*****@*****.**", "http://e.com") self.assertTrue(self.verifier.verify(assertion))
def test_email_validation(self): verifier = LocalVerifier(audiences="http://persona.org") # Null bytes in the email hostname. assertion = make_assertion("[email protected]\x00.com", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Newlines in the email hostanem. assertion = make_assertion("[email protected]\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Null bytes in the email username. assertion = make_assertion(u"test\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Null bytes with regex-busting newline. assertion = make_assertion(u"[email protected]\u0000\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion)
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): with patched_urlopen(exc=RuntimeError("TESTING")): self.assertRaises(ConnectionError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_missing_well_known_document(self): with patched_urlopen(exc=RuntimeError("404 Not Found")): self.assertRaises(InvalidIssuerError, self.verifier.verify, EXPIRED_ASSERTION, now=0) def test_malformed_well_known_document(self): # patch urlopen def urlopen(url, data): class response(object): @staticmethod def read(): return "I AINT NO JSON, FOOL!" return response with patched_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 with patched_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 with patched_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/browserid. # This simulates it with a dummy key. def urlopen(url, data): # NOQA class response(object): @staticmethod def read(): key = fetch_public_key("browserid.org") return json.dumps({"public-key": key}) return response with patched_urlopen(urlopen): assertion = 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 with patched_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.patched = patched_supportdoc_fetching() self.patched.__enter__() self.verifier = LocalVerifier(["*"])
class TestDummyVerifier(unittest.TestCase, VerifierTestCases): def setUp(self): self.patched = patched_supportdoc_fetching() self.patched.__enter__() self.verifier = LocalVerifier(["*"]) 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 (unless they delegated). 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): supportdocs = SupportDocumentManager(FIFOCache(cache_timeout=0.1)) verifier = LocalVerifier(["*"], supportdocs=supportdocs) # Prime the cache by verifying an assertion. assertion = make_assertion("*****@*****.**", "") self.assertTrue(verifier.verify(assertion)) # Make it error out if re-fetching the keys exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): # It should be in the cache, so this works fine. self.assertTrue(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): supportdocs = SupportDocumentManager(max_size=2) verifier = LocalVerifier(["*"], supportdocs=supportdocs) # 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(supportdocs.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(supportdocs.cache), 2) # Make it error out if re-fetching any keys exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): # 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): supportdocs = SupportDocumentManager(cache_timeout=0.1) verifier = LocalVerifier(["*"], supportdocs=supportdocs) # Prime the cache by verifying an assertion. assertion1 = make_assertion("*****@*****.**", "", "1.com") self.assertTrue(verifier.verify(assertion1)) self.assertEquals(len(supportdocs.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(supportdocs.cache), 1) # Check that only the second entry is in cache. exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): self.assertTrue(verifier.verify(assertion2)) self.assertRaises(RuntimeError, verifier.verify, assertion1) def test_audience_pattern_checking(self): verifier = LocalVerifier(["*.moz.com", "www.test.com"]) # Domains like *.moz.com should be valid audiences. # They will work with both the implicit patterns and explicit audience. assertion = make_assertion("*****@*****.**", "www.moz.com") self.assertTrue(verifier.verify(assertion)) self.assertTrue(verifier.verify(assertion, "www.moz.com")) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, "www.test.com") # The specific domain www.test.com should be a valid audience. # It will work with both the implicit patterns and explicit audience. assertion = make_assertion("*****@*****.**", "www.test.com") self.assertTrue(verifier.verify(assertion)) self.assertTrue(verifier.verify(assertion, "www.test.com")) self.assertTrue(verifier.verify(assertion, "*.test.com")) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, "www.moz.com") # Domains not matching any patterns should not be valid audiences. # They will fail unless given as an explicit argument. assertion = make_assertion("*****@*****.**", "www.evil.com") self.assertRaises(AudienceMismatchError, verifier.verify, assertion) self.assertTrue(verifier.verify(assertion, "www.evil.com")) self.assertTrue(verifier.verify(assertion, "*.evil.com"))
class TestDummyVerifier(unittest.TestCase, VerifierTestCases): def setUp(self): self.patched = patched_supportdoc_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 (unless they delegated). 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): supportdocs = SupportDocumentManager(FIFOCache(cache_timeout=0.1)) verifier = LocalVerifier(["*"], supportdocs=supportdocs, 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 exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): # It should be in the cache, so this works fine. self.assertTrue(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): supportdocs = SupportDocumentManager(max_size=2) verifier = LocalVerifier(["*"], supportdocs=supportdocs, 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(supportdocs.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(supportdocs.cache), 2) # Make it error out if re-fetching any keys exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): # 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): supportdocs = SupportDocumentManager(cache_timeout=0.1) verifier = LocalVerifier(["*"], supportdocs=supportdocs, warning=False) # Prime the cache by verifying an assertion. assertion1 = make_assertion("*****@*****.**", "", "1.com") self.assertTrue(verifier.verify(assertion1)) self.assertEquals(len(supportdocs.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(supportdocs.cache), 1) # Check that only the second entry is in cache. exc = RuntimeError("key fetch disabled") with patched_supportdoc_fetching(exc=exc): self.assertTrue(verifier.verify(assertion2)) self.assertRaises(RuntimeError, verifier.verify, assertion1) def test_audience_pattern_checking(self): verifier = LocalVerifier(["*.moz.com", "www.test.com"], warning=False) # Domains like *.moz.com should be valid audiences. # They will work with both the implicit patterns and explicit audience. assertion = make_assertion("*****@*****.**", "www.moz.com") self.assertTrue(verifier.verify(assertion)) self.assertTrue(verifier.verify(assertion, "www.moz.com")) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, "www.test.com") # The specific domain www.test.com should be a valid audience. # It will work with both the implicit patterns and explicit audience. assertion = make_assertion("*****@*****.**", "www.test.com") self.assertTrue(verifier.verify(assertion)) self.assertTrue(verifier.verify(assertion, "www.test.com")) self.assertTrue(verifier.verify(assertion, "*.test.com")) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, "www.moz.com") # Domains not matching any patterns should not be valid audiences. # They will fail unless given as an explicit argument. assertion = make_assertion("*****@*****.**", "www.evil.com") self.assertRaises(AudienceMismatchError, verifier.verify, assertion) self.assertTrue(verifier.verify(assertion, "www.evil.com")) self.assertTrue(verifier.verify(assertion, "*.evil.com"))
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 no warning about using this verifier. self.assertEquals(len(w), 0) @callwith(patched_supportdoc_fetching()) 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) @callwith(patched_supportdoc_fetching()) def test_well_known_doc_with_public_key(self): assertion = make_assertion("*****@*****.**", "http://e.com") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_delegated_primary(self): assertion = make_assertion("*****@*****.**", "http://persona.org", issuer="delegated.org") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_double_delegated_primary(self): assertion = make_assertion("*****@*****.**", "http://persona.org", issuer="delegated.org") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_extraction_of_extra_claims(self): assertion = make_assertion("*****@*****.**", "http://e.com", idp_claims={"extra": "claim"}, user_claims={"another": "claim"}, ) result = self.verifier.verify(assertion) self.assertEqual(result["status"], "okay") self.assertEqual(result["idpClaims"], {"extra": "claim"}) self.assertEqual(result["userClaims"], {"another": "claim"}) @callwith(patched_supportdoc_fetching()) def test_extraction_of_extra_claims_from_principal(self): assertion = make_assertion("*****@*****.**", "http://e.com", idp_claims={ "extra": "claim", "principal": { "email": "*****@*****.**", "another": "claim", "public-key": "should-be-ignored", } }, ) result = self.verifier.verify(assertion) self.assertEqual(result["status"], "okay") self.assertEqual(result["idpClaims"], { "extra": "claim", "another": "claim", }) self.assertTrue("userClaims" not in result) @callwith(patched_supportdoc_fetching()) def test_email_validation(self): verifier = LocalVerifier(audiences="http://persona.org") # Null bytes in the email hostname. assertion = make_assertion("[email protected]\x00.com", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Newlines in the email hostanem. assertion = make_assertion("[email protected]\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Null bytes in the email username. assertion = make_assertion(u"test\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Null bytes with regex-busting newline. assertion = make_assertion(u"[email protected]\u0000\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) @callwith(patched_supportdoc_fetching()) def test_audience_verification(self): # create an assertion with the audience set to http://persona.org for # the tests. This assertion is only valid for this audience. assertion = make_assertion("*****@*****.**", "http://persona.org") # we don't set any audience explicitely here verifier = LocalVerifier() # specifying the audience on verifier.verify uses it. self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # if we change the audience to the expected one, the assertion is # considered valid self.assertTrue(verifier.verify(assertion, audience="persona.org")) # specifying the audience when creating the verifier AND when calling # verifier.verify. verifier = LocalVerifier(["*.example.com"]) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # specifying a different audience at instanciation and at verification, # only the last one is used. self.assertTrue(verifier.verify(assertion, audience="persona.org")) # overwritting the audience with an invalid one (we are waiting for # persona.org but getting example.com) raises an error self.assertRaises(AudienceMismatchError, verifier.verify, audience="persona.org", assertion=make_assertion("*****@*****.**", "http://example.com")) # the assertion is valid for http://persona.org; the verifier is # configured to accept this audience so it should validate verifier = LocalVerifier(["persona.org"]) self.assertTrue(verifier.verify(assertion)) # but if we ask explicitely for a different audience (the assertion is # not accepted, even if the instance is configured so) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="example.com")
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 no warning about using this verifier. self.assertEquals(len(w), 0) @callwith(patched_supportdoc_fetching()) 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) @callwith(patched_supportdoc_fetching()) def test_well_known_doc_with_public_key(self): assertion = make_assertion("*****@*****.**", "http://e.com") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_delegated_primary(self): assertion = make_assertion("*****@*****.**", "http://persona.org", issuer="delegated.org") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_double_delegated_primary(self): assertion = make_assertion("*****@*****.**", "http://persona.org", issuer="delegated.org") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_extraction_of_extra_claims(self): assertion = make_assertion( "*****@*****.**", "http://e.com", idp_claims={"extra": "claim"}, user_claims={"another": "claim"}, ) result = self.verifier.verify(assertion) self.assertEqual(result["status"], "okay") self.assertEqual(result["idpClaims"], {"extra": "claim"}) self.assertEqual(result["userClaims"], {"another": "claim"}) @callwith(patched_supportdoc_fetching()) def test_extraction_of_extra_claims_from_principal(self): assertion = make_assertion( "*****@*****.**", "http://e.com", idp_claims={ "extra": "claim", "principal": { "email": "*****@*****.**", "another": "claim", "public-key": "should-be-ignored", } }, ) result = self.verifier.verify(assertion) self.assertEqual(result["status"], "okay") self.assertEqual(result["idpClaims"], { "extra": "claim", "another": "claim", }) self.assertTrue("userClaims" not in result) @callwith(patched_supportdoc_fetching()) def test_email_validation(self): verifier = LocalVerifier(audiences="http://persona.org") # Null bytes in the email hostname. assertion = make_assertion("[email protected]\x00.com", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Newlines in the email hostanem. assertion = make_assertion("[email protected]\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Null bytes in the email username. assertion = make_assertion(u"test\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) # Null bytes with regex-busting newline. assertion = make_assertion(u"[email protected]\u0000\[email protected]", "http://persona.org") self.assertRaises(ValueError, verifier.verify, assertion) @callwith(patched_supportdoc_fetching()) def test_audience_verification(self): # create an assertion with the audience set to http://persona.org for # the tests. This assertion is only valid for this audience. assertion = make_assertion("*****@*****.**", "http://persona.org") # we don't set any audience explicitely here verifier = LocalVerifier() # specifying the audience on verifier.verify uses it. self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # if we change the audience to the expected one, the assertion is # considered valid self.assertTrue(verifier.verify(assertion, audience="persona.org")) # specifying the audience when creating the verifier AND when calling # verifier.verify. verifier = LocalVerifier(["*.example.com"]) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # specifying a different audience at instanciation and at verification, # only the last one is used. self.assertTrue(verifier.verify(assertion, audience="persona.org")) # overwritting the audience with an invalid one (we are waiting for # persona.org but getting example.com) raises an error self.assertRaises(AudienceMismatchError, verifier.verify, audience="persona.org", assertion=make_assertion("*****@*****.**", "http://example.com")) # the assertion is valid for http://persona.org; the verifier is # configured to accept this audience so it should validate verifier = LocalVerifier(["persona.org"]) self.assertTrue(verifier.verify(assertion)) # but if we ask explicitely for a different audience (the assertion is # not accepted, even if the instance is configured so) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="example.com")
def setUp(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") self.verifier = LocalVerifier(["*"]) # There should be no warning about using this verifier. self.assertEquals(len(w), 0)
def setUp(self): self.patched = patched_key_fetching() self.patched.__enter__() self.verifier = LocalVerifier(["*"], warning=False)
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_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) @callwith(patched_supportdoc_fetching()) def test_well_known_doc_with_public_key(self): assertion = make_assertion("*****@*****.**", "http://e.com") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_delegated_primary(self): assertion = make_assertion("*****@*****.**", "http://persona.org", issuer="delegated.org") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_double_delegated_primary(self): assertion = make_assertion("*****@*****.**", "http://persona.org", issuer="delegated.org") self.assertTrue(self.verifier.verify(assertion)) @callwith(patched_supportdoc_fetching()) def test_audience_verification(self): # create an assertion with the audience set to http://persona.org for # the tests. This assertion is only valid for this audience. assertion = make_assertion("*****@*****.**", "http://persona.org") # we don't set any audience explicitely here verifier = LocalVerifier(warning=False) # specifying the audience on verifier.verify uses it. self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # if we change the audience to the expected one, the assertion is # considered valid self.assertTrue(verifier.verify(assertion, audience="persona.org")) # specifying the audience when creating the verifier AND when calling # verifier.verify. verifier = LocalVerifier(["*.example.com"], warning=False) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # specifying a different audience at instanciation and at verification, # only the last one is used. self.assertTrue(verifier.verify(assertion, audience="persona.org")) # overwritting the audience with an invalid one (we are waiting for # persona.org but getting example.com) raises an error self.assertRaises(AudienceMismatchError, verifier.verify, audience="persona.org", assertion=make_assertion("*****@*****.**", "http://example.com")) # the assertion is valid for http://persona.org; the verifier is # configured to accept this audience so it should validate verifier = LocalVerifier(["persona.org"], warning=False) self.assertTrue(verifier.verify(assertion)) # but if we ask explicitely for a different audience (the assertion is # not accepted, even if the instance is configured so) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="example.com")
def setUp(self): self.patched = patched_supportdoc_fetching() self.patched.__enter__() self.verifier = LocalVerifier(["*"], warning=False)
def setUp(self): super(TestWorkerPoolVerifier, self).setUp() self.verifier = WorkerPoolVerifier(verifier=LocalVerifier(["*"]))
def setUp(self): super(TestWorkerPoolVerifier, self).setUp() self.verifier = WorkerPoolVerifier( verifier=LocalVerifier(["*"], warning=False) )
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_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) @patch('browserid.certificates.fetch_public_key', fetch_public_key) def test_well_known_doc_with_public_key(self): assertion = make_assertion("*****@*****.**", "http://e.com") self.assertTrue(self.verifier.verify(assertion)) @patch('browserid.certificates.fetch_public_key', fetch_public_key) def test_audience_verification(self): # create an assertion with the audience set to http://persona.org for # the tests. This assertion is only valid for this audience. assertion = make_assertion("*****@*****.**", "http://persona.org") # we don't set any audience explicitely here verifier = LocalVerifier(warning=False) # specifying the audience on verifier.verify uses it. self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # if we change the audience to the expected one, the assertion is # considered valid self.assertTrue(verifier.verify(assertion, audience="persona.org")) # specifying the audience when creating the verifier AND when calling # verifier.verify. verifier = LocalVerifier(["*.example.com"], warning=False) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="*.example.com") # specifying a difference audience at instanciation and at verification, # only the last one is used. self.assertTrue(verifier.verify(assertion, audience="persona.org")) # overwritting the audience with an invalid one (we are waiting for # persona.org but getting example.com) raises an error self.assertRaises(AudienceMismatchError, verifier.verify, audience="persona.org", assertion=make_assertion("*****@*****.**", "http://example.com")) # the assertion is valid for http://persona.org; the verifier is # configured to accept this audience so it should validate verifier = LocalVerifier(["persona.org"], warning=False) self.assertTrue(verifier.verify(assertion)) # but if we ask explicitely for a different audience (the assertion is # not accepted, even if the instance is configured so) self.assertRaises(AudienceMismatchError, verifier.verify, assertion, audience="example.com")