Revert "Validate domain ownership for v2 tokens"

This reverts commit c4723550aa.

This revert is being proposed as it breaks behavior that real-world
deployments rely on. The deployments requested the V2 token with
user_id and tenantId and then used the V2 token for the
non-default-domain user to access swift.

While the deployment is being encouraged to fix their code to use V3,
this is behavior that was supported and used.

This revert was done by hand due to the volume of change that has
occured to the tests since the original patch landed.

Conflicts (a lot of test refactoring):
    keystone/tests/unit/test_v3_assignment.py
    keystone/tests/unit/test_v3_auth.py
    keystone/tests/unit/test_v3_identity.py

Change-Id: I4a303a5fcc8c2dacef5960e9e26ad9402f34a790
Closes-Bug: 1527759
This commit is contained in:
Morgan Fainberg 2016-01-07 15:18:03 -08:00
parent bf54eada0f
commit c75f39f3d6
4 changed files with 15 additions and 98 deletions

View File

@ -247,27 +247,13 @@ class V2Controller(wsgi.Application):
@staticmethod
def filter_domain_id(ref):
"""Remove domain_id since v2 calls are not domain-aware."""
if 'domain_id' in ref:
if ref['domain_id'] != CONF.identity.default_domain_id:
raise exception.Unauthorized(
_('Non-default domain is not supported'))
del ref['domain_id']
ref.pop('domain_id', None)
return ref
@staticmethod
def filter_domain(ref):
"""Remove domain since v2 calls are not domain-aware.
V3 Fernet tokens builds the users with a domain in the token data.
This method will ensure that users create in v3 belong to the default
domain.
"""
if 'domain' in ref:
if ref['domain'].get('id') != CONF.identity.default_domain_id:
raise exception.Unauthorized(
_('Non-default domain is not supported'))
del ref['domain']
"""Remove domain since v2 calls are not domain-aware."""
ref.pop('domain', None)
return ref
@staticmethod
@ -310,15 +296,9 @@ class V2Controller(wsgi.Application):
def v3_to_v2_user(ref):
"""Convert a user_ref from v3 to v2 compatible.
- v2.0 users are not domain aware, and should have domain_id validated
to be the default domain, and then removed.
- v2.0 users expect the use of tenantId instead of default_project_id.
- v2.0 users have a username attribute.
This method should only be applied to user_refs being returned from the
v2.0 controller(s).
* v2.0 users are not domain aware, and should have domain_id removed
* v2.0 users expect the use of tenantId instead of default_project_id
* v2.0 users have a username attribute
If ref is a list type, we will iterate through each element and do the
conversion.

View File

@ -134,18 +134,6 @@ class TokenAPITests(object):
def test_default_fixture_scope_token(self):
self.assertIsNotNone(self.get_scoped_token())
def test_v3_v2_intermix_non_default_domain_failed(self):
v3_token = self.get_requested_token(self.build_authentication_request(
user_id=self.user['id'],
password=self.user['password']))
# now validate the v3 token with v2 API
self.admin_request(
path='/v2.0/tokens/%s' % v3_token,
token=CONF.admin_token,
method='GET',
expected_status=http_client.UNAUTHORIZED)
def test_v3_v2_intermix_new_default_domain(self):
# If the default_domain_id config option is changed, then should be
# able to validate a v3 token with user in the new domain.
@ -193,7 +181,7 @@ class TokenAPITests(object):
token=CONF.admin_token,
expected_status=http_client.UNAUTHORIZED)
def test_v3_v2_intermix_non_default_project_failed(self):
def test_v3_v2_intermix_non_default_project_succeed(self):
# self.project is in a non-default domain
v3_token = self.get_requested_token(self.build_authentication_request(
user_id=self.default_domain_user['id'],
@ -204,10 +192,9 @@ class TokenAPITests(object):
self.admin_request(
method='GET',
path='/v2.0/tokens/%s' % v3_token,
token=CONF.admin_token,
expected_status=http_client.UNAUTHORIZED)
token=CONF.admin_token)
def test_v3_v2_intermix_non_default_user_failed(self):
def test_v3_v2_intermix_non_default_user_succeed(self):
self.assignment_api.create_grant(
self.role['id'],
user_id=self.user['id'],
@ -223,8 +210,7 @@ class TokenAPITests(object):
self.admin_request(
method='GET',
path='/v2.0/tokens/%s' % v3_token,
token=CONF.admin_token,
expected_status=http_client.UNAUTHORIZED)
token=CONF.admin_token)
def test_v3_v2_intermix_domain_scope_failed(self):
self.assignment_api.create_grant(
@ -4527,17 +4513,6 @@ class TestFernetTokenProvider(test_v3.RestfulTestCase):
self.token_provider_api.validate_token,
trust_scoped_token)
def test_v2_validate_unscoped_token_returns_unauthorized(self):
"""Test raised exception when validating unscoped token.
Test that validating an unscoped token in v2.0 of a v3 user of a
non-default domain returns unauthorized.
"""
unscoped_token = self._get_unscoped_token()
self.assertRaises(exception.Unauthorized,
self.token_provider_api.validate_v2_token,
unscoped_token)
def test_v2_validate_domain_scoped_token_returns_unauthorized(self):
"""Test raised exception when validating a domain scoped token.

