bug 1131840: fix auth and token data for XML translation

Change-Id: I4408b3e6e0752ca75bc36399f5148890820e9a89
This commit is contained in:
Guang Yee 2013-02-25 12:46:16 -08:00
parent f3d2a46220
commit 250e6716bd
14 changed files with 189 additions and 119 deletions

View File

@ -187,15 +187,15 @@ class AuthInfo(object):
def _validate_auth_methods(self):
# make sure auth methods are provided
if 'methods' not in self.auth['authentication']:
if 'methods' not in self.auth['identity']:
raise exception.ValidationError(attribute='methods',
target='authentication')
target='identity')
# make sure all the method data/payload are provided
for method_name in self.get_method_names():
if method_name not in self.auth['authentication']:
if method_name not in self.auth['identity']:
raise exception.ValidationError(attribute=method_name,
target='authentication')
target='identity')
# make sure auth method is supported
for method_name in self.get_method_names():
@ -213,12 +213,12 @@ class AuthInfo(object):
self._validate_and_normalize_scope_data()
def get_method_names(self):
""" Returns the authentication method names.
""" Returns the identity method names.
:returns: list of auth method names
"""
return self.auth['authentication']['methods']
return self.auth['identity']['methods']
def get_method_data(self, method):
""" Get the auth method payload.
@ -226,10 +226,10 @@ class AuthInfo(object):
:returns: auth method payload
"""
if method not in self.auth['authentication']['methods']:
if method not in self.auth['identity']['methods']:
raise exception.ValidationError(attribute=method_name,
target='authentication')
return self.auth['authentication'][method]
target='identity')
return self.auth['identity'][method]
def get_scope(self):
""" Get scope information.
@ -257,13 +257,9 @@ class Auth(controller.V3Controller):
super(Auth, self).__init__(*args, **kw)
self.token_controllers_ref = token.controllers.Auth()
def authenticate_for_token(self, context, authentication, scope=None):
def authenticate_for_token(self, context, auth=None):
""" Authenticate user and issue a token. """
try:
auth = None
auth = {'authentication': authentication}
if scope:
auth['scope'] = scope
auth_info = AuthInfo(context, auth=auth)
auth_context = {'extras': {}, 'method_names': []}
self.authenticate(context, auth_info, auth_context)
@ -306,7 +302,7 @@ class Auth(controller.V3Controller):
# requiring domain_id to do user lookup now. Try to get
# the user_id from auth_info for now, assuming external auth
# has check to make sure user is the same as the one specify
# in "authentication".
# in "identity".
if 'password' in auth_info.get_method_names():
user_info = auth_info.get_method_data('password')
user_ref = auth_info.lookup_user(user_info['user'])

View File

