Improve the performance of tokens deletion for user
Provide new delete the tokens api 'delete_tokens' to support delete all the tokens for user in one session in the sql backend. For the kvs and memcache, I also provide the corresponding implementation. Fix bug 1178063 Change-Id: I986a583e5900ea04e26cbdb7c49638a33818bca7
This commit is contained in:
parent
6d33805d0f
commit
d6cfe4f2e2
|
@ -153,23 +153,14 @@ class V2Controller(wsgi.Application):
|
|||
"""Base controller class for Identity API v2."""
|
||||
|
||||
def _delete_tokens_for_trust(self, context, user_id, trust_id):
|
||||
try:
|
||||
token_list = self.token_api.list_tokens(context, user_id,
|
||||
trust_id=trust_id)
|
||||
for token in token_list:
|
||||
self.token_api.delete_token(context, token)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
self.token_api.delete_tokens(context, user_id,
|
||||
trust_id=trust_id)
|
||||
|
||||
def _delete_tokens_for_user(self, context, user_id, project_id=None):
|
||||
#First delete tokens that could get other tokens.
|
||||
for token_id in self.token_api.list_tokens(context,
|
||||
user_id,
|
||||
tenant_id=project_id):
|
||||
try:
|
||||
self.token_api.delete_token(context, token_id)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
self.token_api.delete_tokens(context,
|
||||
user_id,
|
||||
tenant_id=project_id)
|
||||
|
||||
#delete tokens generated from trusts
|
||||
for trust in self.trust_api.list_trusts_for_trustee(context, user_id):
|
||||
|
|
|
@ -77,6 +77,40 @@ class Token(sql.Base, token.Driver):
|
|||
token_ref.valid = False
|
||||
session.flush()
|
||||
|
||||
def delete_tokens(self, user_id, tenant_id=None, trust_id=None):
|
||||
"""Deletes all tokens in one session
|
||||
|
||||
The user_id will be ignored if the trust_id is specified. user_id
|
||||
will always be specified.
|
||||
If using a trust, the token's user_id is set to the trustee's user ID
|
||||
or the trustor's user ID, so will use trust_id to query the tokens.
|
||||
|
||||
"""
|
||||
session = self.get_session()
|
||||
with session.begin():
|
||||
now = timeutils.utcnow()
|
||||
query = session.query(TokenModel)
|
||||
query = query.filter_by(valid=True)
|
||||
query = query.filter(TokenModel.expires > now)
|
||||
if trust_id:
|
||||
query = query.filter(TokenModel.trust_id == trust_id)
|
||||
else:
|
||||
query = query.filter(TokenModel.user_id == user_id)
|
||||
|
||||
for token_ref in query.all():
|
||||
if tenant_id:
|
||||
token_ref_dict = token_ref.to_dict()
|
||||
if not self._tenant_matches(tenant_id, token_ref_dict):
|
||||
continue
|
||||
token_ref.valid = False
|
||||
|
||||
session.flush()
|
||||
|
||||
def _tenant_matches(self, tenant_id, token_ref_dict):
|
||||
return ((tenant_id is None) or
|
||||
(token_ref_dict.get('tenant') and
|
||||
token_ref_dict['tenant'].get('id') == tenant_id))
|
||||
|
||||
def _list_tokens_for_trust(self, trust_id):
|
||||
session = self.get_session()
|
||||
tokens = []
|
||||
|
@ -92,11 +126,6 @@ class Token(sql.Base, token.Driver):
|
|||
return tokens
|
||||
|
||||
def _list_tokens_for_user(self, user_id, tenant_id=None):
|
||||
def tenant_matches(tenant_id, token_ref_dict):
|
||||
return ((tenant_id is None) or
|
||||
(token_ref_dict.get('tenant') and
|
||||
token_ref_dict['tenant'].get('id') == tenant_id))
|
||||
|
||||
session = self.get_session()
|
||||
tokens = []
|
||||
now = timeutils.utcnow()
|
||||
|
@ -107,7 +136,7 @@ class Token(sql.Base, token.Driver):
|
|||
token_references = query.filter_by(valid=True)
|
||||
for token_ref in token_references:
|
||||
token_ref_dict = token_ref.to_dict()
|
||||
if tenant_matches(tenant_id, token_ref_dict):
|
||||
if self._tenant_matches(tenant_id, token_ref_dict):
|
||||
tokens.append(token_ref['id'])
|
||||
return tokens
|
||||
|
||||
|
|
|
@ -166,6 +166,32 @@ class Driver(object):
|
|||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
def delete_tokens(self, user_id, tenant_id=None, trust_id=None):
|
||||
"""Deletes tokens by user.
|
||||
If the tenant_id is not None, only delete the tokens by user id under
|
||||
the specified tenant.
|
||||
If the trust_id is not None, it will be used to query tokens and the
|
||||
user_id will be ignored.
|
||||
|
||||
:param user_id: identity of user
|
||||
:type token_id: string
|
||||
:param tenant_id: identity of the tenant
|
||||
:type tenant_id: string
|
||||
:param trust_id: identified of the trust
|
||||
:type trust_id: string
|
||||
:returns: None.
|
||||
:raises: keystone.exception.TokenNotFound
|
||||
|
||||
"""
|
||||
token_list = self.list_tokens(user_id,
|
||||
tenant_id=tenant_id,
|
||||
trust_id=trust_id)
|
||||
for token in token_list:
|
||||
try:
|
||||
self.delete_token(token)
|
||||
except exception.NotFound:
|
||||
pass
|
||||
|
||||
def list_tokens(self, user_id, tenant_id=None, trust_id=None):
|
||||
"""Returns a list of current token_id's for a user
|
||||
|
||||
|
|
|
@ -2052,10 +2052,11 @@ class TokenTests(object):
|
|||
self.assertRaises(exception.TokenNotFound,
|
||||
self.token_api.delete_token, token_id)
|
||||
|
||||
def create_token_sample_data(self, tenant_id=None, trust_id=None):
|
||||
def create_token_sample_data(self, tenant_id=None, trust_id=None,
|
||||
user_id="testuserid"):
|
||||
token_id = self._create_token_id()
|
||||
data = {'id': token_id, 'a': 'b',
|
||||
'user': {'id': 'testuserid'}}
|
||||
'user': {'id': user_id}}
|
||||
if tenant_id is not None:
|
||||
data['tenant'] = {'id': tenant_id, 'name': tenant_id}
|
||||
if tenant_id is NULL_OBJECT:
|
||||
|
@ -2065,6 +2066,46 @@ class TokenTests(object):
|
|||
new_token = self.token_api.create_token(token_id, data)
|
||||
return new_token['id']
|
||||
|
||||
def test_delete_tokens(self):
|
||||
tokens = self.token_api.list_tokens('testuserid')
|
||||
self.assertEquals(len(tokens), 0)
|
||||
token_id1 = self.create_token_sample_data('testtenantid')
|
||||
token_id2 = self.create_token_sample_data('testtenantid')
|
||||
token_id3 = self.create_token_sample_data(tenant_id='testtenantid',
|
||||
user_id="testuserid1")
|
||||
tokens = self.token_api.list_tokens('testuserid')
|
||||
self.assertEquals(len(tokens), 2)
|
||||
self.assertIn(token_id2, tokens)
|
||||
self.assertIn(token_id1, tokens)
|
||||
self.token_api.delete_tokens(user_id='testuserid',
|
||||
tenant_id='testtenantid')
|
||||
tokens = self.token_api.list_tokens('testuserid')
|
||||
self.assertEquals(len(tokens), 0)
|
||||
self.assertRaises(exception.TokenNotFound,
|
||||
self.token_api.get_token, token_id1)
|
||||
self.assertRaises(exception.TokenNotFound,
|
||||
self.token_api.get_token, token_id2)
|
||||
|
||||
self.token_api.get_token(token_id3)
|
||||
|
||||
def test_delete_tokens_trust(self):
|
||||
tokens = self.token_api.list_tokens(user_id='testuserid')
|
||||
self.assertEquals(len(tokens), 0)
|
||||
token_id1 = self.create_token_sample_data(tenant_id='testtenantid',
|
||||
trust_id='testtrustid')
|
||||
token_id2 = self.create_token_sample_data(tenant_id='testtenantid',
|
||||
user_id="testuserid1",
|
||||
trust_id="testtrustid1")
|
||||
tokens = self.token_api.list_tokens('testuserid')
|
||||
self.assertEquals(len(tokens), 1)
|
||||
self.assertIn(token_id1, tokens)
|
||||
self.token_api.delete_tokens(user_id='testuserid',
|
||||
tenant_id='testtenantid',
|
||||
trust_id='testtrustid')
|
||||
self.assertRaises(exception.TokenNotFound,
|
||||
self.token_api.get_token, token_id1)
|
||||
self.token_api.get_token(token_id2)
|
||||
|
||||
def test_token_list(self):
|
||||
tokens = self.token_api.list_tokens('testuserid')
|
||||
self.assertEquals(len(tokens), 0)
|
||||
|
|
Loading…
Reference in New Issue