Return 404 instead of 401 for tokens w/o roles

If a scoped-token was validated and the user didn't have any role assignment
on a project, keystone would return a 401 Unauthorized. This was the
case when the fernet token provider was enabled because the reference is
rebuilt on every request. The uuid token provider has a different behavior - if
the token isn't found in the backend a 404 Not Found is returned. Furthermore,
for persisted tokens, any validation error will result in 404, such as in the
case where user no longer have any roles assigned for the given scope.

These two behaviors should be consistent regardless of the token provider.

Closes-Bug: 1541621
Change-Id: If9fd6060ed13a7c03ab8d70ebed1adecafef9160
This commit is contained in:
Raildo Mascena 2016-02-08 14:58:34 +00:00 committed by Lance Bragstad
parent 05c58bb35e
commit f1792f4089
2 changed files with 55 additions and 14 deletions

View File

@ -687,6 +687,38 @@ class TokenAPITests(object):
self.assertIn(implied['id'], token_role_ids)
self.assertNotIn(new_role['id'], token_role_ids)
def test_remove_all_roles_from_scope_result_in_404(self):
# create a new user
new_user = unit.create_user(self.identity_api,
domain_id=self.domain['id'])
# give the new user a role on a project
path = '/projects/%s/users/%s/roles/%s' % (
self.project['id'], new_user['id'], self.role['id'])
self.put(path=path)
# authenticate as the new user and get a project-scoped token
auth_data = self.build_authentication_request(
user_id=new_user['id'],
password=new_user['password'],
project_id=self.project['id'])
subject_token_id = self.v3_create_token(auth_data).headers.get(
'X-Subject-Token')
# make sure the project-scoped token is valid
headers = {'X-Subject-Token': subject_token_id}
r = self.get('/auth/tokens', headers=headers)
self.assertValidProjectScopedTokenResponse(r)
# remove the roles from the user for the given scope
path = '/projects/%s/users/%s/roles/%s' % (
self.project['id'], new_user['id'], self.role['id'])
self.delete(path=path)
# token validation should now result in 404
self.get('/auth/tokens', headers=headers,
expected_status=http_client.NOT_FOUND)
class TokenDataTests(object):
"""Test the data in specific token types."""

View File

@ -268,19 +268,24 @@ class Manager(manager.Manager):
if not token_id:
raise exception.TokenNotFound(_('No token in the request'))
# NOTE(lbragstad): Only go to persistent storage if we have a token to
# fetch from the backend (the driver persists the token). Otherwise
# the information about the token must be in the token id.
if not self._needs_persistence:
token_ref = self.validate_non_persistent_token(token_id)
else:
unique_id = utils.generate_unique_id(token_id)
# NOTE(morganfainberg): Ensure we never use the long-form token_id
# (PKI) as part of the cache_key.
token_ref = self._persistence.get_token(unique_id)
token_ref = self._validate_v3_token(token_ref)
self._is_valid_token(token_ref)
return token_ref
try:
# NOTE(lbragstad): Only go to persistent storage if we have a token
# to fetch from the backend (the driver persists the token).
# Otherwise the information about the token must be in the token
# id.
if not self._needs_persistence:
token_ref = self.validate_non_persistent_token(token_id)
else:
unique_id = utils.generate_unique_id(token_id)
# NOTE(morganfainberg): Ensure we never use the long-form
# token_id (PKI) as part of the cache_key.
token_ref = self._persistence.get_token(unique_id)
token_ref = self._validate_v3_token(token_ref)
self._is_valid_token(token_ref)
return token_ref
except exception.Unauthorized as e:
LOG.debug('Unable to validate token: %s', e)
raise exception.TokenNotFound(token_id=token_id)
@MEMOIZE
def _validate_token(self, token_id):
@ -294,7 +299,11 @@ class Manager(manager.Manager):
token_ref = self._persistence.get_token(token_id)
version = self.get_token_version(token_ref)
if version == self.V3:
return self.driver.validate_v3_token(token_ref)
try:
return self.driver.validate_v3_token(token_ref)
except exception.Unauthorized as e:
LOG.debug('Unable to validate token: %s', e)
raise exception.TokenNotFound(token_id=token_id)
elif version == self.V2:
return self.driver.validate_v2_token(token_ref)
raise exception.UnsupportedTokenVersionException()