Merge "Refactor request methods onto request object"
This commit is contained in:
commit
6661501498
@ -219,6 +219,7 @@ from keystonemiddleware.auth_token import _base
|
||||
from keystonemiddleware.auth_token import _cache
|
||||
from keystonemiddleware.auth_token import _exceptions as exc
|
||||
from keystonemiddleware.auth_token import _identity
|
||||
from keystonemiddleware.auth_token import _request
|
||||
from keystonemiddleware.auth_token import _revocations
|
||||
from keystonemiddleware.auth_token import _signing_dir
|
||||
from keystonemiddleware.auth_token import _user_plugin
|
||||
@ -363,26 +364,6 @@ CONF.register_opts(_OPTS, group=_base.AUTHTOKEN_GROUP)
|
||||
|
||||
_LOG = logging.getLogger(__name__)
|
||||
|
||||
_HEADER_TEMPLATE = {
|
||||
'X%s-Domain-Id': 'domain_id',
|
||||
'X%s-Domain-Name': 'domain_name',
|
||||
'X%s-Project-Id': 'project_id',
|
||||
'X%s-Project-Name': 'project_name',
|
||||
'X%s-Project-Domain-Id': 'project_domain_id',
|
||||
'X%s-Project-Domain-Name': 'project_domain_name',
|
||||
'X%s-User-Id': 'user_id',
|
||||
'X%s-User-Name': 'username',
|
||||
'X%s-User-Domain-Id': 'user_domain_id',
|
||||
'X%s-User-Domain-Name': 'user_domain_name',
|
||||
}
|
||||
|
||||
_DEPRECATED_HEADER_TEMPLATE = {
|
||||
'X-User': 'username',
|
||||
'X-Tenant-Id': 'project_id',
|
||||
'X-Tenant-Name': 'project_name',
|
||||
'X-Tenant': 'project_name',
|
||||
}
|
||||
|
||||
|
||||
class _BIND_MODE(object):
|
||||
DISABLED = 'disabled'
|
||||
@ -400,42 +381,6 @@ def _token_is_v3(token_info):
|
||||
return ('token' in token_info)
|
||||
|
||||
|
||||
def _v3_to_v2_catalog(catalog):
|
||||
"""Convert a catalog to v2 format.
|
||||
|
||||
X_SERVICE_CATALOG must be specified in v2 format. If you get a token
|
||||
that is in v3 convert it.
|
||||
"""
|
||||
v2_services = []
|
||||
for v3_service in catalog:
|
||||
# first copy over the entries we allow for the service
|
||||
v2_service = {'type': v3_service['type']}
|
||||
try:
|
||||
v2_service['name'] = v3_service['name']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# now convert the endpoints. Because in v3 we specify region per
|
||||
# URL not per group we have to collect all the entries of the same
|
||||
# region together before adding it to the new service.
|
||||
regions = {}
|
||||
for v3_endpoint in v3_service.get('endpoints', []):
|
||||
region_name = v3_endpoint.get('region')
|
||||
try:
|
||||
region = regions[region_name]
|
||||
except KeyError:
|
||||
region = {'region': region_name} if region_name else {}
|
||||
regions[region_name] = region
|
||||
|
||||
interface_name = v3_endpoint['interface'].lower() + 'URL'
|
||||
region[interface_name] = v3_endpoint['url']
|
||||
|
||||
v2_service['endpoints'] = list(regions.values())
|
||||
v2_services.append(v2_service)
|
||||
|
||||
return v2_services
|
||||
|
||||
|
||||
def _conf_values_type_convert(conf):
|
||||
"""Convert conf values into correct type."""
|
||||
if not conf:
|
||||
@ -518,7 +463,6 @@ class AuthProtocol(object):
|
||||
|
||||
self._check_revocations_for_cached = self._conf_get(
|
||||
'check_revocations_for_cached')
|
||||
self._init_auth_headers()
|
||||
|
||||
def _conf_get(self, name, group=_base.AUTHTOKEN_GROUP):
|
||||
# try config from paste-deploy first
|
||||
@ -527,7 +471,7 @@ class AuthProtocol(object):
|
||||
else:
|
||||
return CONF[group][name]
|
||||
|
||||
@webob.dec.wsgify
|
||||
@webob.dec.wsgify(RequestClass=_request._AuthTokenRequest)
|
||||
def __call__(self, request):
|
||||
"""Handle incoming request.
|
||||
|
||||
@ -536,7 +480,7 @@ class AuthProtocol(object):
|
||||
|
||||
"""
|
||||
self._token_cache.initialize(request.environ)
|
||||
self._remove_auth_headers(request)
|
||||
request.remove_auth_headers()
|
||||
|
||||
try:
|
||||
user_auth_ref = None
|
||||
@ -548,8 +492,8 @@ class AuthProtocol(object):
|
||||
user_auth_ref, user_token_info = self._validate_token(
|
||||
user_token_info, request.environ)
|
||||
request.environ['keystone.token_info'] = user_token_info
|
||||
user_headers = self._build_user_headers(user_auth_ref)
|
||||
request.headers.update(user_headers)
|
||||
request.set_user_headers(user_auth_ref,
|
||||
self._include_service_catalog)
|
||||
except exc.InvalidToken:
|
||||
if self._delay_auth_decision:
|
||||
self._LOG.info(
|
||||
@ -567,8 +511,7 @@ class AuthProtocol(object):
|
||||
if serv_token is not None:
|
||||
serv_auth_ref, serv_token_info = self._validate_token(
|
||||
serv_token, request.environ)
|
||||
serv_headers = self._build_service_headers(serv_auth_ref)
|
||||
request.headers.update(serv_headers)
|
||||
request.set_service_headers(serv_auth_ref)
|
||||
except exc.InvalidToken:
|
||||
if self._delay_auth_decision:
|
||||
self._LOG.info(
|
||||
@ -597,41 +540,6 @@ class AuthProtocol(object):
|
||||
|
||||
return response
|
||||
|
||||
def _init_auth_headers(self):
|
||||
"""Initialize auth header list.
|
||||
|
||||
Both user and service token headers are generated.
|
||||
"""
|
||||
auth_headers = ['X-Service-Catalog',
|
||||
'X-Identity-Status',
|
||||
'X-Service-Identity-Status',
|
||||
'X-Roles',
|
||||
'X-Service-Roles']
|
||||
for key in six.iterkeys(_HEADER_TEMPLATE):
|
||||
auth_headers.append(key % '')
|
||||
# Service headers
|
||||
auth_headers.append(key % '-Service')
|
||||
|
||||
# Deprecated headers
|
||||
auth_headers.append('X-Role')
|
||||
for key in six.iterkeys(_DEPRECATED_HEADER_TEMPLATE):
|
||||
auth_headers.append(key)
|
||||
|
||||
self._auth_headers = auth_headers
|
||||
|
||||
def _remove_auth_headers(self, request):
|
||||
"""Remove headers so a user can't fake authentication.
|
||||
|
||||
Both user and service token headers are removed.
|
||||
|
||||
:param env: wsgi request environment
|
||||
|
||||
"""
|
||||
self._LOG.debug('Removing headers from request environment: %s',
|
||||
','.join(self._auth_headers))
|
||||
for k in self._auth_headers:
|
||||
request.headers.pop(k, None)
|
||||
|
||||
def _get_user_token_from_request(self, request):
|
||||
"""Get token id from request.
|
||||
|
||||
@ -783,61 +691,6 @@ class AuthProtocol(object):
|
||||
self._LOG.warning(_LW('Authorization failed for token'))
|
||||
raise exc.InvalidToken(_('Token authorization failed'))
|
||||
|
||||
def _build_user_headers(self, auth_ref):
|
||||
"""Convert token object into headers.
|
||||
|
||||
Build headers that represent authenticated user - see main
|
||||
doc info at start of file for details of headers to be defined.
|
||||
|
||||
:param token_info: token object returned by identity
|
||||
server on authentication
|
||||
:raises exc.InvalidToken: when unable to parse token object
|
||||
|
||||
"""
|
||||
roles = ','.join(auth_ref.role_names)
|
||||
|
||||
rval = {
|
||||
'X-Identity-Status': 'Confirmed',
|
||||
'X-Roles': roles,
|
||||
}
|
||||
|
||||
for header_tmplt, attr in six.iteritems(_HEADER_TEMPLATE):
|
||||
rval[header_tmplt % ''] = getattr(auth_ref, attr)
|
||||
|
||||
# Deprecated headers
|
||||
rval['X-Role'] = roles
|
||||
for header_tmplt, attr in six.iteritems(_DEPRECATED_HEADER_TEMPLATE):
|
||||
rval[header_tmplt] = getattr(auth_ref, attr)
|
||||
|
||||
if self._include_service_catalog and auth_ref.has_service_catalog():
|
||||
catalog = auth_ref.service_catalog.get_data()
|
||||
if auth_ref.version == 'v3':
|
||||
catalog = _v3_to_v2_catalog(catalog)
|
||||
rval['X-Service-Catalog'] = jsonutils.dumps(catalog)
|
||||
|
||||
return rval
|
||||
|
||||
def _build_service_headers(self, auth_ref):
|
||||
"""Convert token object into service headers.
|
||||
|
||||
Build headers that represent authenticated user - see main
|
||||
doc info at start of file for details of headers to be defined.
|
||||
|
||||
:param auth_ref: authentication information
|
||||
"""
|
||||
|
||||
roles = ','.join(auth_ref.role_names)
|
||||
rval = {
|
||||
'X-Service-Identity-Status': 'Confirmed',
|
||||
'X-Service-Roles': roles,
|
||||
}
|
||||
|
||||
header_type = '-Service'
|
||||
for header_tmplt, attr in six.iteritems(_HEADER_TEMPLATE):
|
||||
rval[header_tmplt % header_type] = getattr(auth_ref, attr)
|
||||
|
||||
return rval
|
||||
|
||||
def _invalid_user_token(self, msg=False):
|
||||
# NOTE(jamielennox): use False as the default so that None is valid
|
||||
if msg is False:
|
||||
|
180
keystonemiddleware/auth_token/_request.py
Normal file
180
keystonemiddleware/auth_token/_request.py
Normal file
@ -0,0 +1,180 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import itertools
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
import webob
|
||||
|
||||
|
||||
def _v3_to_v2_catalog(catalog):
|
||||
"""Convert a catalog to v2 format.
|
||||
|
||||
X_SERVICE_CATALOG must be specified in v2 format. If you get a token
|
||||
that is in v3 convert it.
|
||||
"""
|
||||
v2_services = []
|
||||
for v3_service in catalog:
|
||||
# first copy over the entries we allow for the service
|
||||
v2_service = {'type': v3_service['type']}
|
||||
try:
|
||||
v2_service['name'] = v3_service['name']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# now convert the endpoints. Because in v3 we specify region per
|
||||
# URL not per group we have to collect all the entries of the same
|
||||
# region together before adding it to the new service.
|
||||
regions = {}
|
||||
for v3_endpoint in v3_service.get('endpoints', []):
|
||||
region_name = v3_endpoint.get('region')
|
||||
try:
|
||||
region = regions[region_name]
|
||||
except KeyError:
|
||||
region = {'region': region_name} if region_name else {}
|
||||
regions[region_name] = region
|
||||
|
||||
interface_name = v3_endpoint['interface'].lower() + 'URL'
|
||||
region[interface_name] = v3_endpoint['url']
|
||||
|
||||
v2_service['endpoints'] = list(regions.values())
|
||||
v2_services.append(v2_service)
|
||||
|
||||
return v2_services
|
||||
|
||||
|
||||
class _AuthTokenRequest(webob.Request):
|
||||
|
||||
_HEADER_TEMPLATE = {
|
||||
'X%s-Domain-Id': 'domain_id',
|
||||
'X%s-Domain-Name': 'domain_name',
|
||||
'X%s-Project-Id': 'project_id',
|
||||
'X%s-Project-Name': 'project_name',
|
||||
'X%s-Project-Domain-Id': 'project_domain_id',
|
||||
'X%s-Project-Domain-Name': 'project_domain_name',
|
||||
'X%s-User-Id': 'user_id',
|
||||
'X%s-User-Name': 'username',
|
||||
'X%s-User-Domain-Id': 'user_domain_id',
|
||||
'X%s-User-Domain-Name': 'user_domain_name',
|
||||
}
|
||||
|
||||
_ROLES_TEMPLATE = 'X%s-Roles'
|
||||
|
||||
_USER_HEADER_PREFIX = ''
|
||||
_SERVICE_HEADER_PREFIX = '-Service'
|
||||
|
||||
_USER_STATUS_HEADER = 'X-Identity-Status'
|
||||
_SERVICE_STATUS_HEADER = 'X-Service-Identity-Status'
|
||||
|
||||
_SERVICE_CATALOG_HEADER = 'X-Service-Catalog'
|
||||
|
||||
_CONFIRMED = 'Confirmed'
|
||||
_INVALID = 'Invalid'
|
||||
|
||||
# header names that have been deprecated in favour of something else.
|
||||
_DEPRECATED_HEADER_MAP = {
|
||||
'X-Role': 'X-Roles',
|
||||
'X-User': 'X-User-Name',
|
||||
'X-Tenant-Id': 'X-Project-Id',
|
||||
'X-Tenant-Name': 'X-Project-Name',
|
||||
'X-Tenant': 'X-Project-Name',
|
||||
}
|
||||
|
||||
def _confirmed(cls, value):
|
||||
return cls._CONFIRMED if value else cls._INVALID
|
||||
|
||||
@property
|
||||
def user_token_valid(self):
|
||||
"""User token is marked as valid.
|
||||
|
||||
:returns: True if the X-Identity-Status header is set to Confirmed.
|
||||
:rtype: bool
|
||||
"""
|
||||
return self.headers[self._USER_STATUS_HEADER] == self._CONFIRMED
|
||||
|
||||
@user_token_valid.setter
|
||||
def user_token_valid(self, value):
|
||||
self.headers[self._USER_STATUS_HEADER] = self._confirmed(value)
|
||||
|
||||
@property
|
||||
def service_token_valid(self):
|
||||
"""Service token is marked as valid.
|
||||
|
||||
:returns: True if the X-Service-Identity-Status header
|
||||
is set to Confirmed.
|
||||
:rtype: bool
|
||||
"""
|
||||
return self.headers[self._SERVICE_STATUS_HEADER] == self._CONFIRMED
|
||||
|
||||
@service_token_valid.setter
|
||||
def service_token_valid(self, value):
|
||||
self.headers[self._SERVICE_STATUS_HEADER] = self._confirmed(value)
|
||||
|
||||
def _set_auth_headers(self, auth_ref, prefix):
|
||||
names = ','.join(auth_ref.role_names)
|
||||
self.headers[self._ROLES_TEMPLATE % prefix] = names
|
||||
|
||||
for header_tmplt, attr in six.iteritems(self._HEADER_TEMPLATE):
|
||||
self.headers[header_tmplt % prefix] = getattr(auth_ref, attr)
|
||||
|
||||
def set_user_headers(self, auth_ref, include_service_catalog):
|
||||
"""Convert token object into headers.
|
||||
|
||||
Build headers that represent authenticated user - see main
|
||||
doc info at start of __init__ file for details of headers to be defined
|
||||
"""
|
||||
self._set_auth_headers(auth_ref, self._USER_HEADER_PREFIX)
|
||||
|
||||
for k, v in six.iteritems(self._DEPRECATED_HEADER_MAP):
|
||||
self.headers[k] = self.headers[v]
|
||||
|
||||
if include_service_catalog and auth_ref.has_service_catalog():
|
||||
catalog = auth_ref.service_catalog.get_data()
|
||||
if auth_ref.version == 'v3':
|
||||
catalog = _v3_to_v2_catalog(catalog)
|
||||
|
||||
c = jsonutils.dumps(catalog)
|
||||
self.headers[self._SERVICE_CATALOG_HEADER] = c
|
||||
|
||||
self.user_token_valid = True
|
||||
|
||||
def set_service_headers(self, auth_ref):
|
||||
"""Convert token object into service headers.
|
||||
|
||||
Build headers that represent authenticated user - see main
|
||||
doc info at start of __init__ file for details of headers to be defined
|
||||
"""
|
||||
self._set_auth_headers(auth_ref, self._SERVICE_HEADER_PREFIX)
|
||||
self.service_token_valid = True
|
||||
|
||||
def _all_auth_headers(self):
|
||||
"""All the authentication headers that can be set on the request"""
|
||||
yield self._SERVICE_CATALOG_HEADER
|
||||
yield self._USER_STATUS_HEADER
|
||||
yield self._SERVICE_STATUS_HEADER
|
||||
|
||||
for header in self._DEPRECATED_HEADER_MAP:
|
||||
yield header
|
||||
|
||||
prefixes = (self._USER_HEADER_PREFIX, self._SERVICE_HEADER_PREFIX)
|
||||
|
||||
for tmpl, prefix in itertools.product(self._HEADER_TEMPLATE, prefixes):
|
||||
yield tmpl % prefix
|
||||
|
||||
for prefix in prefixes:
|
||||
yield self._ROLES_TEMPLATE % prefix
|
||||
|
||||
def remove_auth_headers(self):
|
||||
"""Remove headers so a user can't fake authentication."""
|
||||
for header in self._all_auth_headers():
|
||||
self.headers.pop(header, None)
|
@ -23,7 +23,6 @@ import time
|
||||
import uuid
|
||||
|
||||
import fixtures
|
||||
from keystoneclient import access
|
||||
from keystoneclient import auth
|
||||
from keystoneclient.common import cms
|
||||
from keystoneclient import exceptions
|
||||
@ -1839,69 +1838,6 @@ class v3AuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest,
|
||||
self.assertEqual(self.middleware._token_cache.get(token), data)
|
||||
|
||||
|
||||
class CatalogConversionTests(BaseAuthTokenMiddlewareTest):
|
||||
|
||||
PUBLIC_URL = 'http://server:5000/v2.0'
|
||||
ADMIN_URL = 'http://admin:35357/v2.0'
|
||||
INTERNAL_URL = 'http://internal:5000/v2.0'
|
||||
|
||||
REGION_ONE = 'RegionOne'
|
||||
REGION_TWO = 'RegionTwo'
|
||||
REGION_THREE = 'RegionThree'
|
||||
|
||||
def test_basic_convert(self):
|
||||
token = fixture.V3Token()
|
||||
s = token.add_service(type='identity')
|
||||
s.add_standard_endpoints(public=self.PUBLIC_URL,
|
||||
admin=self.ADMIN_URL,
|
||||
internal=self.INTERNAL_URL,
|
||||
region=self.REGION_ONE)
|
||||
|
||||
auth_ref = access.AccessInfo.factory(body=token)
|
||||
catalog_data = auth_ref.service_catalog.get_data()
|
||||
catalog = auth_token._v3_to_v2_catalog(catalog_data)
|
||||
|
||||
self.assertEqual(1, len(catalog))
|
||||
service = catalog[0]
|
||||
self.assertEqual(1, len(service['endpoints']))
|
||||
endpoints = service['endpoints'][0]
|
||||
|
||||
self.assertEqual('identity', service['type'])
|
||||
self.assertEqual(4, len(endpoints))
|
||||
self.assertEqual(self.PUBLIC_URL, endpoints['publicURL'])
|
||||
self.assertEqual(self.ADMIN_URL, endpoints['adminURL'])
|
||||
self.assertEqual(self.INTERNAL_URL, endpoints['internalURL'])
|
||||
self.assertEqual(self.REGION_ONE, endpoints['region'])
|
||||
|
||||
def test_multi_region(self):
|
||||
token = fixture.V3Token()
|
||||
s = token.add_service(type='identity')
|
||||
|
||||
s.add_endpoint('internal', self.INTERNAL_URL, region=self.REGION_ONE)
|
||||
s.add_endpoint('public', self.PUBLIC_URL, region=self.REGION_TWO)
|
||||
s.add_endpoint('admin', self.ADMIN_URL, region=self.REGION_THREE)
|
||||
|
||||
auth_ref = access.AccessInfo.factory(body=token)
|
||||
catalog_data = auth_ref.service_catalog.get_data()
|
||||
catalog = auth_token._v3_to_v2_catalog(catalog_data)
|
||||
|
||||
self.assertEqual(1, len(catalog))
|
||||
service = catalog[0]
|
||||
|
||||
# the 3 regions will come through as 3 separate endpoints
|
||||
expected = [{'internalURL': self.INTERNAL_URL,
|
||||
'region': self.REGION_ONE},
|
||||
{'publicURL': self.PUBLIC_URL,
|
||||
'region': self.REGION_TWO},
|
||||
{'adminURL': self.ADMIN_URL,
|
||||
'region': self.REGION_THREE}]
|
||||
|
||||
self.assertEqual('identity', service['type'])
|
||||
self.assertEqual(3, len(service['endpoints']))
|
||||
for e in expected:
|
||||
self.assertIn(e, expected)
|
||||
|
||||
|
||||
class DelayedAuthTests(BaseAuthTokenMiddlewareTest):
|
||||
|
||||
def test_header_in_401(self):
|
||||
|
218
keystonemiddleware/tests/unit/auth_token/test_request.py
Normal file
218
keystonemiddleware/tests/unit/auth_token/test_request.py
Normal file
@ -0,0 +1,218 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import itertools
|
||||
import uuid
|
||||
|
||||
from keystoneclient import access
|
||||
from keystoneclient import fixture
|
||||
|
||||
from keystonemiddleware.auth_token import _request
|
||||
from keystonemiddleware.tests.unit import utils
|
||||
|
||||
|
||||
class RequestObjectTests(utils.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(RequestObjectTests, self).setUp()
|
||||
self.request = _request._AuthTokenRequest.blank('/')
|
||||
|
||||
def test_setting_user_token_valid(self):
|
||||
self.assertNotIn('X-Identity-Status', self.request.headers)
|
||||
|
||||
self.request.user_token_valid = True
|
||||
self.assertEqual('Confirmed',
|
||||
self.request.headers['X-Identity-Status'])
|
||||
self.assertTrue(self.request.user_token_valid)
|
||||
|
||||
self.request.user_token_valid = False
|
||||
self.assertEqual('Invalid',
|
||||
self.request.headers['X-Identity-Status'])
|
||||
self.assertFalse(self.request.user_token_valid)
|
||||
|
||||
def test_setting_service_token_valid(self):
|
||||
self.assertNotIn('X-Service-Identity-Status', self.request.headers)
|
||||
|
||||
self.request.service_token_valid = True
|
||||
self.assertEqual('Confirmed',
|
||||
self.request.headers['X-Service-Identity-Status'])
|
||||
self.assertTrue(self.request.service_token_valid)
|
||||
|
||||
self.request.service_token_valid = False
|
||||
self.assertEqual('Invalid',
|
||||
self.request.headers['X-Service-Identity-Status'])
|
||||
self.assertFalse(self.request.service_token_valid)
|
||||
|
||||
def test_removing_headers(self):
|
||||
GOOD = ('X-Auth-Token',
|
||||
'unknownstring',
|
||||
uuid.uuid4().hex)
|
||||
|
||||
BAD = ('X-Domain-Id',
|
||||
'X-Domain-Name',
|
||||
'X-Project-Id',
|
||||
'X-Project-Name',
|
||||
'X-Project-Domain-Id',
|
||||
'X-Project-Domain-Name',
|
||||
'X-User-Id',
|
||||
'X-User-Name',
|
||||
'X-User-Domain-Id',
|
||||
'X-User-Domain-Name',
|
||||
'X-Roles',
|
||||
'X-Identity-Status',
|
||||
|
||||
'X-Service-Domain-Id',
|
||||
'X-Service-Domain-Name',
|
||||
'X-Service-Project-Id',
|
||||
'X-Service-Project-Name',
|
||||
'X-Service-Project-Domain-Id',
|
||||
'X-Service-Project-Domain-Name',
|
||||
'X-Service-User-Id',
|
||||
'X-Service-User-Name',
|
||||
'X-Service-User-Domain-Id',
|
||||
'X-Service-User-Domain-Name',
|
||||
'X-Service-Roles',
|
||||
'X-Service-Identity-Status',
|
||||
|
||||
'X-Service-Catalog',
|
||||
|
||||
'X-Role',
|
||||
'X-User',
|
||||
'X-Tenant-Id',
|
||||
'X-Tenant-Name',
|
||||
'X-Tenant',
|
||||
)
|
||||
|
||||
header_vals = {}
|
||||
|
||||
for header in itertools.chain(GOOD, BAD):
|
||||
v = uuid.uuid4().hex
|
||||
header_vals[header] = v
|
||||
self.request.headers[header] = v
|
||||
|
||||
self.request.remove_auth_headers()
|
||||
|
||||
for header in BAD:
|
||||
self.assertNotIn(header, self.request.headers)
|
||||
|
||||
for header in GOOD:
|
||||
self.assertEqual(header_vals[header], self.request.headers[header])
|
||||
|
||||
def _test_v3_headers(self, token, prefix):
|
||||
self.assertEqual(token.domain_id,
|
||||
self.request.headers['X%s-Domain-Id' % prefix])
|
||||
self.assertEqual(token.domain_name,
|
||||
self.request.headers['X%s-Domain-Name' % prefix])
|
||||
self.assertEqual(token.project_id,
|
||||
self.request.headers['X%s-Project-Id' % prefix])
|
||||
self.assertEqual(token.project_name,
|
||||
self.request.headers['X%s-Project-Name' % prefix])
|
||||
self.assertEqual(
|
||||
token.project_domain_id,
|
||||
self.request.headers['X%s-Project-Domain-Id' % prefix])
|
||||
self.assertEqual(
|
||||
token.project_domain_name,
|
||||
self.request.headers['X%s-Project-Domain-Name' % prefix])
|
||||
|
||||
self.assertEqual(token.user_id,
|
||||
self.request.headers['X%s-User-Id' % prefix])
|
||||
self.assertEqual(token.user_name,
|
||||
self.request.headers['X%s-User-Name' % prefix])
|
||||
self.assertEqual(
|
||||
token.user_domain_id,
|
||||
self.request.headers['X%s-User-Domain-Id' % prefix])
|
||||
self.assertEqual(
|
||||
token.user_domain_name,
|
||||
self.request.headers['X%s-User-Domain-Name' % prefix])
|
||||
|
||||
def test_project_scoped_user_headers(self):
|
||||
token = fixture.V3Token()
|
||||
token.set_project_scope()
|
||||
token_id = uuid.uuid4().hex
|
||||
|
||||
auth_ref = access.AccessInfo.factory(token_id=token_id, body=token)
|
||||
self.request.set_user_headers(auth_ref, include_service_catalog=True)
|
||||
|
||||
self._test_v3_headers(token, '')
|
||||
|
||||
def test_project_scoped_service_headers(self):
|
||||
token = fixture.V3Token()
|
||||
token.set_project_scope()
|
||||
token_id = uuid.uuid4().hex
|
||||
|
||||
auth_ref = access.AccessInfo.factory(token_id=token_id, body=token)
|
||||
self.request.set_service_headers(auth_ref)
|
||||
|
||||
self._test_v3_headers(token, '-Service')
|
||||
|
||||
|
||||
class CatalogConversionTests(utils.TestCase):
|
||||
|
||||
PUBLIC_URL = 'http://server:5000/v2.0'
|
||||
ADMIN_URL = 'http://admin:35357/v2.0'
|
||||
INTERNAL_URL = 'http://internal:5000/v2.0'
|
||||
|
||||
REGION_ONE = 'RegionOne'
|
||||
REGION_TWO = 'RegionTwo'
|
||||
REGION_THREE = 'RegionThree'
|
||||
|
||||
def test_basic_convert(self):
|
||||
token = fixture.V3Token()
|
||||
s = token.add_service(type='identity')
|
||||
s.add_standard_endpoints(public=self.PUBLIC_URL,
|
||||
admin=self.ADMIN_URL,
|
||||
internal=self.INTERNAL_URL,
|
||||
region=self.REGION_ONE)
|
||||
|
||||
auth_ref = access.AccessInfo.factory(body=token)
|
||||
catalog_data = auth_ref.service_catalog.get_data()
|
||||
catalog = _request._v3_to_v2_catalog(catalog_data)
|
||||
|
||||
self.assertEqual(1, len(catalog))
|
||||
service = catalog[0]
|
||||
self.assertEqual(1, len(service['endpoints']))
|
||||
endpoints = service['endpoints'][0]
|
||||
|
||||
self.assertEqual('identity', service['type'])
|
||||
self.assertEqual(4, len(endpoints))
|
||||
self.assertEqual(self.PUBLIC_URL, endpoints['publicURL'])
|
||||
self.assertEqual(self.ADMIN_URL, endpoints['adminURL'])
|
||||
self.assertEqual(self.INTERNAL_URL, endpoints['internalURL'])
|
||||
self.assertEqual(self.REGION_ONE, endpoints['region'])
|
||||
|
||||
def test_multi_region(self):
|
||||
token = fixture.V3Token()
|
||||
s = token.add_service(type='identity')
|
||||
|
||||
s.add_endpoint('internal', self.INTERNAL_URL, region=self.REGION_ONE)
|
||||
s.add_endpoint('public', self.PUBLIC_URL, region=self.REGION_TWO)
|
||||
s.add_endpoint('admin', self.ADMIN_URL, region=self.REGION_THREE)
|
||||
|
||||
auth_ref = access.AccessInfo.factory(body=token)
|
||||
catalog_data = auth_ref.service_catalog.get_data()
|
||||
catalog = _request._v3_to_v2_catalog(catalog_data)
|
||||
|
||||
self.assertEqual(1, len(catalog))
|
||||
service = catalog[0]
|
||||
|
||||
# the 3 regions will come through as 3 separate endpoints
|
||||
expected = [{'internalURL': self.INTERNAL_URL,
|
||||
'region': self.REGION_ONE},
|
||||
{'publicURL': self.PUBLIC_URL,
|
||||
'region': self.REGION_TWO},
|
||||
{'adminURL': self.ADMIN_URL,
|
||||
'region': self.REGION_THREE}]
|
||||
|
||||
self.assertEqual('identity', service['type'])
|
||||
self.assertEqual(3, len(service['endpoints']))
|
||||
for e in expected:
|
||||
self.assertIn(e, expected)
|
Loading…
x
Reference in New Issue
Block a user