Ensure tokens are added to both Trustor and Trustee indexes
Tokens are now added to both the Trustor and Trustee user-token-index so that bulk token revocations (e.g. password change) of the trustee will work as expected. This is a backport of the basic code that was used in the Icehouse-vintage Dogpile Token KVS backend that resolves this issue by merging the handling of memcache and KVS backends into the same logic. Change-Id: I3e19e4a8fc1e11cef6db51d364e80061e97befa7 Closes-Bug: #1260080
This commit is contained in:
parent
c22f2edeb7
commit
b6f0e26da0
|
@ -25,6 +25,7 @@ from keystone import exception
|
|||
from keystone.openstack.common import timeutils
|
||||
from keystone import tests
|
||||
from keystone.tests import default_fixtures
|
||||
from keystone.token import provider
|
||||
|
||||
|
||||
CONF = config.CONF
|
||||
|
@ -2645,7 +2646,8 @@ class TokenTests(object):
|
|||
self.token_api.delete_token, token_id)
|
||||
|
||||
def create_token_sample_data(self, tenant_id=None, trust_id=None,
|
||||
user_id="testuserid"):
|
||||
user_id='testuserid',
|
||||
trustee_user_id='testuserid2'):
|
||||
token_id = self._create_token_id()
|
||||
data = {'id': token_id, 'a': 'b',
|
||||
'user': {'id': user_id}}
|
||||
|
@ -2655,6 +2657,15 @@ class TokenTests(object):
|
|||
data['tenant'] = None
|
||||
if trust_id is not None:
|
||||
data['trust_id'] = trust_id
|
||||
data.setdefault('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.
|
||||
data['access']['trust']['trustee_user_id'] = trustee_user_id
|
||||
data['token_version'] = provider.V2
|
||||
# Issue token stores a copy of all token data at token['token_data'].
|
||||
# This emulates that assumption as part of the test.
|
||||
data['token_data'] = copy.deepcopy(data)
|
||||
new_token = self.token_api.create_token(token_id, data)
|
||||
return new_token['id']
|
||||
|
||||
|
@ -2907,6 +2918,39 @@ class TokenTests(object):
|
|||
for t in self.token_api.list_revoked_tokens():
|
||||
self.assertIn('expires', t)
|
||||
|
||||
def test_token_in_trustee_and_trustor_token_list(self):
|
||||
self.opt_in_group('trust',
|
||||
enabled=True)
|
||||
trustor = self.user_foo
|
||||
trustee = self.user_two
|
||||
trust_id = uuid.uuid4().hex
|
||||
trust_info = {'trustor_user_id': trustor['id'],
|
||||
'trustee_user_id': trustee['id'],
|
||||
'project_id': self.tenant_bar['id'],
|
||||
'expires_at': timeutils.
|
||||
parse_isotime('2031-02-18T18:10:00Z'),
|
||||
'impersonation': True}
|
||||
self.trust_api.create_trust(trust_id, trust_info,
|
||||
roles=[{'id': 'member'},
|
||||
{'id': 'other'},
|
||||
{'id': 'browser'}])
|
||||
|
||||
token_id = self.create_token_sample_data(
|
||||
tenant_id=self.tenant_bar['id'],
|
||||
trust_id=trust_id,
|
||||
user_id=trustor['id'],
|
||||
trustee_user_id=trustee['id'])
|
||||
|
||||
# Ensure the token id exists in both the trustor and trustee token
|
||||
# lists
|
||||
|
||||
self.assertIn(token_id,
|
||||
self.token_api.list_tokens(self.user_two['id'],
|
||||
trust_id=trust_id))
|
||||
self.assertIn(token_id,
|
||||
self.token_api.list_tokens(self.user_foo['id'],
|
||||
trust_id=trust_id))
|
||||
|
||||
|
||||
class TokenCacheInvalidation(object):
|
||||
def _create_test_data(self):
|
||||
|
|
|
@ -70,6 +70,7 @@ class KvsToken(tests.TestCase, test_backend.TokenTests):
|
|||
identity.CONF.identity.driver = (
|
||||
'keystone.identity.backends.kvs.Identity')
|
||||
self.load_backends()
|
||||
self.load_fixtures(default_fixtures)
|
||||
|
||||
|
||||
class KvsTrust(tests.TestCase, test_backend.TrustTests):
|
||||
|
|
|
@ -26,6 +26,7 @@ from keystone import exception
|
|||
from keystone.openstack.common import jsonutils
|
||||
from keystone.openstack.common import timeutils
|
||||
from keystone import tests
|
||||
from keystone.tests import default_fixtures
|
||||
from keystone.tests import test_backend
|
||||
from keystone.tests import test_utils
|
||||
from keystone import token
|
||||
|
@ -115,6 +116,7 @@ class MemcacheToken(tests.TestCase, test_backend.TokenTests):
|
|||
def setUp(self):
|
||||
super(MemcacheToken, self).setUp()
|
||||
self.load_backends()
|
||||
self.load_fixtures(default_fixtures)
|
||||
fake_client = MemcacheClient()
|
||||
self.token_man = token.Manager()
|
||||
self.token_man.driver = token_memcache.Token(client=fake_client)
|
||||
|
|
|
@ -150,5 +150,7 @@ class Token(kvs.Base, token.Driver):
|
|||
def flush_expired_tokens(self):
|
||||
now = timeutils.utcnow()
|
||||
for token, token_ref in self.db.items():
|
||||
if not token.startswith('revoked-token-'):
|
||||
continue
|
||||
if self.is_expired(now, token_ref):
|
||||
self.db.delete(token)
|
||||
|
|
|
@ -83,12 +83,33 @@ class Token(token.Driver):
|
|||
expires_ts = utils.unixtime(data_copy['expires'])
|
||||
kwargs['time'] = expires_ts
|
||||
self.client.set(ptk, data_copy, **kwargs)
|
||||
if 'id' in data['user']:
|
||||
user_id = data['user']['id']
|
||||
user_key = self._prefix_user_id(user_id)
|
||||
# Append the new token_id to the token-index-list stored in the
|
||||
# user-key within memcache.
|
||||
self._update_user_list_with_cas(user_key, token_id, data_copy)
|
||||
user_id = data['user']['id']
|
||||
user_key = self._prefix_user_id(user_id)
|
||||
# Append the new token_id to the token-index-list stored in the
|
||||
# user-key within memcache.
|
||||
self._update_user_list_with_cas(user_key, token_id, data_copy)
|
||||
if CONF.trust.enabled and data.get('trust_id'):
|
||||
# NOTE(morganfainberg): If trusts are enabled and this is a trust
|
||||
# scoped token, we add the token to the trustee list as well. This
|
||||
# allows password changes of the trustee to also expire the token.
|
||||
# There is no harm in placing the token in multiple lists, as
|
||||
# _list_tokens is smart enough to handle almost any case of
|
||||
# valid/invalid/expired for a given token.
|
||||
token_data = data_copy['token_data']
|
||||
if data_copy['token_version'] == token.provider.V2:
|
||||
trustee_user_id = token_data['access']['trust'][
|
||||
'trustee_user_id']
|
||||
elif data_copy['token_version'] == token.provider.V3:
|
||||
trustee_user_id = token_data['OS-TRUST:trust'][
|
||||
'trustee_user_id']
|
||||
else:
|
||||
raise token.provider.UnsupportedTokenVersionException(
|
||||
_('Unknown token version %s') %
|
||||
data_copy.get('token_version'))
|
||||
|
||||
trustee_key = self._prefix_user_id(trustee_user_id)
|
||||
self._update_user_list_with_cas(trustee_key, token_id, data_copy)
|
||||
|
||||
return copy.deepcopy(data_copy)
|
||||
|
||||
def _convert_user_index_from_json(self, token_list, user_key):
|
||||
|
|
Loading…
Reference in New Issue