Remove v2.0 auth APIs

This was originally staged to be removed in the T release.
Discussions from the Queens PTG resulted in the ability to remove it
sooner since everything else in v2.0 is gone except the ec2 APIs.

This patch just removes the v2.0 authentication API and the tests
that failed as a result. A subsequent patch will go through and start
removing all the plumbing, fixtures, and testing infrastructure that
is no longer needed.

bp removed-as-of-queens

Change-Id: I4c3e35f3565b4b60ae4d00cc2490bd04aba1a800
This commit is contained in:
Lance Bragstad 2017-09-15 13:33:18 +00:00
parent 139aa015d2
commit 8e85cb1a4d
9 changed files with 48 additions and 1999 deletions

File diff suppressed because it is too large Load Diff

View File

@ -27,26 +27,14 @@ from keystone.tests import unit
from keystone.tests.unit import default_fixtures
from keystone.tests.unit import ksfixtures
from keystone.tests.unit.ksfixtures import database
from keystone.tests.unit import rest
from keystone.tests.unit import test_v3 as rest
CRED_TYPE_EC2 = controllers.CRED_TYPE_EC2
class V2CredentialEc2TestCase(rest.RestfulTestCase):
def setUp(self):
super(V2CredentialEc2TestCase, self).setUp()
self.user_id = self.user_foo['id']
self.project_id = self.tenant_bar['id']
self.useFixture(
ksfixtures.KeyRepository(
self.config_fixture,
'credential',
credential_fernet.MAX_ACTIVE_KEYS
)
)
def _get_token_id(self, r):
return r.result['access']['token']['id']
return r.headers.get('X-Subject-Token')
def _get_ec2_cred(self):
uri = self._get_ec2_cred_uri()

View File

