bug 1131840: fix auth and token data for XML translation
Change-Id: I4408b3e6e0752ca75bc36399f5148890820e9a89
This commit is contained in:
parent
f3d2a46220
commit
250e6716bd
@ -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'])
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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'))
|
||||
|
||||
|
@ -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": {
|
||||
|
@ -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):
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user