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:
Morgan Fainberg 2014-02-21 14:09:04 -08:00
parent 8fcc18c42b
commit a411c944af
4 changed files with 65 additions and 8 deletions

View File

@ -62,6 +62,15 @@ class Token(token.Driver):
return token_ref
def create_token(self, token_id, data):
def update_index(user_id, token_data):
user_key = self._prefix_user_id(user_id)
if not self.client.append(user_key, ',%s' % token_data):
if not self.client.add(user_key, token_data):
if not self.client.append(user_key, ',%s' % token_data):
msg = _('Unable to add token user list.')
raise exception.UnexpectedError(msg)
data_copy = copy.deepcopy(data)
ptk = self._prefix_token_id(token.unique_id(token_id))
if not data_copy.get('expires'):
@ -73,15 +82,19 @@ class Token(token.Driver):
expires_ts = utils.unixtime(data_copy['expires'])
kwargs['time'] = expires_ts
self.client.set(ptk, data_copy, **kwargs)
token_data = jsonutils.dumps(token_id)
if 'id' in data['user']:
token_data = jsonutils.dumps(token_id)
user_id = data['user']['id']
user_key = self._prefix_user_id(user_id)
if not self.client.append(user_key, ',%s' % token_data):
if not self.client.add(user_key, token_data):
if not self.client.append(user_key, ',%s' % token_data):
msg = _('Unable to add token user list.')
raise exception.UnexpectedError(msg)
update_index(user_id, token_data)
if CONF.trust.enabled and data.get('trust_id'):
if 'access' in data_copy:
trustee_user_id = data_copy['access']['trust'][
'trustee_user_id']
else:
trustee_user_id = data_copy['OS-TRUST:trust'][
'trustee_user_id']
update_index(trustee_user_id, token_data)
return copy.deepcopy(data_copy)
def _add_to_revocation_list(self, token_id, token_data):

View File

@ -2096,7 +2096,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}}
@ -2104,6 +2105,11 @@ class TokenTests(object):
data['tenant'] = {'id': tenant_id, 'name': tenant_id}
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
self.token_api.create_token(token_id, data)
return token_id
@ -2290,6 +2296,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 TrustTests(object):
def create_sample_trust(self, new_id):

View File

@ -73,6 +73,8 @@ class KvsToken(test.TestCase, test_backend.TokenTests):
def setUp(self):
super(KvsToken, self).setUp()
self.token_api = token_kvs.Token(db={})
self.load_backends()
self.load_fixtures(default_fixtures)
class KvsTrust(test.TestCase, test_backend.TrustTests):

View File

@ -18,6 +18,7 @@ import uuid
import memcache
import default_fixtures
from keystone.common import utils
from keystone.openstack.common import timeutils
from keystone import test
@ -75,8 +76,10 @@ class MemcacheClient(object):
class MemcacheToken(test.TestCase, test_backend.TokenTests):
def setUp(self):
super(MemcacheToken, self).setUp()
self.load_backends()
fake_client = MemcacheClient()
self.token_api = token_memcache.Token(client=fake_client)
self.load_fixtures(default_fixtures)
def test_create_unicode_token_id(self):
token_id = unicode(self._create_token_id())