6033N/AFrom 9c9c1331e0c004897d5f4c5847f7143b56373f10 Mon Sep 17 00:00:00 2001
6033N/AFrom: Brant Knudson <bknudson@us.ibm.com>
6033N/ADate: Tue, 1 Dec 2015 11:09:14 -0600
6033N/ASubject: [PATCH] Add audit IDs to revocation events
6033N/A
6033N/AThe revoked tokens' audit ID is now included in the data returned in
6033N/Athe revocation list.
6033N/A
6033N/ACloses-Bug: 1490804
6033N/AChange-Id: Ifcf88f1158bebddc4f927121fbf4136fb53b659f
6033N/A(cherry picked from commit d5378f173da14a34ca010271477337879002d6d0)
6033N/AConflicts:
6033N/A keystone/tests/unit/test_backend.py
6033N/A---
6033N/A keystone/tests/unit/test_backend.py | 39 ++++++++++++++++++++----------
6033N/A keystone/tests/unit/test_backend_sql.py | 3 ++-
6033N/A keystone/token/persistence/backends/kvs.py | 9 +++++++
6033N/A keystone/token/persistence/backends/sql.py | 12 ++++++++-
6033N/A 4 files changed, 48 insertions(+), 15 deletions(-)
6033N/A
6033N/Adiff --git a/keystone/tests/unit/test_backend.py b/keystone/tests/unit/test_backend.py
6033N/Aindex 6cf0649..9c82502 100644
6033N/A--- a/keystone/tests/unit/test_backend.py
6033N/A+++ b/keystone/tests/unit/test_backend.py
6033N/A@@ -3778,7 +3778,9 @@ class TokenTests(object):
6033N/A token_id = self._create_token_id()
6033N/A data = {'id': token_id, 'a': 'b',
6033N/A 'trust_id': None,
6033N/A- 'user': {'id': 'testuserid'}}
6033N/A+ 'user': {'id': 'testuserid'},
6033N/A+ 'token_data': {'access': {'token': {
6033N/A+ 'audit_ids': [uuid.uuid4().hex]}}}}
6033N/A data_ref = self.token_provider_api._persistence.create_token(token_id,
6033N/A data)
6033N/A expires = data_ref.pop('expires')
6033N/A@@ -3813,7 +3815,8 @@ class TokenTests(object):
6033N/A # FIXME(morganfainberg): These tokens look nothing like "Real" tokens.
6033N/A # This should be fixed when token issuance is cleaned up.
6033N/A data = {'id': token_id, 'a': 'b',
6033N/A- 'user': {'id': user_id}}
6033N/A+ 'user': {'id': user_id},
6033N/A+ 'access': {'token': {'audit_ids': [uuid.uuid4().hex]}}}
6033N/A if tenant_id is not None:
6033N/A data['tenant'] = {'id': tenant_id, 'name': tenant_id}
6033N/A if tenant_id is NULL_OBJECT:
6033N/A@@ -3822,7 +3825,7 @@ class TokenTests(object):
6033N/A data['expires'] = expires
6033N/A if trust_id is not None:
6033N/A data['trust_id'] = trust_id
6033N/A- data.setdefault('access', {}).setdefault('trust', {})
6033N/A+ data['access'].setdefault('trust', {})
6033N/A # Testuserid2 is used here since a trustee will be different in
6033N/A # the cases of impersonation and therefore should not match the
6033N/A # token's user_id.
6033N/A@@ -3988,17 +3991,21 @@ class TokenTests(object):
6033N/A
6033N/A self.assertEqual(data_ref, new_data_ref)
6033N/A
6033N/A- def check_list_revoked_tokens(self, token_ids):
6033N/A- revoked_ids = [x['id']
6033N/A- for x in self.token_provider_api.list_revoked_tokens()]
6033N/A+ def check_list_revoked_tokens(self, token_infos):
6033N/A+ revocation_list = self.token_provider_api.list_revoked_tokens()
6033N/A+ revoked_ids = [x['id'] for x in revocation_list]
6033N/A+ revoked_audit_ids = [x['audit_id'] for x in revocation_list]
6033N/A self._assert_revoked_token_list_matches_token_persistence(revoked_ids)
6033N/A- for token_id in token_ids:
6033N/A+ for token_id, audit_id in token_infos:
6033N/A self.assertIn(token_id, revoked_ids)
6033N/A+ self.assertIn(audit_id, revoked_audit_ids)
6033N/A
6033N/A def delete_token(self):
6033N/A token_id = uuid.uuid4().hex
6033N/A+ audit_id = uuid.uuid4().hex
6033N/A data = {'id_hash': token_id, 'id': token_id, 'a': 'b',
6033N/A- 'user': {'id': 'testuserid'}}
6033N/A+ 'user': {'id': 'testuserid'},
6033N/A+ 'token_data': {'token': {'audit_ids': [audit_id]}}}
6033N/A data_ref = self.token_provider_api._persistence.create_token(token_id,
6033N/A data)
6033N/A self.token_provider_api._persistence.delete_token(token_id)
6033N/A@@ -4010,7 +4017,7 @@ class TokenTests(object):
6033N/A exception.TokenNotFound,
6033N/A self.token_provider_api._persistence.delete_token,
6033N/A data_ref['id'])
6033N/A- return token_id
6033N/A+ return (token_id, audit_id)
6033N/A
6033N/A def test_list_revoked_tokens_returns_empty_list(self):
6033N/A revoked_ids = [x['id']
6033N/A@@ -4061,12 +4068,16 @@ class TokenTests(object):
6033N/A token_data = {'id_hash': token_id, 'id': token_id, 'a': 'b',
6033N/A 'expires': expire_time,
6033N/A 'trust_id': None,
6033N/A- 'user': {'id': 'testuserid'}}
6033N/A+ 'user': {'id': 'testuserid'},
6033N/A+ 'token_data': {'token': {
6033N/A+ 'audit_ids': [uuid.uuid4().hex]}}}
6033N/A token2_id = uuid.uuid4().hex
6033N/A token2_data = {'id_hash': token2_id, 'id': token2_id, 'a': 'b',
6033N/A 'expires': expire_time,
6033N/A 'trust_id': None,
6033N/A- 'user': {'id': 'testuserid'}}
6033N/A+ 'user': {'id': 'testuserid'},
6033N/A+ 'token_data': {'token': {
6033N/A+ 'audit_ids': [uuid.uuid4().hex]}}}
6033N/A # Create 2 Tokens.
6033N/A self.token_provider_api._persistence.create_token(token_id,
6033N/A token_data)
6033N/A@@ -4101,7 +4112,8 @@ class TokenTests(object):
6033N/A def _test_predictable_revoked_pki_token_id(self, hash_fn):
6033N/A token_id = self._create_token_id()
6033N/A token_id_hash = hash_fn(token_id).hexdigest()
6033N/A- token = {'user': {'id': uuid.uuid4().hex}}
6033N/A+ token = {'user': {'id': uuid.uuid4().hex},
6033N/A+ 'token_data': {'token': {'audit_ids': [uuid.uuid4().hex]}}}
6033N/A
6033N/A self.token_provider_api._persistence.create_token(token_id, token)
6033N/A self.token_provider_api._persistence.delete_token(token_id)
6033N/A@@ -4123,7 +4135,8 @@ class TokenTests(object):
6033N/A
6033N/A def test_predictable_revoked_uuid_token_id(self):
6033N/A token_id = uuid.uuid4().hex
6033N/A- token = {'user': {'id': uuid.uuid4().hex}}
6033N/A+ token = {'user': {'id': uuid.uuid4().hex},
6033N/A+ 'token_data': {'token': {'audit_ids': [uuid.uuid4().hex]}}}
6033N/A
6033N/A self.token_provider_api._persistence.create_token(token_id, token)
6033N/A self.token_provider_api._persistence.delete_token(token_id)
6033N/Adiff --git a/keystone/tests/unit/test_backend_sql.py b/keystone/tests/unit/test_backend_sql.py
6033N/Aindex a7c63bf..7adc936 100644
6033N/A--- a/keystone/tests/unit/test_backend_sql.py
6033N/A+++ b/keystone/tests/unit/test_backend_sql.py
6033N/A@@ -441,7 +441,8 @@ class SqlToken(SqlTests, test_backend.TokenTests):
6033N/A # necessary.
6033N/A
6033N/A expected_query_args = (token_sql.TokenModel.id,
6033N/A- token_sql.TokenModel.expires)
6033N/A+ token_sql.TokenModel.expires,
6033N/A+ token_sql.TokenModel.extra,)
6033N/A
6033N/A with mock.patch.object(token_sql, 'sql') as mock_sql:
6033N/A tok = token_sql.Token()
6033N/Adiff --git a/keystone/token/persistence/backends/kvs.py b/keystone/token/persistence/backends/kvs.py
6033N/Aindex b4807bf..9a7ccea 100644
6033N/A--- a/keystone/token/persistence/backends/kvs.py
6033N/A+++ b/keystone/token/persistence/backends/kvs.py
6033N/A@@ -211,6 +211,15 @@ class Token(token.persistence.Driver):
6033N/A subsecond=True)
6033N/A revoked_token_data['id'] = data['id']
6033N/A
6033N/A+ token_data = data['token_data']
6033N/A+ if 'access' in token_data:
6033N/A+ # It's a v2 token.
6033N/A+ audit_ids = token_data['access']['token']['audit_ids']
6033N/A+ else:
6033N/A+ # It's a v3 token.
6033N/A+ audit_ids = token_data['token']['audit_ids']
6033N/A+ revoked_token_data['audit_id'] = audit_ids[0]
6033N/A+
6033N/A token_list = self._get_key_or_default(self.revocation_key, default=[])
6033N/A if not isinstance(token_list, list):
6033N/A # NOTE(morganfainberg): In the case that the revocation list is not
6033N/Adiff --git a/keystone/token/persistence/backends/sql.py b/keystone/token/persistence/backends/sql.py
6033N/Aindex 08c3a21..7c5c11d 100644
6033N/A--- a/keystone/token/persistence/backends/sql.py
6033N/A+++ b/keystone/token/persistence/backends/sql.py
6033N/A@@ -228,13 +228,23 @@ class Token(token.persistence.Driver):
6033N/A session = sql.get_session()
6033N/A tokens = []
6033N/A now = timeutils.utcnow()
6033N/A- query = session.query(TokenModel.id, TokenModel.expires)
6033N/A+ query = session.query(TokenModel.id, TokenModel.expires,
6033N/A+ TokenModel.extra)
6033N/A query = query.filter(TokenModel.expires > now)
6033N/A token_references = query.filter_by(valid=False)
6033N/A for token_ref in token_references:
6033N/A+ token_data = token_ref[2]['token_data']
6033N/A+ if 'access' in token_data:
6033N/A+ # It's a v2 token.
6033N/A+ audit_ids = token_data['access']['token']['audit_ids']
6033N/A+ else:
6033N/A+ # It's a v3 token.
6033N/A+ audit_ids = token_data['token']['audit_ids']
6033N/A+
6033N/A record = {
6033N/A 'id': token_ref[0],
6033N/A 'expires': token_ref[1],
6033N/A+ 'audit_id': audit_ids[0],
6033N/A }
6033N/A tokens.append(record)
6033N/A return tokens
6033N/A--
6033N/A1.9.1
6033N/A