Merge "Invalidate user tokens when password is changed" into stable/essex
This commit is contained in:
commit
35d5ebd54e
1
AUTHORS
1
AUTHORS
|
@ -25,6 +25,7 @@ Darren Birkett <darren.birkett@gmail.com>
|
|||
dcramer <david.cramer@rackspace.com>
|
||||
Dean Troyer <dtroyer@gmail.com>
|
||||
Deepak Garg <deepakgarg.iitg@gmail.com>
|
||||
Derek Higgins <derekh@redhat.com>
|
||||
Devin Carlen <devin.carlen@gmail.com>
|
||||
Dolph Mathews <dolph.mathews@gmail.com>
|
||||
Dolph Mathews <dolph.mathews@rackspace.com>
|
||||
|
|
|
@ -24,12 +24,15 @@ from keystone import config
|
|||
from keystone import exception
|
||||
from keystone import policy
|
||||
from keystone import token
|
||||
from keystone.common import logging
|
||||
from keystone.common import manager
|
||||
from keystone.common import wsgi
|
||||
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the Identity backend.
|
||||
|
@ -418,7 +421,16 @@ class UserController(wsgi.Application):
|
|||
return self.update_user(context, user_id, user)
|
||||
|
||||
def set_user_password(self, context, user_id, user):
|
||||
return self.update_user(context, user_id, user)
|
||||
user_ref = self.update_user(context, user_id, user)
|
||||
try:
|
||||
for token_id in self.token_api.list_tokens(context, user_id):
|
||||
self.token_api.delete_token(context, token_id)
|
||||
except exception.NotImplemented:
|
||||
# The password has been changed but tokens remain valid for
|
||||
# backends that can't list tokens for users
|
||||
LOG.warning('Password changed for %s, but existing tokens remain '
|
||||
'valid' % user_id)
|
||||
return user_ref
|
||||
|
||||
def update_user_tenant(self, context, user_id, user):
|
||||
"""Update the default tenant."""
|
||||
|
|
|
@ -44,3 +44,18 @@ class Token(kvs.Base, token.Driver):
|
|||
return self.db.delete('token-%s' % token_id)
|
||||
except KeyError:
|
||||
raise exception.TokenNotFound(token_id=token_id)
|
||||
|
||||
def list_tokens(self, user_id):
|
||||
tokens = []
|
||||
now = datetime.datetime.utcnow()
|
||||
for token, user_ref in self.db.items():
|
||||
if not token.startswith('token-'):
|
||||
continue
|
||||
if 'user' not in user_ref:
|
||||
continue
|
||||
if user_ref['user'].get('id') != user_id:
|
||||
continue
|
||||
if user_ref.get('expires') and user_ref.get('expires') < now:
|
||||
continue
|
||||
tokens.append(token.split('-', 1)[1])
|
||||
return tokens
|
||||
|
|
|
@ -81,3 +81,17 @@ class Token(sql.Base, token.Driver):
|
|||
with session.begin():
|
||||
session.delete(token_ref)
|
||||
session.flush()
|
||||
|
||||
def list_tokens(self, user_id):
|
||||
session = self.get_session()
|
||||
tokens = []
|
||||
now = datetime.datetime.utcnow()
|
||||
for token_ref in session.query(TokenModel)\
|
||||
.filter(TokenModel.expires > now):
|
||||
token_ref_dict = token_ref.to_dict()
|
||||
if 'user' not in token_ref_dict:
|
||||
continue
|
||||
if token_ref_dict['user'].get('id') != user_id:
|
||||
continue
|
||||
tokens.append(token_ref['id'])
|
||||
return tokens
|
||||
|
|
|
@ -87,6 +87,16 @@ class Driver(object):
|
|||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
def list_tokens(self, user_id):
|
||||
"""Returns a list of current token_id's for a user
|
||||
|
||||
:param user_id: identity of the user
|
||||
:type user_id: string
|
||||
:returns: list of token_id's
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
def _get_default_expire_time(self):
|
||||
"""Determine when a token should expire based on the config.
|
||||
|
||||
|
|
|
@ -286,6 +286,29 @@ class KeystoneClientTests(object):
|
|||
username='blah',
|
||||
password='blah')
|
||||
|
||||
def test_change_password_invalidates_token(self):
|
||||
from keystoneclient import exceptions as client_exceptions
|
||||
|
||||
client = self.get_client(admin=True)
|
||||
|
||||
username = uuid.uuid4().hex
|
||||
passwd = uuid.uuid4().hex
|
||||
user = client.users.create(name=username, password=passwd,
|
||||
email=uuid.uuid4().hex)
|
||||
|
||||
token_id = client.tokens.authenticate(username=username,
|
||||
password=passwd).id
|
||||
|
||||
# authenticate with a token should work before a password change
|
||||
client.tokens.authenticate(token=token_id)
|
||||
|
||||
client.users.update_password(user=user.id, password=uuid.uuid4().hex)
|
||||
|
||||
# authenticate with a token should not work after a password change
|
||||
self.assertRaises(client_exceptions.Unauthorized,
|
||||
client.tokens.authenticate,
|
||||
token=token_id)
|
||||
|
||||
def test_user_create_update_delete(self):
|
||||
from keystoneclient import exceptions as client_exceptions
|
||||
|
||||
|
|
Loading…
Reference in New Issue