diff --git a/keystoneclient/middleware/auth_token.py b/keystoneclient/middleware/auth_token.py index f11a26026..247857510 100644 --- a/keystoneclient/middleware/auth_token.py +++ b/keystoneclient/middleware/auth_token.py @@ -164,7 +164,6 @@ from keystoneclient.middleware import memcache_crypt from keystoneclient.openstack.common import jsonutils from keystoneclient.openstack.common import memorycache from keystoneclient.openstack.common import timeutils -from keystoneclient import utils # alternative middleware configuration in the main application's @@ -876,10 +875,10 @@ class AuthProtocol(object): raise InvalidUserToken( 'Token authorization failed') elif cms.is_pkiz(user_token): - verified = self.verify_pkiz_token(user_token) + verified = self.verify_pkiz_token(user_token, token_id) data = jsonutils.loads(verified) elif cms.is_asn1_token(user_token): - verified = self.verify_signed_token(user_token) + verified = self.verify_signed_token(user_token, token_id) data = jsonutils.loads(verified) else: data = self.verify_uuid_token(user_token, retry) @@ -1210,11 +1209,8 @@ class AuthProtocol(object): raise InvalidUserToken() - def is_signed_token_revoked(self, signed_text): + def is_signed_token_revoked(self, token_id): """Indicate whether the token appears in the revocation list.""" - if isinstance(signed_text, six.text_type): - signed_text = signed_text.encode('utf-8') - token_id = utils.hash_signed_token(signed_text) is_revoked = self._is_token_id_in_revoked_list(token_id) if is_revoked: self.LOG.debug('Token is marked as having been revoked') @@ -1261,17 +1257,17 @@ class AuthProtocol(object): self.LOG.error('CMS Verify output: %s', err.output) raise - def verify_signed_token(self, signed_text): + def verify_signed_token(self, signed_text, token_id): """Check that the token is unrevoked and has a valid signature.""" - if self.is_signed_token_revoked(signed_text): + if self.is_signed_token_revoked(token_id): raise InvalidUserToken('Token has been revoked') formatted = cms.token_to_cms(signed_text) verified = self.cms_verify(formatted) return verified - def verify_pkiz_token(self, signed_text): - if self.is_signed_token_revoked(signed_text): + def verify_pkiz_token(self, signed_text, token_id): + if self.is_signed_token_revoked(token_id): raise InvalidUserToken('Token has been revoked') try: uncompressed = cms.pkiz_uncompress(signed_text) diff --git a/keystoneclient/tests/client_fixtures.py b/keystoneclient/tests/client_fixtures.py index f090db04e..cc7eaf17c 100644 --- a/keystoneclient/tests/client_fixtures.py +++ b/keystoneclient/tests/client_fixtures.py @@ -31,6 +31,12 @@ CMSDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'cms') KEYDIR = os.path.join(ROOTDIR, 'examples', 'pki', 'private') +def _hash_signed_token_safe(signed_text, **kwargs): + if isinstance(signed_text, six.text_type): + signed_text = signed_text.encode('utf-8') + return utils.hash_signed_token(signed_text, **kwargs) + + class Examples(fixtures.Fixture): """Example tokens and certs loaded from the examples directory. @@ -58,10 +64,14 @@ class Examples(fixtures.Fixture): with open(os.path.join(CMSDIR, 'auth_token_scoped.pem')) as f: self.SIGNED_TOKEN_SCOPED = cms.cms_to_token(f.read()) + self.SIGNED_TOKEN_SCOPED_HASH = _hash_signed_token_safe( + self.SIGNED_TOKEN_SCOPED) with open(os.path.join(CMSDIR, 'auth_token_unscoped.pem')) as f: self.SIGNED_TOKEN_UNSCOPED = cms.cms_to_token(f.read()) with open(os.path.join(CMSDIR, 'auth_v3_token_scoped.pem')) as f: self.SIGNED_v3_TOKEN_SCOPED = cms.cms_to_token(f.read()) + self.SIGNED_v3_TOKEN_SCOPED_HASH = _hash_signed_token_safe( + self.SIGNED_v3_TOKEN_SCOPED) with open(os.path.join(CMSDIR, 'auth_token_revoked.pem')) as f: self.REVOKED_TOKEN = cms.cms_to_token(f.read()) with open(os.path.join(CMSDIR, 'auth_token_scoped_expired.pem')) as f: diff --git a/keystoneclient/tests/test_auth_token_middleware.py b/keystoneclient/tests/test_auth_token_middleware.py index 6b81f2368..c94b42f36 100644 --- a/keystoneclient/tests/test_auth_token_middleware.py +++ b/keystoneclient/tests/test_auth_token_middleware.py @@ -564,27 +564,29 @@ class CommonAuthTokenMiddlewareTest(object): self.middleware.token_revocation_list = jsonutils.dumps( {"revoked": [], "extra": "success"}) result = self.middleware.is_signed_token_revoked( - self.token_dict['revoked_token']) + self.token_dict['revoked_token_hash']) self.assertFalse(result) def test_is_signed_token_revoked_returns_true(self): self.middleware.token_revocation_list = self.get_revocation_list_json() result = self.middleware.is_signed_token_revoked( - self.token_dict['revoked_token']) + self.token_dict['revoked_token_hash']) self.assertTrue(result) def test_verify_signed_token_raises_exception_for_revoked_token(self): self.middleware.token_revocation_list = self.get_revocation_list_json() self.assertRaises(auth_token.InvalidUserToken, self.middleware.verify_signed_token, - self.token_dict['revoked_token']) + self.token_dict['revoked_token'], + self.token_dict['revoked_token_hash']) def test_verify_signed_token_raises_exception_for_revoked_pkiz_token(self): self.middleware.token_revocation_list = ( self.examples.REVOKED_TOKEN_PKIZ_LIST_JSON) self.assertRaises(auth_token.InvalidUserToken, self.middleware.verify_pkiz_token, - self.token_dict['revoked_token_pkiz']) + self.token_dict['revoked_token_pkiz'], + self.token_dict['revoked_token_pkiz_hash']) def assertIsValidJSON(self, text): json.loads(text) @@ -592,13 +594,15 @@ class CommonAuthTokenMiddlewareTest(object): def test_verify_signed_token_succeeds_for_unrevoked_token(self): self.middleware.token_revocation_list = self.get_revocation_list_json() text = self.middleware.verify_signed_token( - self.token_dict['signed_token_scoped']) + self.token_dict['signed_token_scoped'], + self.token_dict['signed_token_scoped_hash']) self.assertIsValidJSON(text) def test_verify_signed_compressed_token_succeeds_for_unrevoked_token(self): self.middleware.token_revocation_list = self.get_revocation_list_json() text = self.middleware.verify_pkiz_token( - self.token_dict['signed_token_scoped_pkiz']) + self.token_dict['signed_token_scoped_pkiz'], + self.token_dict['signed_token_scoped_hash']) self.assertIsValidJSON(text) def test_verify_signing_dir_create_while_missing(self): @@ -1200,7 +1204,8 @@ class V2CertDownloadMiddlewareTest(BaseAuthTokenMiddlewareTest, status=404) self.assertRaises(exceptions.CertificateConfigError, self.middleware.verify_signed_token, - self.examples.SIGNED_TOKEN_SCOPED) + self.examples.SIGNED_TOKEN_SCOPED, + self.examples.SIGNED_TOKEN_SCOPED_HASH) def test_fetch_signing_cert(self): data = 'FAKE CERT' @@ -1326,11 +1331,14 @@ class v2AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest, 'uuid_token_unknown_bind': self.examples.UUID_TOKEN_UNKNOWN_BIND, 'signed_token_scoped': self.examples.SIGNED_TOKEN_SCOPED, 'signed_token_scoped_pkiz': self.examples.SIGNED_TOKEN_SCOPED_PKIZ, + 'signed_token_scoped_hash': self.examples.SIGNED_TOKEN_SCOPED_HASH, 'signed_token_scoped_expired': self.examples.SIGNED_TOKEN_SCOPED_EXPIRED, 'revoked_token': self.examples.REVOKED_TOKEN, 'revoked_token_pkiz': self.examples.REVOKED_TOKEN_PKIZ, - 'revoked_token_hash': self.examples.REVOKED_TOKEN_HASH + 'revoked_token_pkiz_hash': + self.examples.REVOKED_TOKEN_PKIZ_HASH, + 'revoked_token_hash': self.examples.REVOKED_TOKEN_HASH, } httpretty.reset() @@ -1511,11 +1519,15 @@ class v3AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest, 'signed_token_scoped': self.examples.SIGNED_v3_TOKEN_SCOPED, 'signed_token_scoped_pkiz': self.examples.SIGNED_v3_TOKEN_SCOPED_PKIZ, + 'signed_token_scoped_hash': + self.examples.SIGNED_v3_TOKEN_SCOPED_HASH, 'signed_token_scoped_expired': self.examples.SIGNED_TOKEN_SCOPED_EXPIRED, 'revoked_token': self.examples.REVOKED_v3_TOKEN, 'revoked_token_pkiz': self.examples.REVOKED_v3_TOKEN_PKIZ, - 'revoked_token_hash': self.examples.REVOKED_v3_TOKEN_HASH + 'revoked_token_hash': self.examples.REVOKED_v3_TOKEN_HASH, + 'revoked_token_pkiz_hash': + self.examples.REVOKED_v3_PKIZ_TOKEN_HASH, } httpretty.reset()