@ -14,7 +14,6 @@
import uuid
import six
from six.moves import http_client
from keystone.common import extension as keystone_extension
@ -22,7 +21,6 @@ import keystone.conf
from keystone.tests import unit
from keystone.tests.unit import ksfixtures
from keystone.tests.unit import rest
from keystone.tests.unit.schema import v2
CONF = keystone.conf.CONF
@ -116,37 +114,6 @@ class CoreApiTests(object):
self.assertValidExtensionResponse(
r, keystone_extension.ADMIN_EXTENSIONS)
def test_authenticate(self):
r = self.public_request(
method='POST',
path='/v2.0/tokens',
body={
'auth': {
'passwordCredentials': {
'username': self.user_foo['name'],
'password': self.user_foo['password'],
},
'tenantId': self.tenant_bar['id'],
},
},
expected_status=http_client.OK)
self.assertValidAuthenticationResponse(r, require_service_catalog=True)
def test_authenticate_unscoped(self):
r = self.public_request(
method='POST',
path='/v2.0/tokens',
body={
'auth': {
'passwordCredentials': {
'username': self.user_foo['name'],
'password': self.user_foo['password'],
},
},
},
expected_status=http_client.OK)
self.assertValidAuthenticationResponse(r)
def test_error_response(self):
"""Trigger assertValidErrorResponse by convention."""
self.public_request(path='/v2.0/tenants',
@ -197,38 +164,6 @@ class CoreApiTests(object):
"""
raise NotImplementedError()
def test_authenticating_a_user_with_no_password(self):
token = self.get_scoped_token()
username = uuid.uuid4().hex
# create the user
self.admin_request(
method='POST',
path='/v3/users',
body={
'user': {
'name': username,
'enabled': True,
},
},
token=token)
# fail to authenticate
r = self.public_request(
method='POST',
path='/v2.0/tokens',
body={
'auth': {
'passwordCredentials': {
'username': username,
'password': 'password',
},
},
},
expected_status=http_client.UNAUTHORIZED)
self.assertValidErrorResponse(r)
def test_www_authenticate_header(self):
r = self.public_request(
path='/v2.0/tenants',
@ -454,136 +389,3 @@ class V2TestCaseFernet(V2TestCase, RestfulTestCase, CoreApiTests):
CONF.fernet_tokens.max_active_keys
)
)
class TestFernetTokenProviderV2(RestfulTestCase):
def setUp(self):
super(TestFernetTokenProviderV2, self).setUp()
# Add catalog data
self.region = unit.new_region_ref()
self.region_id = self.region['id']
self.catalog_api.create_region(self.region)
self.service = unit.new_service_ref()
self.service_id = self.service['id']
self.catalog_api.create_service(self.service_id, self.service)
self.endpoint = unit.new_endpoint_ref(service_id=self.service_id,
interface='public',
region_id=self.region_id)
self.endpoint_id = self.endpoint['id']
self.catalog_api.create_endpoint(self.endpoint_id, self.endpoint)
def assertValidUnscopedTokenResponse(self, r):
v2.unscoped_validator.validate(r.json['access'])
def assertValidScopedTokenResponse(self, r):
v2.scoped_validator.validate(r.json['access'])
# Used by RestfulTestCase
def _get_token_id(self, r):
return r.result['access']['token']['id']
def new_project_ref(self):
return {'id': uuid.uuid4().hex,
'name': uuid.uuid4().hex,
'description': uuid.uuid4().hex,
'domain_id': 'default',
'enabled': True}
def config_overrides(self):
super(TestFernetTokenProviderV2, self).config_overrides()
self.config_fixture.config(group='token', provider='fernet')
self.useFixture(
ksfixtures.KeyRepository(
self.config_fixture,
'fernet_tokens',
CONF.fernet_tokens.max_active_keys
)
)
def test_authenticate_unscoped_token(self):
unscoped_token = self.get_unscoped_token()
# Fernet token must be of length 255 per usability requirements
self.assertLess(len(unscoped_token), 255)
def test_authenticate_scoped_token(self):
project_ref = self.new_project_ref()
self.resource_api.create_project(project_ref['id'], project_ref)
self.assignment_api.add_role_to_user_and_project(
self.user_foo['id'], project_ref['id'], self.role_service['id'])
token = self.get_scoped_token(tenant_id=project_ref['id'])
# Fernet token must be of length 255 per usability requirements
self.assertLess(len(token), 255)
def test_token_authentication_and_validation(self):
"""Test token authentication for Fernet token provider.
Verify that token authentication returns validate response code and
valid token belongs to project.
"""
project_ref = self.new_project_ref()
self.resource_api.create_project(project_ref['id'], project_ref)
unscoped_token = self.get_unscoped_token()
self.assignment_api.add_role_to_user_and_project(self.user_foo['id'],
project_ref['id'],
self.role_admin['id'])
token_id = unscoped_token
if six.PY2:
token_id = token_id.encode('ascii')
resp = self.public_request(
method='POST',
path='/v2.0/tokens',
body={
'auth': {
'tenantName': project_ref['name'],
'token': {
'id': token_id,
}
}
},
expected_status=http_client.OK)
self.assertValidScopedTokenResponse(resp)
def test_rescoped_tokens_maintain_original_expiration(self):
project_ref = self.new_project_ref()
self.resource_api.create_project(project_ref['id'], project_ref)
self.assignment_api.add_role_to_user_and_project(self.user_foo['id'],
project_ref['id'],
self.role_admin['id'])
resp = self.public_request(
method='POST',
path='/v2.0/tokens',
body={
'auth': {
'tenantName': project_ref['name'],
'passwordCredentials': {
'username': self.user_foo['name'],
'password': self.user_foo['password']
}
}
},
# NOTE(lbragstad): This test may need to be refactored if Keystone
# decides to disallow rescoping using a scoped token.
expected_status=http_client.OK)
original_token = resp.result['access']['token']['id']
original_expiration = resp.result['access']['token']['expires']
resp = self.public_request(
method='POST',
path='/v2.0/tokens',
body={
'auth': {
'tenantName': project_ref['name'],
'token': {
'id': original_token,
}
}
},
expected_status=http_client.OK)
rescoped_token = resp.result['access']['token']['id']
rescoped_expiration = resp.result['access']['token']['expires']
self.assertNotEqual(original_token, rescoped_token)
self.assertEqual(original_expiration, rescoped_expiration)
self.assertValidScopedTokenResponse(resp)

View File

@ -388,14 +388,6 @@ class TokenAPITests(object):
expected_status=expected_status
)
def _validate_token_v2(self, token, expected_status=http_client.OK):
return self.admin_request(
path='/v2.0/tokens/%s' % token,
headers={'X-Auth-Token': self.get_scoped_token()},
method='GET',
expected_status=expected_status
)
def _revoke_token(self, token, expected_status=http_client.NO_CONTENT):
return self.delete(
'/auth/tokens',
@ -1445,110 +1437,6 @@ class TokenAPITests(object):
def test_default_fixture_scope_token(self):
self.assertIsNotNone(self.get_scoped_token())
def test_v2_v3_unscoped_token_intermix(self):
r = self.admin_request(
method='POST',
path='/v2.0/tokens',
body={
'auth': {
'passwordCredentials': {
'userId': self.default_domain_user['id'],
'password': self.default_domain_user['password']
}
}
})
v2_token_data = r.result
v2_token = v2_token_data['access']['token']['id']
r = self.get('/auth/tokens', headers={'X-Subject-Token': v2_token})
self.assertValidUnscopedTokenResponse(r)
v3_token_data = r.result
self.assertEqual(v2_token_data['access']['user']['id'],
v3_token_data['token']['user']['id'])
self.assertTimestampEqual(v2_token_data['access']['token']['expires'],
v3_token_data['token']['expires_at'])
def test_v2_v3_token_intermix(self):
r = self.admin_request(
path='/v2.0/tokens',
method='POST',
body={
'auth': {
'passwordCredentials': {
'userId': self.default_domain_user['id'],
'password': self.default_domain_user['password']
},
'tenantId': self.default_domain_project['id']
}
})
v2_token_data = r.result
v2_token = v2_token_data['access']['token']['id']
r = self.get('/auth/tokens', headers={'X-Subject-Token': v2_token})
self.assertValidProjectScopedTokenResponse(r)
v3_token_data = r.result
self.assertEqual(v2_token_data['access']['user']['id'],
v3_token_data['token']['user']['id'])
self.assertTimestampEqual(v2_token_data['access']['token']['expires'],
v3_token_data['token']['expires_at'])
self.assertEqual(v2_token_data['access']['user']['roles'][0]['name'],
v3_token_data['token']['roles'][0]['name'])
v2_issued_at = timeutils.parse_isotime(
v2_token_data['access']['token']['issued_at'])
v3_issued_at = timeutils.parse_isotime(
v3_token_data['token']['issued_at'])
self.assertEqual(v2_issued_at, v3_issued_at)
def test_create_v3_project_token_from_v2_project_token(self):
r = self.admin_request(
path='/v2.0/tokens',
method='POST',
body={
'auth': {
'passwordCredentials': {
'userId': self.default_domain_user['id'],
'password': self.default_domain_user['password']
},
'tenantId': self.default_domain_project['id']
}
})
v2_token_data = r.result
v2_token = v2_token_data['access']['token']['id']
auth_data = self.build_authentication_request(
token=v2_token,
project_id=self.default_domain_project['id'])
r = self.v3_create_token(auth_data)
self.assertValidScopedTokenResponse(r)
def test_v2_token_deleted_on_v3(self):
# Create a v2 token.
body = {
'auth': {
'passwordCredentials': {
'userId': self.default_domain_user['id'],
'password': self.default_domain_user['password']
},
'tenantId': self.default_domain_project['id']
}
}
r = self.admin_request(
path='/v2.0/tokens', method='POST', body=body)
v2_token = r.result['access']['token']['id']
# Delete the v2 token using v3.
self.delete(
'/auth/tokens', headers={'X-Subject-Token': v2_token})
# Attempting to use the deleted token on v2 should fail.
self._validate_token_v2(
v2_token, expected_status=http_client.NOT_FOUND
)
def test_rescoping_token(self):
expires = self.v3_token_data['token']['expires_at']
@ -2239,38 +2127,6 @@ class TokenAPITests(object):
# the bind information should be carried over from the original token
self.assertEqual(remote_user, token['bind']['kerberos'])
def test_v2_v3_bind_token_intermix(self):
self.config_fixture.config(group='token', bind='kerberos')
# we need our own user registered to the default domain because of
# the way external auth works.
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
body = {'auth': {}}
resp = self.admin_request(path='/v2.0/tokens',
method='POST',
body=body)
v2_token_data = resp.result
bind = v2_token_data['access']['token']['bind']
self.assertEqual(self.default_domain_user['name'], bind['kerberos'])
v2_token_id = v2_token_data['access']['token']['id']
# NOTE(gyee): self.get() will try to obtain an auth token if one
# is not provided. When REMOTE_USER is present in the request
# environment, the external user auth plugin is used in conjunction
# with the password auth for the admin user. Therefore, we need to
# cleanup the REMOTE_USER information from the previous call.
del self.admin_app.extra_environ['REMOTE_USER']
headers = {'X-Subject-Token': v2_token_id}
resp = self.get('/auth/tokens', headers=headers)
token_data = resp.result
self.assertDictEqual(v2_token_data['access']['token']['bind'],
token_data['token']['bind'])
def test_fetch_expired_allow_expired(self):
self.config_fixture.config(group='token',
expiration=10,
@ -2405,48 +2261,6 @@ class AllowRescopeScopedTokenDisabledTests(test_v3.RestfulTestCase):
project_id=self.project_id),
expected_status=http_client.FORBIDDEN)
def _v2_token(self):
body = {
'auth': {
"tenantId": self.default_domain_project['id'],
'passwordCredentials': {
'userId': self.default_domain_user['id'],
'password': self.default_domain_user['password']
}
}}
resp = self.admin_request(path='/v2.0/tokens',
method='POST',
body=body)
v2_token_data = resp.result
return v2_token_data
def _v2_token_from_token(self, token):
body = {
'auth': {
"tenantId": self.project['id'],
"token": token
}}
self.admin_request(path='/v2.0/tokens',
method='POST',
body=body,
expected_status=http_client.FORBIDDEN)
def test_rescoping_v2_to_v3_disabled(self):
token = self._v2_token()
self.v3_create_token(
self.build_authentication_request(
token=token['access']['token']['id'],
project_id=self.project_id),
expected_status=http_client.FORBIDDEN)
def test_rescoping_v3_to_v2_disabled(self):
token = {'id': self.get_scoped_token()}
self._v2_token_from_token(token)
def test_rescoping_v2_to_v2_disabled(self):
token = self._v2_token()
self._v2_token_from_token(token['access']['token'])
def test_rescoped_domain_token_disabled(self):
self.domainA = unit.new_domain_ref()
@ -2546,21 +2360,6 @@ class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
self.v3_create_token(auth_data,
expected_status=http_client.NOT_IMPLEMENTED)
def test_v2_v3_bind_token_intermix(self):
self.config_fixture.config(group='token', bind='kerberos')
# we need our own user registered to the default domain because of
# the way external auth works.
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
body = {'auth': {}}
# Bind not current supported by Fernet, see bug 1433311.
self.admin_request(path='/v2.0/tokens',
method='POST',
body=body,
expected_status=http_client.NOT_IMPLEMENTED)
def test_auth_with_bind_token(self):
self.config_fixture.config(group='token', bind=['kerberos'])
@ -3323,37 +3122,6 @@ class TestTokenRevokeById(test_v3.RestfulTestCase):
# Make sure that we get a 404 Not Found when heading that role.
self.head(role_path, expected_status=http_client.NOT_FOUND)
def get_v2_token(self, token=None, project_id=None):
body = {'auth': {}, }
if token:
body['auth']['token'] = {
'id': token
}
else:
body['auth']['passwordCredentials'] = {
'username': self.default_domain_user['name'],
'password': self.default_domain_user['password'],
}
if project_id:
body['auth']['tenantId'] = project_id
r = self.admin_request(method='POST', path='/v2.0/tokens', body=body)
return r.json_body['access']['token']['id']
def test_revoke_v2_token_no_check(self):
# Test that a V2 token can be revoked without validating it first.
token = self.get_v2_token()
self.delete('/auth/tokens',
headers={'X-Subject-Token': token})
self.head('/auth/tokens',
headers={'X-Subject-Token': token},
expected_status=http_client.NOT_FOUND)
def test_revoke_token_from_token(self):
# Test that a scoped token can be requested from an unscoped token,
# the scoped token can be revoked, and the unscoped token remains
@ -3409,31 +3177,6 @@ class TestTokenRevokeById(test_v3.RestfulTestCase):
headers={'X-Subject-Token': unscoped_token},
expected_status=http_client.OK)
def test_revoke_token_from_token_v2(self):
# Test that a scoped token can be requested from an unscoped token,
# the scoped token can be revoked, and the unscoped token remains
# valid.
unscoped_token = self.get_v2_token()
# Get a project-scoped token from the unscoped token
project_scoped_token = self.get_v2_token(
token=unscoped_token, project_id=self.default_domain_project['id'])
# revoke the project-scoped token.
self.delete('/auth/tokens',
headers={'X-Subject-Token': project_scoped_token})
# The project-scoped token is invalidated.
self.head('/auth/tokens',
headers={'X-Subject-Token': project_scoped_token},
expected_status=http_client.NOT_FOUND)
# The unscoped token should still be valid.
self.head('/auth/tokens',
headers={'X-Subject-Token': unscoped_token},
expected_status=http_client.OK)
class TestTokenRevokeByAssignment(TestTokenRevokeById):
@ -3556,20 +3299,6 @@ class TestTokenRevokeApi(TestTokenRevokeById):
self.assertValidRevokedTokenResponse(events_response,
audit_id=response['audit_ids'][0])
def test_revoke_v2_token(self):
token = self.get_v2_token()
headers = {'X-Subject-Token': token}
response = self.get('/auth/tokens',
headers=headers).json_body['token']
self.delete('/auth/tokens', headers=headers)
self.head('/auth/tokens', headers=headers,
expected_status=http_client.NOT_FOUND)
events_response = self.get('/OS-REVOKE/events').json_body
self.assertValidRevokedTokenResponse(
events_response,
audit_id=response['audit_ids'][0])
def test_get_revoke_by_id_false_returns_gone(self):
self.get('/auth/tokens/OS-PKI/revoked',
expected_status=http_client.GONE)

View File

@ -239,18 +239,6 @@ class ResourceTestCase(test_v3.RestfulTestCase,
user2['id'])
# First check a user in that domain can authenticate..
body = {
'auth': {
'passwordCredentials': {
'userId': user2['id'],
'password': user2['password']
},
'tenantId': project2['id']
}
}
self.admin_request(
path='/v2.0/tokens', method='POST', body=body)
auth_data = self.build_authentication_request(
user_id=user2['id'],
password=user2['password'],
@ -264,21 +252,6 @@ class ResourceTestCase(test_v3.RestfulTestCase,
body={'domain': {'enabled': False}})
self.assertValidDomainResponse(r, domain2)
# Make sure the user can no longer authenticate, via
# either API
body = {
'auth': {
'passwordCredentials': {
'userId': user2['id'],
'password': user2['password']
},
'tenantId': project2['id']
}
}
self.admin_request(
path='/v2.0/tokens', method='POST', body=body,
expected_status=http_client.UNAUTHORIZED)
# Try looking up in v3 by name and id
auth_data = self.build_authentication_request(
user_id=user2['id'],

View File

@ -45,6 +45,35 @@ class TestTrustOperations(test_v3.RestfulTestCase):
self.post('/OS-TRUST/trusts', body={'trust': {}},
expected_status=http_client.FORBIDDEN)
def test_create_trust_with_invalid_expiration_fails(self):
# create a new trust
ref = unit.new_trust_ref(
trustor_user_id=self.user_id,
trustee_user_id=self.trustee_user_id,
project_id=self.project_id,
role_ids=[self.role_id])
ref['expires_at'] = 'bad'
self.post(
'/OS-TRUST/trusts',
body={'trust': ref},
expected_status=http_client.BAD_REQUEST
)
ref['expires_at'] = ''
self.post(
'/OS-TRUST/trusts',
body={'trust': ref},
expected_status=http_client.BAD_REQUEST
)
ref['expires_at'] = 'Z'
self.post(
'/OS-TRUST/trusts',
body={'trust': ref},
expected_status=http_client.BAD_REQUEST
)
def test_trust_crud(self):
# create a new trust
ref = unit.new_trust_ref(
@ -151,6 +180,22 @@ class TestTrustOperations(test_v3.RestfulTestCase):
expected_status=http_client.FORBIDDEN
)
def test_create_trust_with_expiration_in_the_past_fails(self):
ref = unit.new_trust_ref(
trustor_user_id=self.user_id,
trustee_user_id=self.trustee_user_id,
project_id=self.project_id,
impersonation=False,
expires='2010-06-04T08:44:31.999999Z',
role_ids=[self.role_id]
)
self.post(
'/OS-TRUST/trusts',
body={'trust': ref},
expected_status=http_client.BAD_REQUEST
)
def test_delete_trust(self):
# create a trust
ref = unit.new_trust_ref(

View File

@ -12,10 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import sys
import six
from keystone.common import controller
from keystone.common import dependency
from keystone.common import utils
@ -62,84 +58,6 @@ class ExternalAuthNotApplicable(Exception):
pass
@dependency.requires('catalog_api', 'identity_api', 'resource_api',
'token_provider_api', 'trust_api')
class Auth(controller.V2Controller):
@controller.v2_auth_deprecated
def authenticate(self, request, auth=None):
"""Authenticate credentials and return a token.
Accept auth as a dict that looks like::
{
"auth":{
"passwordCredentials":{
"username":"test_user",
"password":"mypass"
},
"tenantName":"customer-x"
}
}
In this case, tenant is optional, if not provided the token will be
considered "unscoped" and can later be used to get a scoped token.
Alternatively, this call accepts auth with only a token and tenant
that will return a token that is scoped to that tenant.
"""
method = authentication_method_generator(request, auth)
user_ref, project_id, expiry, bind, audit_id = (
method.authenticate(request, auth)
)
# Ensure the entities provided in the authentication information are
# valid and not disabled.
try:
self.identity_api.assert_user_enabled(
user_id=user_ref['id'], user=user_ref)
if project_id:
try:
self.resource_api.get_project(project_id)
except exception.ProjectNotFound:
msg = _(
'Project ID not found: %(p_id)s'
) % {'p_id': project_id}
raise exception.Unauthorized(msg)
self.resource_api.assert_project_enabled(project_id)
except AssertionError as e:
six.reraise(exception.Unauthorized, exception.Unauthorized(e),
sys.exc_info()[2])
# NOTE(morganfainberg): Make sure the data is in correct form since it
# might be consumed external to Keystone and this is a v2.0 controller.
# The user_ref is encoded into the auth_token_data which is returned as
# part of the token data. The token provider doesn't care about the
# format.
user_ref = self.v3_to_v2_user(user_ref)
auth_context = {}
if bind:
auth_context['bind'] = bind
trust_ref = None
if CONF.trust.enabled and 'trust_id' in auth:
trust_ref = self.trust_api.get_trust(auth['trust_id'])
(token_id, token_data) = self.token_provider_api.issue_token(
user_ref['id'], ['password'], expires_at=expiry,
project_id=project_id, trust=trust_ref, parent_audit_id=audit_id,
auth_context=auth_context)
v2_helper = V2TokenDataHelper()
token_data = v2_helper.v3_to_v2_token(token_data, token_id)
# NOTE(wanghong): We consume a trust use only when we are using trusts
# and have successfully issued a token.
if CONF.trust.enabled and 'trust_id' in auth:
self.trust_api.consume_use(auth['trust_id'])
return token_data
@dependency.requires('resource_api', 'identity_api')
class BaseAuthenticationMethod(object):
"""Common utilities/dependencies for all authentication method classes."""

View File

@ -1,24 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# 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.
from keystone.common import wsgi
from keystone.token import controllers
class Router(wsgi.ComposableRouter):
def add_routes(self, mapper):
token_controller = controllers.Auth()
mapper.connect('/tokens',
controller=token_controller,
action='authenticate',
conditions=dict(method=['POST']))

View File

@ -33,7 +33,6 @@ from keystone.policy import routers as policy_routers
from keystone.resource import routers as resource_routers
from keystone.revoke import routers as revoke_routers
from keystone.token import _simple_cert as simple_cert_ext
from keystone.token import routers as token_routers
from keystone.trust import routers as trust_routers
from keystone.v2_crud import admin_crud
from keystone.version import controllers
@ -83,7 +82,6 @@ def public_app_factory(global_conf, **local_conf):
controllers.register_version('v2.0')
return wsgi.ComposingRouter(routes.Mapper(),
[assignment_routers.Public(),
token_routers.Router(),
routers.VersionV2('public'),
routers.Extension(False)])
@ -93,8 +91,7 @@ def public_app_factory(global_conf, **local_conf):
def admin_app_factory(global_conf, **local_conf):
controllers.register_version('v2.0')
return wsgi.ComposingRouter(routes.Mapper(),
[token_routers.Router(),
admin_crud.Router(),
[admin_crud.Router(),
routers.VersionV2('admin'),
routers.Extension()])