def __init__(self, app_name, cert=None, key=None, ca_bundle=None, authserver="login.ancient-solutions.com"): """Set up the authentication client so it can be used lateron. Args: app_name: The name the login server shall display to the user. cert: Path to the certificate to use for signing the requests, or the contents of the certificate. key: Path to the private key to use for signing the requests, or the contents of the key. ca_bundle: path to a CA bundle file to use for authenticating the server. """ if key is not None and type(key) == str and exists(key): self._rsa_key = rsa.UnwrapRSAKey(key) elif key is not None and isinstance(key, RSA._RSAobj): self._rsa_key = key elif key is not None: self._rsa_key = RSA.importKey(key) else: self._rsa_key = None if cert is not None and type(cert) == str and exists(cert): self._cert = x509.parse_certificate_file(cert) f = open(cert) self._plain_cert = f.read() f.close() elif cert is not None and isinstance(cert, x509.Certificate): self._cert = cert # TODO: We'll need the plaintext certificate here... elif cert is not None: self._cert = x509.parse_certificate(cert) self._plain_cert = cert else: self._cert = None self._plain_cert = None if ca_bundle is not None and type(ca_bundle) == str and exists( ca_bundle): self._ca = x509.parse_certificate_file(ca_bundle) elif ca_bundle is not None and isinstance(ca_bundle, x509.Certificate): self._ca = ca_bundle elif ca_bundle is not None: self._ca = x509.parse_certificate(ca_bundle) else: self._ca = None self._app_name = app_name self._authserver = authserver
def __init__(self, app_name, cert=None, key=None, ca_bundle=None, authserver="login.ancient-solutions.com"): """Set up the authentication client so it can be used lateron. Args: app_name: The name the login server shall display to the user. cert: Path to the certificate to use for signing the requests, or the contents of the certificate. key: Path to the private key to use for signing the requests, or the contents of the key. ca_bundle: path to a CA bundle file to use for authenticating the server. """ if key is not None and type(key) == str and exists(key): self._rsa_key = rsa.UnwrapRSAKey(key) elif key is not None and isinstance(key, RSA._RSAobj): self._rsa_key = key elif key is not None: self._rsa_key = RSA.importKey(key) else: self._rsa_key = None if cert is not None and type(cert) == str and exists(cert): self._cert = x509.parse_certificate_file(cert) f = open(cert) self._plain_cert = f.read() f.close() elif cert is not None and isinstance(cert, x509.Certificate): self._cert = cert # TODO: We'll need the plaintext certificate here... elif cert is not None: self._cert = x509.parse_certificate(cert) self._plain_cert = cert else: self._cert = None self._plain_cert = None if ca_bundle is not None and type(ca_bundle) == str and exists(ca_bundle): self._ca = x509.parse_certificate_file(ca_bundle) elif ca_bundle is not None and isinstance(ca_bundle, x509.Certificate): self._ca = ca_bundle elif ca_bundle is not None: self._ca = x509.parse_certificate(ca_bundle) else: self._ca = None self._app_name = app_name self._authserver = authserver
def test_request_authorization(self): """Test if we can request authorization correctly.""" cert = x509.parse_certificate(_TEST_CERT) auth = authenticator.Authenticator("Unit Test", cert=_TEST_CERT, key=_TEST_KEY) dest = authenticator.urlparse( auth.request_authorization( 'http://bazquux.foo/asdf/bsdf?q=x&r=x#asd')) self.assertEqual("https", dest.scheme) self.assertEqual("login.ancient-solutions.com", dest.hostname) self.assertEqual("/", dest.path) query = authenticator.parse_qs(dest.query) self.assertEqual(["token"], query["response_type"]) self.assertEqual(["http://bazquux.foo/asdf/bsdf?q=x&r=x#asd"], query["redirect_uri"]) self.assertIn("client_id", query) atr = token_pb2.AuthTokenRequest() cdc = token_cookie.AuthTokenRequestCodec(atr, pubkey=cert.get_pub_key()) try: cdc.decode(query["client_id"][0]) except token_cookie.SignatureException as e: self.fail("Cannot validate signature on auth token request") self.assertEqual("Unit Test", atr.app_name) self.assertEqual("http://bazquux.foo/asdf/bsdf?q=x&r=x#asd", atr.original_uri) self.assertEqual("http://bazquux.foo/login", atr.return_uri)
def test_request_authorization(self): """Test if we can request authorization correctly.""" cert = x509.parse_certificate(_TEST_CERT) auth = authenticator.Authenticator("Unit Test", cert=_TEST_CERT, key=_TEST_KEY) dest = authenticator.urlparse(auth.request_authorization( 'http://bazquux.foo/asdf/bsdf?q=x&r=x#asd')) self.assertEqual("https", dest.scheme) self.assertEqual("login.ancient-solutions.com", dest.hostname) self.assertEqual("/", dest.path) query = authenticator.parse_qs(dest.query) self.assertEqual(["token"], query["response_type"]) self.assertEqual(["http://bazquux.foo/asdf/bsdf?q=x&r=x#asd"], query["redirect_uri"]) self.assertIn("client_id", query) atr = token_pb2.AuthTokenRequest() cdc = token_cookie.AuthTokenRequestCodec(atr, pubkey=cert.get_pub_key()) try: cdc.decode(query["client_id"][0]) except token_cookie.SignatureException as e: self.fail("Cannot validate signature on auth token request") self.assertEqual("Unit Test", atr.app_name) self.assertEqual("http://bazquux.foo/asdf/bsdf?q=x&r=x#asd", atr.original_uri) self.assertEqual("http://bazquux.foo/login", atr.return_uri)
def test_verify_unknown_signer(self): """Verify a wrong signature.""" cert, key = gen_certificate() cacert = x509.parse_certificate(_TEST_CA) # Set up a token cookie with test data. atr = token_pb2.AuthTokenResponse() set_basic_creds(atr.basic_creds) atr.certificate = _TEST_CERT atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' atr.granted = calendar.timegm(datetime.now().timetuple()) atr.random = 'A' * 42 # TODO(tonnerre): This should go away. # Create the codec and encode. atrc = token_cookie.AuthTokenResponseCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenResponse() vatrc = token_cookie.AuthTokenResponseCodec(vatr, cacert=cacert) self.assertRaises(token_cookie.SignatureException, vatrc.decode, data)
def test_sign_and_decrypt(self): """Encode and decode an authentication token request object.""" # We need a CA signed certificate, so we use the one # from above. cert = x509.parse_certificate(_TEST_CERT) key = RSA.importKey(_TEST_KEY) cacert = x509.parse_certificate(_TEST_CA) # Sanity check for the above certificates. self.assertTrue(cert.check_signature(cacert)) # Create an AuthTokenRequest with some correct-sounding data. atr = token_pb2.AuthTokenRequest() atr.certificate = _TEST_CERT atr.return_uri = 'https://localhost/login' atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' # Create the codec and encode. atrc = token_cookie.AuthTokenRequestCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenRequest() vatrc = token_cookie.AuthTokenRequestCodec(vatr, pubkey=cert.get_pub_key()) try: vatrc.decode(data) except token_cookie.SignatureException as e: # TODO(tonnerre): Reenable this test. self.fail("Can't verify signature using original certificate") self.assertEqual(atr, vatr) # Decode again, using the contained certificate. vatr.Clear() vatrc = token_cookie.AuthTokenRequestCodec(vatr, cacert=cacert) try: vatrc.decode(data) except token_cookie.SignatureException as e: # TODO(tonnerre): reenable this test. # self.fail("Can't verify signature using inband certificate") pass self.assertEqual(atr, vatr)
def test_sign_and_decrypt(self): """Encode and decode an authentication token response object.""" # We need a CA signed certificate, so we use the one # from above. cert = x509.parse_certificate(_TEST_CERT) key = RSA.importKey(_TEST_KEY) cacert = x509.parse_certificate(_TEST_CA) # Sanity check for the above certificates. self.assertTrue(cert.check_signature(cacert)) # Create an AuthTokenRequest with some correct-sounding data. atr = token_pb2.AuthTokenResponse() set_basic_creds(atr.basic_creds) atr.certificate = _TEST_CERT atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' atr.granted = calendar.timegm(datetime.now().timetuple()) atr.random = 'A' * 42 # TODO(tonnerre): This should go away. # Create the codec and encode. atrc = token_cookie.AuthTokenResponseCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenResponse() vatrc = token_cookie.AuthTokenResponseCodec(vatr, pubkey=cert.get_pub_key()) try: vatrc.decode(data) except token_cookie.SignatureException as e: self.fail("Can't verify signature using original certificate") self.assertEqual(atr, vatr) # Decode again, using the contained certificate. vatr.Clear() vatrc = token_cookie.AuthTokenResponseCodec(vatr, cacert=cacert) try: vatrc.decode(data) except token_cookie.SignatureException as e: self.fail("Can't verify signature using inband certificate: " + e.message) self.assertEqual(atr, vatr)
def test_sign_and_decrypt(self): """Encode and decode an authentication token response object.""" # We need a CA signed certificate, so we use the one # from above. cert = x509.parse_certificate(_TEST_CERT) key = RSA.importKey(_TEST_KEY) cacert = x509.parse_certificate(_TEST_CA) # Sanity check for the above certificates. self.assertTrue(cert.check_signature(cacert)) # Create an AuthTokenRequest with some correct-sounding data. atr = token_pb2.AuthTokenResponse() set_basic_creds(atr.basic_creds) atr.certificate = _TEST_CERT atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' atr.granted = calendar.timegm(datetime.now().timetuple()) atr.random = 'A' * 42 # TODO(caoimhe): This should go away. # Create the codec and encode. atrc = token_cookie.AuthTokenResponseCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenResponse() vatrc = token_cookie.AuthTokenResponseCodec(vatr, pubkey=cert.get_pub_key()) try: vatrc.decode(data) except token_cookie.SignatureException as e: self.fail("Can't verify signature using original certificate") self.assertEqual(atr, vatr) # Decode again, using the contained certificate. vatr.Clear() vatrc = token_cookie.AuthTokenResponseCodec(vatr, cacert=cacert) try: vatrc.decode(data) except token_cookie.SignatureException as e: self.fail("Can't verify signature using inband certificate: " + e.message) self.assertEqual(atr, vatr)
def test_sign_and_decrypt(self): """Encode and decode an authentication token request object.""" # We need a CA signed certificate, so we use the one # from above. cert = x509.parse_certificate(_TEST_CERT) key = RSA.importKey(_TEST_KEY) cacert = x509.parse_certificate(_TEST_CA) # Sanity check for the above certificates. self.assertTrue(cert.check_signature(cacert)) # Create an AuthTokenRequest with some correct-sounding data. atr = token_pb2.AuthTokenRequest() atr.certificate = _TEST_CERT atr.return_uri = 'https://localhost/login' atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' # Create the codec and encode. atrc = token_cookie.AuthTokenRequestCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenRequest() vatrc = token_cookie.AuthTokenRequestCodec(vatr, pubkey=cert.get_pub_key()) try: vatrc.decode(data) except token_cookie.SignatureException as e: # TODO(caoimhe): Reenable this test. self.fail("Can't verify signature using original certificate") self.assertEqual(atr, vatr) # Decode again, using the contained certificate. vatr.Clear() vatrc = token_cookie.AuthTokenRequestCodec(vatr, cacert=cacert) try: vatrc.decode(data) except token_cookie.SignatureException as e: # TODO(caoimhe): reenable this test. # self.fail("Can't verify signature using inband certificate") pass self.assertEqual(atr, vatr)
def test_login_handler(self): """Check whether an authentication token response is handled and decoded correctly by the authenticator implementation.""" now = datetime.now() expires = now + timedelta(0, 300) pkey = importKey(_TEST_KEY) # We need a CA signed certificate, so we use the one # from above. cert = x509.parse_certificate(_TEST_CERT) cacert = x509.parse_certificate(_TEST_CA) # Sanity check for the above certificates. self.assertTrue(cert.check_signature(cacert)) auth = authenticator.Authenticator("Unit Test", cert=_TEST_CERT, key=_TEST_KEY, ca_bundle=_TEST_CA) atres = token_pb2.AuthTokenResponse() atres.basic_creds.user_name = 'testosteronius' atres.basic_creds.scope.extend(['one', 'two']) atres.basic_creds.expires = calendar.timegm(expires.utctimetuple()) atres.app_name = 'Unit Test' atres.original_uri = 'http://lolcathost:8080/foo/bar' atres.certificate = _TEST_CERT atres.granted = calendar.timegm(now.utctimetuple()) # FIXME(caoimhe): this should go away. atres.random = 'A' * 64 atrc = token_cookie.AuthTokenResponseCodec(atres, privkey=pkey) response = atrc.encode() data = auth.login_handler(response) self.assertEquals(2, len(data)) cookiedata = data[0] nexturl = data[1] self.assertEquals('http://lolcathost:8080/foo/bar', nexturl)
def test_login_handler(self): """Check whether an authentication token response is handled and decoded correctly by the authenticator implementation.""" now = datetime.now() expires = now + timedelta(0, 300) pkey = importKey(_TEST_KEY) # We need a CA signed certificate, so we use the one # from above. cert = x509.parse_certificate(_TEST_CERT) cacert = x509.parse_certificate(_TEST_CA) # Sanity check for the above certificates. self.assertTrue(cert.check_signature(cacert)) auth = authenticator.Authenticator("Unit Test", cert=_TEST_CERT, key=_TEST_KEY, ca_bundle=_TEST_CA) atres = token_pb2.AuthTokenResponse() atres.basic_creds.user_name = 'testosteronius' atres.basic_creds.scope.extend(['one', 'two']) atres.basic_creds.expires = calendar.timegm(expires.utctimetuple()) atres.app_name = 'Unit Test' atres.original_uri = 'http://lolcathost:8080/foo/bar' atres.certificate = _TEST_CERT atres.granted = calendar.timegm(now.utctimetuple()) # FIXME(tonnerre): this should go away. atres.random = 'A' * 64 atrc = token_cookie.AuthTokenResponseCodec(atres, privkey=pkey) response = atrc.encode() data = auth.login_handler(response) self.assertEquals(2, len(data)) cookiedata = data[0] nexturl = data[1] self.assertEquals('http://lolcathost:8080/foo/bar', nexturl)
def decode(self, src): """Verify the signature and decode the response. Decode the structure. Verifies the signature with the given public key, or with the key contained inside the message if None is passed. Args: src: string containing the base64 encoded cookie. Return: Integer value indicating the length of the data which was read; this is so it can be skipped if multiple records are returned. This length is after base64 decoding, so a multiplier must be applied. """ data = base64.urlsafe_b64decode(src) self._atr.ParseFromString(data) if (datetime.utcfromtimestamp(self._atr.basic_creds.expires) < datetime.utcnow()): raise TokenExpiredException() # We'll need a copy of the data so we can verify it by # setting the signature to None. pb = token_pb2.AuthTokenResponse() pb.ParseFromString(data) pb.ClearField("signature") h = SHA256.new(pb.SerializeToString()) if self._pub: verifier = PKCS1_v1_5.new(self._pub) else: # Attempt to extract the certificate from the request. cert = x509.parse_certificate(self._atr.certificate) if not self._ca: raise NoKeyException() if not cert.check_signature(self._ca): raise SignatureException("Certificate not signed by CA") verifier = PKCS1_v1_5.new(cert.get_pub_key()) if verifier.verify(h, self._atr.signature): return len(data) else: raise SignatureException("Unable to verify data signature")
def test_verify_unknown_signer(self): """Verify a wrong signature.""" cert, key = gen_certificate() cacert = x509.parse_certificate(_TEST_CA) # Set up a token cookie with test data. atr = token_pb2.AuthTokenRequest() atr.certificate = _TEST_CERT atr.return_uri = 'https://localhost/login' atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' # Create the codec and encode. atrc = token_cookie.AuthTokenRequestCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenRequest() vatrc = token_cookie.AuthTokenRequestCodec(vatr, cacert=cacert) self.assertRaises(token_cookie.SignatureException, vatrc.decode, data)
def test_verify_unknown_signer(self): """Verify a wrong signature.""" cert, key = gen_certificate() cacert = x509.parse_certificate(_TEST_CA) # Set up a token cookie with test data. atr = token_pb2.AuthTokenRequest() atr.certificate = _TEST_CERT atr.return_uri = 'https://localhost/login' atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' # Create the codec and encode. atrc = token_cookie.AuthTokenRequestCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenRequest() vatrc = token_cookie.AuthTokenRequestCodec(vatr, cacert=cacert) self.assertRaises(token_cookie.SignatureException, vatrc.decode, data)
def test_verify_unknown_signer(self): """Verify a wrong signature.""" cert, key = gen_certificate() cacert = x509.parse_certificate(_TEST_CA) # Set up a token cookie with test data. atr = token_pb2.AuthTokenResponse() set_basic_creds(atr.basic_creds) atr.certificate = _TEST_CERT atr.original_uri = 'https://localhost/' atr.app_name = 'Test Application' atr.granted = calendar.timegm(datetime.now().timetuple()) atr.random = 'A' * 42 # TODO(caoimhe): This should go away. # Create the codec and encode. atrc = token_cookie.AuthTokenResponseCodec(atr, privkey=key) data = atrc.encode() # Verify the signature. vatr = token_pb2.AuthTokenResponse() vatrc = token_cookie.AuthTokenResponseCodec(vatr, cacert=cacert) self.assertRaises(token_cookie.SignatureException, vatrc.decode, data)