View File

@ -162,8 +162,7 @@ class ResourceTestCase(test_v3.RestfulTestCase,
self.assignment_api.add_user_to_project(project2['id'],
user2['id'])
# First check a user in that domain can authenticate. The v2 user
# cannot authenticate because they exist outside the default domain.
# First check a user in that domain can authenticate..
body = {
'auth': {
'passwordCredentials': {
@ -174,8 +173,7 @@ class ResourceTestCase(test_v3.RestfulTestCase,
}
}
self.admin_request(
path='/v2.0/tokens', method='POST', body=body,
expected_status=http_client.UNAUTHORIZED)
path='/v2.0/tokens', method='POST', body=body)
auth_data = self.build_authentication_request(
user_id=user2['id'],
@ -1255,9 +1253,9 @@ class ResourceV3toV2MethodsTestCase(unit.TestCase):
'other_data': other_data}
updated_ref = controller.V2Controller.filter_domain(default_domain_ref)
self.assertNotIn('domain', updated_ref)
self.assertRaises(exception.Unauthorized,
controller.V2Controller.filter_domain,
non_default_domain_ref)
self.assertNotIn(
'domain',
controller.V2Controller.filter_domain(non_default_domain_ref))
def test_v2controller_filter_project_parent_id(self):
# V2.0 is not project hierarchy aware, ensure parent_id is popped off.

View File

@ -46,23 +46,7 @@ class V2TokenDataHelper(object):
token['issued_at'] = v3_token.get('issued_at')
token['audit_ids'] = v3_token.get('audit_ids')
# Bail immediately if this is a domain-scoped token, which is not
# supported by the v2 API at all.
if 'domain' in v3_token:
raise exception.Unauthorized(_(
'Domains are not supported by the v2 API. Please use the v3 '
'API instead.'))
# Bail if this is a project-scoped token outside the default domain,
# which may result in a namespace collision with a project inside the
# default domain.
if 'project' in v3_token:
if (v3_token['project']['domain']['id'] !=
CONF.identity.default_domain_id):
raise exception.Unauthorized(_(
'Project not found in the default domain (please use the '
'v3 API instead): %s') % v3_token['project']['id'])
# v3 token_data does not contain all tenant attributes
tenant = self.resource_api.get_project(
v3_token['project']['id'])
@ -73,15 +57,6 @@ class V2TokenDataHelper(object):
# Build v2 user
v3_user = v3_token['user']
# Bail if this is a token outside the default domain,
# which may result in a namespace collision with a project inside the
# default domain.
if ('domain' in v3_user and v3_user['domain']['id'] !=
CONF.identity.default_domain_id):
raise exception.Unauthorized(_(
'User not found in the default domain (please use the v3 API '
'instead): %s') % v3_user['id'])
user = common_controller.V2Controller.v3_to_v2_user(v3_user)
# Maintain Trust Data
@ -639,21 +614,10 @@ class BaseProvider(provider.Provider):
token.provider.V3):
# this is a V3 token
msg = _('Non-default domain is not supported')
# user in a non-default is prohibited
if (token_ref['token_data']['token']['user']['domain']['id'] !=
CONF.identity.default_domain_id):
raise exception.Unauthorized(msg)
# domain scoping is prohibited
if token_ref['token_data']['token'].get('domain'):
raise exception.Unauthorized(
_('Domain scoped token is not supported'))
# project in non-default domain is prohibited
if token_ref['token_data']['token'].get('project'):
project = token_ref['token_data']['token']['project']
project_domain_id = project['domain']['id']
# scoped to project in non-default domain is prohibited
if project_domain_id != CONF.identity.default_domain_id:
raise exception.Unauthorized(msg)
# if token is scoped to trust, both trustor and trustee must
# be in the default domain. Furthermore, the delegated project
# must also be in the default domain