diff options
author | Jenkins <jenkins@review.openstack.org> | 2016-01-14 12:56:45 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2016-01-14 12:56:45 +0000 |
commit | 1701856bf1cf0810941f6ae86eab40f6b0b08567 (patch) | |
tree | 76ac09e45369ab8defecf6605a9c42453076ccef | |
parent | ea68a87bf38f24fc44b0db64381eba188f428343 (diff) | |
parent | bff03b5726fe5cac93d44a66715eea49b89c8cb0 (diff) | |
download | keystone-1701856bf1cf0810941f6ae86eab40f6b0b08567.tar.gz |
Merge "Add audit IDs to revocation events" into stable/liberty
-rw-r--r-- | keystone/tests/unit/test_backend.py | 39 | ||||
-rw-r--r-- | keystone/tests/unit/test_backend_sql.py | 3 | ||||
-rw-r--r-- | keystone/token/persistence/backends/kvs.py | 9 | ||||
-rw-r--r-- | keystone/token/persistence/backends/sql.py | 12 | ||||
-rw-r--r-- | releasenotes/notes/bug-1490804-de58a9606edb31eb.yaml | 13 |
5 files changed, 61 insertions, 15 deletions
diff --git a/keystone/tests/unit/test_backend.py b/keystone/tests/unit/test_backend.py index 2340645a0..127373665 100644 --- a/keystone/tests/unit/test_backend.py +++ b/keystone/tests/unit/test_backend.py @@ -4426,7 +4426,9 @@ class TokenTests(object): token_id = self._create_token_id() data = {'id': token_id, 'a': 'b', 'trust_id': None, - 'user': {'id': 'testuserid'}} + 'user': {'id': 'testuserid'}, + 'token_data': {'access': {'token': { + 'audit_ids': [uuid.uuid4().hex]}}}} data_ref = self.token_provider_api._persistence.create_token(token_id, data) expires = data_ref.pop('expires') @@ -4461,7 +4463,8 @@ class TokenTests(object): # FIXME(morganfainberg): These tokens look nothing like "Real" tokens. # This should be fixed when token issuance is cleaned up. data = {'id': token_id, 'a': 'b', - 'user': {'id': user_id}} + 'user': {'id': user_id}, + 'access': {'token': {'audit_ids': [uuid.uuid4().hex]}}} if tenant_id is not None: data['tenant'] = {'id': tenant_id, 'name': tenant_id} if tenant_id is NULL_OBJECT: @@ -4470,7 +4473,7 @@ class TokenTests(object): data['expires'] = expires if trust_id is not None: data['trust_id'] = trust_id - data.setdefault('access', {}).setdefault('trust', {}) + data['access'].setdefault('trust', {}) # Testuserid2 is used here since a trustee will be different in # the cases of impersonation and therefore should not match the # token's user_id. @@ -4633,17 +4636,21 @@ class TokenTests(object): self.assertEqual(data_ref, new_data_ref) - def check_list_revoked_tokens(self, token_ids): - revoked_ids = [x['id'] - for x in self.token_provider_api.list_revoked_tokens()] + def check_list_revoked_tokens(self, token_infos): + revocation_list = self.token_provider_api.list_revoked_tokens() + revoked_ids = [x['id'] for x in revocation_list] + revoked_audit_ids = [x['audit_id'] for x in revocation_list] self._assert_revoked_token_list_matches_token_persistence(revoked_ids) - for token_id in token_ids: + for token_id, audit_id in token_infos: self.assertIn(token_id, revoked_ids) + self.assertIn(audit_id, revoked_audit_ids) def delete_token(self): token_id = uuid.uuid4().hex + audit_id = uuid.uuid4().hex data = {'id_hash': token_id, 'id': token_id, 'a': 'b', - 'user': {'id': 'testuserid'}} + 'user': {'id': 'testuserid'}, + 'token_data': {'token': {'audit_ids': [audit_id]}}} data_ref = self.token_provider_api._persistence.create_token(token_id, data) self.token_provider_api._persistence.delete_token(token_id) @@ -4655,7 +4662,7 @@ class TokenTests(object): exception.TokenNotFound, self.token_provider_api._persistence.delete_token, data_ref['id']) - return token_id + return (token_id, audit_id) def test_list_revoked_tokens_returns_empty_list(self): revoked_ids = [x['id'] @@ -4706,12 +4713,16 @@ class TokenTests(object): token_data = {'id_hash': token_id, 'id': token_id, 'a': 'b', 'expires': expire_time, 'trust_id': None, - 'user': {'id': 'testuserid'}} + 'user': {'id': 'testuserid'}, + 'token_data': {'token': { + 'audit_ids': [uuid.uuid4().hex]}}} token2_id = uuid.uuid4().hex token2_data = {'id_hash': token2_id, 'id': token2_id, 'a': 'b', 'expires': expire_time, 'trust_id': None, - 'user': {'id': 'testuserid'}} + 'user': {'id': 'testuserid'}, + 'token_data': {'token': { + 'audit_ids': [uuid.uuid4().hex]}}} # Create 2 Tokens. self.token_provider_api._persistence.create_token(token_id, token_data) @@ -4746,7 +4757,8 @@ class TokenTests(object): def _test_predictable_revoked_pki_token_id(self, hash_fn): token_id = self._create_token_id() token_id_hash = hash_fn(token_id).hexdigest() - token = {'user': {'id': uuid.uuid4().hex}} + token = {'user': {'id': uuid.uuid4().hex}, + 'token_data': {'token': {'audit_ids': [uuid.uuid4().hex]}}} self.token_provider_api._persistence.create_token(token_id, token) self.token_provider_api._persistence.delete_token(token_id) @@ -4768,7 +4780,8 @@ class TokenTests(object): def test_predictable_revoked_uuid_token_id(self): token_id = uuid.uuid4().hex - token = {'user': {'id': uuid.uuid4().hex}} + token = {'user': {'id': uuid.uuid4().hex}, + 'token_data': {'token': {'audit_ids': [uuid.uuid4().hex]}}} self.token_provider_api._persistence.create_token(token_id, token) self.token_provider_api._persistence.delete_token(token_id) diff --git a/keystone/tests/unit/test_backend_sql.py b/keystone/tests/unit/test_backend_sql.py index 69fac63a2..51221a313 100644 --- a/keystone/tests/unit/test_backend_sql.py +++ b/keystone/tests/unit/test_backend_sql.py @@ -492,7 +492,8 @@ class SqlToken(SqlTests, test_backend.TokenTests): # necessary. expected_query_args = (token_sql.TokenModel.id, - token_sql.TokenModel.expires) + token_sql.TokenModel.expires, + token_sql.TokenModel.extra,) with mock.patch.object(token_sql, 'sql') as mock_sql: tok = token_sql.Token() diff --git a/keystone/token/persistence/backends/kvs.py b/keystone/token/persistence/backends/kvs.py index 519315866..60f7931db 100644 --- a/keystone/token/persistence/backends/kvs.py +++ b/keystone/token/persistence/backends/kvs.py @@ -210,6 +210,15 @@ class Token(token.persistence.TokenDriverV8): subsecond=True) revoked_token_data['id'] = data['id'] + token_data = data['token_data'] + if 'access' in token_data: + # It's a v2 token. + audit_ids = token_data['access']['token']['audit_ids'] + else: + # It's a v3 token. + audit_ids = token_data['token']['audit_ids'] + revoked_token_data['audit_id'] = audit_ids[0] + token_list = self._get_key_or_default(self.revocation_key, default=[]) if not isinstance(token_list, list): # NOTE(morganfainberg): In the case that the revocation list is not diff --git a/keystone/token/persistence/backends/sql.py b/keystone/token/persistence/backends/sql.py index 6fc1d2237..d67762071 100644 --- a/keystone/token/persistence/backends/sql.py +++ b/keystone/token/persistence/backends/sql.py @@ -228,13 +228,23 @@ class Token(token.persistence.TokenDriverV8): session = sql.get_session() tokens = [] now = timeutils.utcnow() - query = session.query(TokenModel.id, TokenModel.expires) + query = session.query(TokenModel.id, TokenModel.expires, + TokenModel.extra) query = query.filter(TokenModel.expires > now) token_references = query.filter_by(valid=False) for token_ref in token_references: + token_data = token_ref[2]['token_data'] + if 'access' in token_data: + # It's a v2 token. + audit_ids = token_data['access']['token']['audit_ids'] + else: + # It's a v3 token. + audit_ids = token_data['token']['audit_ids'] + record = { 'id': token_ref[0], 'expires': token_ref[1], + 'audit_id': audit_ids[0], } tokens.append(record) return tokens diff --git a/releasenotes/notes/bug-1490804-de58a9606edb31eb.yaml b/releasenotes/notes/bug-1490804-de58a9606edb31eb.yaml new file mode 100644 index 000000000..0d5c20348 --- /dev/null +++ b/releasenotes/notes/bug-1490804-de58a9606edb31eb.yaml @@ -0,0 +1,13 @@ +--- +features: + - > + [`bug 1490804 <https://bugs.launchpad.net/keystone/+bug/1490804>`_] + Audit IDs are included in the token revocation list. +security: + - > + [`bug 1490804 <https://bugs.launchpad.net/keystone/+bug/1490804>`_] + [`CVE-2015-7546 <http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-7546>`_] + A bug is fixed where an attacker could avoid token revocation when the PKI + or PKIZ token provider is used. The complete remediation for this + vulnerability requires the corresponding fix in the keystonemiddleware + project. |