@ -49,21 +49,23 @@ class AuthMethodHandler(object):
"extras": {}}
Plugins are invoked in the order in which they are specified in the
"methods" attribute of the "authentication" request body.
"methods" attribute of the "identity" object.
For example, with the following authentication request,
{"authentication": {
"methods": ["custom-plugin", "password", "token"],
"token": {
"id": "sdfafasdfsfasfasdfds"
},
"custom-plugin": {
"custom-data": "sdfdfsfsfsdfsf"
},
"password": {
"user": {
"id": "s23sfad1",
"password": "secrete"
{"auth": {
"identity": {
"methods": ["custom-plugin", "password", "token"],
"token": {
"id": "sdfafasdfsfasfasdfds"
},
"custom-plugin": {
"custom-data": "sdfdfsfsfsdfsf"
},
"password": {
"user": {
"id": "s23sfad1",
"password": "secrete"
}
}
}
}}

View File

@ -38,12 +38,14 @@ class Token(auth.AuthMethodHandler):
target=METHOD_NAME)
token_id = auth_payload['id']
token_ref = self.token_api.get_token(context, token_id)
user_context.setdefault('user_id',
token_ref['token_data']['user']['id'])
user_context.setdefault('expires',
token_ref['expires'])
user_context['extras'].update(token_ref['token_data']['extras'])
user_context['method_names'] += token_ref['token_data']['methods']
user_context.setdefault(
'user_id', token_ref['token_data']['token']['user']['id'])
user_context.setdefault(
'expires', token_ref['token_data']['token']['expires'])
user_context['extras'].update(
token_ref['token_data']['token']['extras'])
user_context['method_names'].extend(
token_ref['token_data']['token']['methods'])
except AssertionError as e:
LOG.error(e)
raise exception.Unauthorized(e)

View File

@ -144,7 +144,7 @@ class TokenDataHelper(object):
self._populate_service_catalog(token_data, user_id, domain_id,
project_id)
self._populate_token(token_data, expires)
return token_data
return {'token': token_data}
def recreate_token_data(context, token_data=None, expires=None,
@ -161,6 +161,8 @@ def recreate_token_data(context, token_data=None, expires=None,
methods = ['password', 'token']
extras = {}
if token_data:
# peel the outer layer so its easier to operate
token_data = token_data['token']
domain_id = (token_data['domain']['id'] if 'domain' in token_data
else None)
project_id = (token_data['project']['id'] if 'project' in token_data
@ -207,20 +209,20 @@ def create_token(context, auth_context, auth_info):
CONF.signing.token_format)
token_api = token_module.Manager()
try:
expiry = token_data['expires']
expiry = token_data['token']['expires']
if isinstance(expiry, basestring):
expiry = timeutils.parse_isotime(expiry)
role_ids = []
if 'project' in token_data:
if 'project' in token_data['token']:
# project-scoped token, fill in the v2 token data
# all we care are the role IDs
role_ids = [role['id'] for role in token_data['roles']]
role_ids = [role['id'] for role in token_data['token']['roles']]
metadata_ref = {'roles': role_ids}
data = dict(key=token_id,
id=token_id,
expires=expiry,
user=token_data['user'],
tenant=token_data.get('project'),
user=token_data['token']['user'],
tenant=token_data['token'].get('project'),
metadata=metadata_ref,
token_data=token_data)
token_api.create_token(context, token_id, data)

View File

@ -30,7 +30,7 @@ def _build_policy_check_credentials(self, action, context, kwargs):
creds = {}
if 'token_data' in token_ref:
#V3 Tokens
token_data = token_ref['token_data']
token_data = token_ref['token_data']['token']
try:
creds['user_id'] = token_data['user']['id']
except AttributeError:

View File

@ -120,10 +120,28 @@ class XmlDeserializer(object):
# current spec does not have attributes on an element with text
values = values or text or {}
decoded_tag = XmlDeserializer._tag_name(element.tag, namespace)
list_item_tag = None
if decoded_tag[-1] == 's' and len(values) == 0:
# FIXME(gyee): special-case lists for now unti we
# figure out how to properly handle them.
# If any key ends with an 's', we are assuming it is a list.
# List element have no attributes.
values = list(values)
if decoded_tag == 'policies':
list_item_tag = 'policy'
else:
list_item_tag = decoded_tag[:-1]
for child in [self.walk_element(x) for x in element
if not isinstance(x, ENTITY_TYPE)]:
values = dict(values.items() + child.items())
if list_item_tag:
# FIXME(gyee): special-case lists for now unti we
# figure out how to properly handle them.
# If any key ends with an 's', we are assuming it is a list.
values.append(child[list_item_tag])
else:
values = dict(values.items() + child.items())
return {XmlDeserializer._tag_name(element.tag, namespace): values}
@ -173,7 +191,7 @@ class XmlSerializer(object):
container = etree.Element(k)
element.append(container)
name = k[:-1]
elif k == 'serviceCatalog':
elif k == 'serviceCatalog' or k == 'catalog':
# xsd compliance: <serviceCatalog> contains <service>s
container = etree.Element(k)
element.append(container)
@ -184,7 +202,13 @@ class XmlSerializer(object):
# unnecessary in XML
name = element.tag[:-1]
elif k[-1] == 's':
name = k[:-1]
container = etree.Element(k)
element.append(container)
if k == 'policies':
# need to special-case policies since policie is not a word
name = 'policy'
else:
name = k[:-1]
else:
name = k
@ -226,6 +250,8 @@ class XmlSerializer(object):
self._populate_sequence(element, value)
elif isinstance(value, dict):
self._populate_tree(element, value)
elif isinstance(value, basestring):
element.text = unicode(value)
def _populate_sequence(self, element, l):
"""Populates an etree with a sequence of elements, given a list."""
@ -233,6 +259,8 @@ class XmlSerializer(object):
name = element.tag
if element.tag[-1] == 's':
name = element.tag[:-1]
if name == 'policie':
name = 'policy'
for item in l:
child = etree.Element(name)

View File

@ -553,5 +553,5 @@ def render_exception(error):
'message': str(error)
}}
if isinstance(error, exception.AuthPluginException):
body['authentication'] = error.authentication
body['error']['identity'] = error.authentication
return render_response(status=(error.code, error.title), body=body)

View File

@ -16,6 +16,7 @@
import webob.dec
from keystone.common import logging
from keystone.common import serializer
from keystone.common import utils
from keystone.common import wsgi
@ -25,6 +26,7 @@ from keystone.openstack.common import jsonutils
CONF = config.CONF
LOG = logging.getLogger(__name__)
# Header used to transmit the auth token
@ -158,6 +160,7 @@ class XmlBodyMiddleware(wsgi.Middleware):
body_obj = jsonutils.loads(response.body)
response.body = serializer.to_xml(body_obj)
except Exception:
LOG.exception('Serializer failed')
raise exception.Error(message=response.body)
return response

View File

@ -56,7 +56,7 @@ class TestAuthPlugin(test.TestCase):
method_name = uuid.uuid4().hex
auth_data = {'methods': [method_name]}
auth_data[method_name] = {'test': 'test'}
auth_data = {'authentication': auth_data}
auth_data = {'identity': auth_data}
self.assertRaises(exception.AuthMethodNotSupported,
auth.controllers.AuthInfo,
None,
@ -66,7 +66,7 @@ class TestAuthPlugin(test.TestCase):
auth_data = {'methods': ['simple-challenge-response']}
auth_data['simple-challenge-response'] = {
'test': 'test'}
auth_data = {'authentication': auth_data}
auth_data = {'identity': auth_data}
auth_info = auth.controllers.AuthInfo(None, auth_data)
auth_context = {'extras': {}, 'method_names': []}
try:
@ -81,7 +81,7 @@ class TestAuthPlugin(test.TestCase):
auth_data = {'methods': ['simple-challenge-response']}
auth_data['simple-challenge-response'] = {
'response': EXPECTED_RESPONSE}
auth_data = {'authentication': auth_data}
auth_data = {'identity': auth_data}
auth_info = auth.controllers.AuthInfo(None, auth_data)
auth_context = {'extras': {}, 'method_names': []}
self.api.authenticate({}, auth_info, auth_context)
@ -91,7 +91,7 @@ class TestAuthPlugin(test.TestCase):
auth_data = {'methods': ['simple-challenge-response']}
auth_data['simple-challenge-response'] = {
'response': uuid.uuid4().hex}
auth_data = {'authentication': auth_data}
auth_data = {'identity': auth_data}
auth_info = auth.controllers.AuthInfo(None, auth_data)
auth_context = {'extras': {}, 'method_names': []}
self.assertRaises(exception.Unauthorized,

View File

@ -173,15 +173,15 @@ class RestfulTestCase(test.TestCase):
if response.body is not None and response.body.strip():
# if a body is provided, a Content-Type is also expected
header = response.getheader('Content-Type', None)
self.assertIn(self.content_type, header)
self.assertIn(content_type, header)
if self.content_type == 'json':
if content_type == 'json':
response.body = jsonutils.loads(response.body)
elif self.content_type == 'xml':
elif content_type == 'xml':
response.body = etree.fromstring(response.body)
def restful_request(self, method='GET', headers=None, body=None,
token=None, **kwargs):
token=None, content_type=None, **kwargs):
"""Serializes/deserializes json/xml as request/response body.
.. WARNING::
@ -196,13 +196,13 @@ class RestfulTestCase(test.TestCase):
if token is not None:
headers['X-Auth-Token'] = token
body = self._to_content_type(body, headers)
body = self._to_content_type(body, headers, content_type)
# Perform the HTTP request/response
response = self.request(method=method, headers=headers, body=body,
**kwargs)
self._from_content_type(response)
self._from_content_type(response, content_type)
# we can save some code & improve coverage by always doing this
if method != 'HEAD' and response.status >= 400:
@ -742,8 +742,9 @@ class XmlTestCase(RestfulTestCase, CoreApiTests):
self.assertIsNotNone(extension.find(self._tag('description')))
self.assertTrue(extension.find(self._tag('description')).text)
self.assertTrue(len(extension.findall(self._tag('link'))))
for link in extension.findall(self._tag('link')):
links = extension.find(self._tag('links'))
self.assertTrue(len(links.findall(self._tag('link'))))
for link in links.findall(self._tag('link')):
self.assertValidExtensionLink(link)
def assertValidExtensionListResponse(self, r):
@ -763,8 +764,10 @@ class XmlTestCase(RestfulTestCase, CoreApiTests):
def assertValidVersion(self, version):
super(XmlTestCase, self).assertValidVersion(version)
self.assertTrue(len(version.findall(self._tag('link'))))
for link in version.findall(self._tag('link')):
links = version.find(self._tag('links'))
self.assertIsNotNone(links)
self.assertTrue(len(links.findall(self._tag('link'))))
for link in links.findall(self._tag('link')):
self.assertIsNotNone(link.get('rel'))
self.assertIsNotNone(link.get('href'))

View File

@ -145,6 +145,17 @@ class XmlSerializerTestCase(test.TestCase):
self.assertSerializeDeserialize(d, xml)
def test_policy_list(self):
d = {"policies": [{"id": "ab12cd"}]}
xml = """
<?xml version="1.0" encoding="UTF-8"?>
<policies xmlns="http://docs.openstack.org/identity/api/v2.0">
<policy id="ab12cd"/>
</policies>
"""
self.assertEqualIgnoreWhitespace(serializer.to_xml(d), xml)
def test_values_list(self):
d = {
"objects": {

View File

@ -1,5 +1,8 @@
import uuid
from lxml import etree
from keystone.common import serializer
from keystone.common.sql import util as sql_util
from keystone import auth
from keystone import test
@ -128,21 +131,23 @@ class RestfulTestCase(test_content_types.RestfulTestCase):
method='POST',
path='/v3/auth/tokens',
body={
'authentication': {
'methods': ['password'],
'password': {
'user': {
'name': self.user['name'],
'password': self.user['password'],
'domain': {
'id': self.user['domain_id']
'auth': {
'identity': {
'methods': ['password'],
'password': {
'user': {
'name': self.user['name'],
'password': self.user['password'],
'domain': {
'id': self.user['domain_id']
}
}
}
}
},
'scope': {
'project': {
'id': self.project['id'],
},
'scope': {
'project': {
'id': self.project['id'],
}
}
}
})
@ -191,11 +196,15 @@ class RestfulTestCase(test_content_types.RestfulTestCase):
return self.v3_request(method='DELETE', path=path, **kwargs)
def assertValidErrorResponse(self, r):
self.assertIsNotNone(r.body.get('error'))
self.assertIsNotNone(r.body['error'].get('code'))
self.assertIsNotNone(r.body['error'].get('title'))
self.assertIsNotNone(r.body['error'].get('message'))
self.assertEqual(r.body['error']['code'], r.status)
if r.getheader('Content-Type') == 'application/xml':
resp = serializer.from_xml(etree.tostring(r.body))
else:
resp = r.body
self.assertIsNotNone(resp.get('error'))
self.assertIsNotNone(resp['error'].get('code'))
self.assertIsNotNone(resp['error'].get('title'))
self.assertIsNotNone(resp['error'].get('message'))
self.assertEqual(int(resp['error']['code']), r.status)
def assertValidListResponse(self, resp, key, entity_validator, ref=None,
expected_length=None):

View File

@ -14,9 +14,13 @@
import uuid
from lxml import etree
from keystone import auth
from keystone import config
from keystone import exception
from keystone.common import serializer
from keystone.openstack.common import jsonutils
from keystone.openstack.common import timeutils
from keystone import test
@ -86,13 +90,13 @@ def _build_authentication_request(token=None, user_id=None, username=None,
that it receives.
"""
auth_data = {}
auth_data['authentication'] = {'methods': []}
auth_data['identity'] = {'methods': []}
if token:
auth_data['authentication']['methods'].append('token')
auth_data['authentication']['token'] = _build_token_auth(token)
auth_data['identity']['methods'].append('token')
auth_data['identity']['token'] = _build_token_auth(token)
if user_id or username:
auth_data['authentication']['methods'].append('password')
auth_data['authentication']['password'] = _build_password_auth(
auth_data['identity']['methods'].append('password')
auth_data['identity']['password'] = _build_password_auth(
user_id, username, user_domain_id, user_domain_name, password)
if project_id or project_name or domain_id or domain_name:
auth_data['scope'] = _build_auth_scope(project_id,
@ -101,14 +105,17 @@ def _build_authentication_request(token=None, user_id=None, username=None,
project_domain_name,
domain_id,
domain_name)
return auth_data
return {'auth': auth_data}
class AuthTest(test_v3.RestfulTestCase):
def assertValidTokenResponse(self, r):
self.assertTrue(r.getheader('X-Subject-Token'))
token = r.body
if r.getheader('Content-Type') == 'application/xml':
token = serializer.from_xml(etree.tostring(r.body))['token']
else:
token = r.body['token']
self.assertIn('expires', token)
self.assertIn('user', token)
self.assertEqual(self.user['id'], token['user']['id'])
@ -169,23 +176,23 @@ class AuthTest(test_v3.RestfulTestCase):
the time in the comparison.
"""
def normalize(token):
del token['expires']
del token['issued_at']
del token['token']['expires']
del token['token']['issued_at']
return token
self.assertCloseEnoughForGovernmentWork(
timeutils.parse_isotime(a['expires']),
timeutils.parse_isotime(b['expires']))
timeutils.parse_isotime(a['token']['expires']),
timeutils.parse_isotime(b['token']['expires']))
self.assertCloseEnoughForGovernmentWork(
timeutils.parse_isotime(a['issued_at']),
timeutils.parse_isotime(b['issued_at']))
timeutils.parse_isotime(a['token']['issued_at']),
timeutils.parse_isotime(b['token']['issued_at']))
return self.assertDictEqual(normalize(a), normalize(b))
class TestAuthInfo(test.TestCase):
def test_missing_auth_methods(self):
auth_data = {'authentication': {}}
auth_data['authentication']['token'] = {'id': uuid.uuid4().hex}
auth_data = {'identity': {}}
auth_data['identity']['token'] = {'id': uuid.uuid4().hex}
self.assertRaises(exception.ValidationError,
auth.controllers.AuthInfo,
None,
@ -194,7 +201,7 @@ class TestAuthInfo(test.TestCase):
def test_unsupported_auth_method(self):
auth_data = {'methods': ['abc']}
auth_data['abc'] = {'test': 'test'}
auth_data = {'authentication': auth_data}
auth_data = {'identity': auth_data}
self.assertRaises(exception.AuthMethodNotSupported,
auth.controllers.AuthInfo,
None,
@ -202,7 +209,7 @@ class TestAuthInfo(test.TestCase):
def test_missing_auth_method_data(self):
auth_data = {'methods': ['password']}
auth_data = {'authentication': auth_data}
auth_data = {'identity': auth_data}
self.assertRaises(exception.ValidationError,
auth.controllers.AuthInfo,
None,
@ -211,7 +218,7 @@ class TestAuthInfo(test.TestCase):
def test_project_name_no_domain(self):
auth_data = _build_authentication_request(username='test',
password='test',
project_name='abc')
project_name='abc')['auth']
self.assertRaises(exception.ValidationError,
auth.controllers.AuthInfo,
None,
@ -221,7 +228,7 @@ class TestAuthInfo(test.TestCase):
auth_data = _build_authentication_request(user_id='test',
password='test',
project_name='test',
domain_name='test')
domain_name='test')['auth']
self.assertRaises(exception.ValidationError,
auth.controllers.AuthInfo,
None,
@ -262,11 +269,11 @@ class TestTokenAPIs(AuthTest):
method='GET')
v2_token = resp.body
self.assertEqual(v2_token['access']['user']['id'],
token_data['user']['id'])
token_data['token']['user']['id'])
self.assertEqual(v2_token['access']['token']['expires'],
token_data['expires'])
token_data['token']['expires'])
self.assertEqual(v2_token['access']['user']['roles'][0]['id'],
token_data['roles'][0]['id'])
token_data['token']['roles'][0]['id'])
def test_v3_v2_pki_token_intermix(self):
# FIXME(gyee): PKI tokens are not interchangeable because token
@ -287,11 +294,11 @@ class TestTokenAPIs(AuthTest):
method='GET')
v2_token = resp.body
self.assertEqual(v2_token['access']['user']['id'],
token_data['user']['id'])
token_data['token']['user']['id'])
self.assertEqual(v2_token['access']['token']['expires'],
token_data['expires'])
token_data['token']['expires'])
self.assertEqual(v2_token['access']['user']['roles'][0]['id'],
token_data['roles'][0]['id'])
token_data['token']['roles'][0]['id'])
def test_v2_v3_uuid_token_intermix(self):
self.opt_in_group('signing', token_format='UUID')
@ -312,11 +319,11 @@ class TestTokenAPIs(AuthTest):
resp = self.get('/auth/tokens', headers=headers)
token_data = resp.body
self.assertEqual(v2_token_data['access']['user']['id'],
token_data['user']['id'])
token_data['token']['user']['id'])
self.assertEqual(v2_token_data['access']['token']['expires'],
token_data['expires'])
token_data['token']['expires'])
self.assertEqual(v2_token_data['access']['user']['roles'][0]['name'],
token_data['roles'][0]['name'])
token_data['token']['roles'][0]['name'])
def test_v2_v3_pki_token_intermix(self):
self.opt_in_group('signing', token_format='PKI')
@ -337,21 +344,21 @@ class TestTokenAPIs(AuthTest):
resp = self.get('/auth/tokens', headers=headers)
token_data = resp.body
self.assertEqual(v2_token_data['access']['user']['id'],
token_data['user']['id'])
token_data['token']['user']['id'])
self.assertEqual(v2_token_data['access']['token']['expires'],
token_data['expires'])
token_data['token']['expires'])
self.assertEqual(v2_token_data['access']['user']['roles'][0]['name'],
token_data['roles'][0]['name'])
token_data['token']['roles'][0]['name'])
def test_rescoping_token(self):
expires = self.token_data['expires']
expires = self.token_data['token']['expires']
auth_data = _build_authentication_request(
token=self.token,
project_id=self.project_id)
r = self.post('/auth/tokens', body=auth_data)
self.assertValidProjectScopedTokenResponse(r)
# make sure expires stayed the same
self.assertEqual(expires, r.body['expires'])
self.assertEqual(expires, r.body['token']['expires'])
def test_check_token(self):
self.head('/auth/tokens', headers=self.headers, expected_status=204)
@ -370,7 +377,9 @@ class TestTokenAPIs(AuthTest):
self.assertIn('signed', r.body)
class TestAuth(AuthTest):
class TestAuthJSON(AuthTest):
content_type = 'json'
def test_unscoped_token_with_user_id(self):
auth_data = _build_authentication_request(
user_id=self.user['id'],
@ -601,7 +610,7 @@ class TestAuth(AuthTest):
def test_remote_user(self):
auth_data = _build_authentication_request(
user_id=self.user['id'],
password=self.user['password'])
password=self.user['password'])['auth']
api = auth.controllers.Auth()
context = {'REMOTE_USER': self.user['name']}
auth_info = auth.controllers.AuthInfo(None, auth_data)
@ -612,7 +621,7 @@ class TestAuth(AuthTest):
def test_remote_user_no_domain(self):
auth_data = _build_authentication_request(
username=self.user['name'],
password=self.user['password'])
password=self.user['password'])['auth']
api = auth.controllers.Auth()
context = {'REMOTE_USER': self.user['name']}
auth_info = auth.controllers.AuthInfo(None, auth_data)
@ -622,3 +631,7 @@ class TestAuth(AuthTest):
context,
auth_info,
auth_context)
class TestAuthXML(TestAuthJSON):
content_type = 'xml'

View File

@ -83,13 +83,14 @@ class IdentityTestProtectedCase(test_v3.RestfulTestCase):
# A default auth request we can use - un-scoped user token
self.auth = {}
self.auth['authentication'] = {'methods': []}
self.auth['authentication']['methods'].append('password')
self.auth['authentication']['password'] = {'user': {}}
self.auth['authentication']['password']['user']['id'] = (
self.auth['identity'] = {'methods': []}
self.auth['identity']['methods'].append('password')
self.auth['identity']['password'] = {'user': {}}
self.auth['identity']['password']['user']['id'] = (
self.user1['id'])
self.auth['authentication']['password']['user']['password'] = (
self.auth['identity']['password']['user']['password'] = (
self.user1['password'])
self.auth = {'auth': self.auth}
def tearDown(self):
super(IdentityTestProtectedCase, self).tearDown()
@ -136,7 +137,7 @@ class IdentityTestProtectedCase(test_v3.RestfulTestCase):
new_policy = """{"identity:list_users": ["domain_id:%(domain_id)s"]}"""
with open(self.tmpfilename, "w") as policyfile:
policyfile.write(new_policy)
self.auth['scope'] = {'domain': {'id': self.domainA['id']}}
self.auth['auth']['scope'] = {'domain': {'id': self.domainA['id']}}
url_by_name = '/users?domain_id=%s' % self.user1['domain_id']
r = self.get(url_by_name, auth=self.auth)
# We should only get back one user, the one in DomainA