CVE-2012-3426 (Python, published 2012-07-31T10:45Z)
Description: value: OpenStack Keystone before 2012.1.1, as used in OpenStack Folsom before Folsom-1 and OpenStack Essex, does not properly implement token expiration, which allows remote authenticated users to bypass intended authorization restrictions by (1) creating new tokens through token chaining, (2) leveraging possession of a token for a disabled user account, or (3) leveraging possession of a token for an account with a changed password.
Severity: MEDIUM (CVSS v3 base score: )
Weakness: CWE-264 \u2014 Permissions, Privileges, and Access Controls
Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.
Repository: https://github.com/openstack/keystone
Files changed:
keystone/identity/core.py
keystone/service.py
tests/test_keystoneclient.py
Commit message: Invalidate user tokens when a user is disabled

Fixes Bug 997194

Delete valid tokens for a user when they have been disabled

Moved logic to delete tokens into update_user, as this can be called
directly form the REST API.

Also checks if a user is enabled when creating a token from another
token, this helps in cases there the backend didn't support listing of
tokens (and as a result weren't deleted)

Change-Id: Ib5ed73a7873bfa66ef31bf6d0f0322f50e677688


Vulnerable code:
        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
                    raise exception.Forbidden(message='User has been disabled')
        self.assertRaises(client_exceptions.AuthorizationFailure,
        self.assertRaises(client_exceptions.AuthorizationFailure,

Fixed code:

        # If the password was changed or the user was disabled we clear tokens
        if user.get('password') or user.get('enabled', True) == False:
            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 users status has been changed but tokens remain valid for
                # backends that can't list tokens for users
                LOG.warning('User %s status has changed, but existing tokens '
                            'remain valid' % user_id)
        return self.update_user(context, user_id, user)
LOG = logging.getLogger(__name__)


                    LOG.warning('User %s is disabled' % user_id)
                    raise exception.Unauthorized()
            # If the user is disabled don't allow them to authenticate
            current_user_ref = self.identity_api.get_user(
                                                    context=context,
                                                    user_id=user_ref['id'])
            if not current_user_ref.get('enabled', True):
                LOG.warning('User %s is disabled' % user_ref['id'])
                raise exception.Unauthorized()

    def test_disable_user_invalidates_token(self):
        from keystoneclient import exceptions as client_exceptions

        admin_client = self.get_client(admin=True)
        foo_client = self.get_client(self.user_foo)

        admin_client.users.update_enabled(user=self.user_foo['id'],
                                          enabled=False)

        self.assertRaises(client_exceptions.Unauthorized,
                          foo_client.tokens.authenticate,
                          token=foo_client.auth_token)

        self.assertRaises(client_exceptions.Unauthorized,
                          self.get_client,
                          self.user_foo)

        self.assertRaises(client_exceptions.Unauthorized,
        self.assertRaises(client_exceptions.Unauthorized,