Merge "module refactoring"

This commit is contained in:
Jenkins 2012-12-18 14:43:26 +00:00 committed by Gerrit Code Review
commit 7db702cab1
15 changed files with 503 additions and 507 deletions

View File

@ -16,3 +16,4 @@
from keystone.catalog.core import *
from keystone.catalog import controllers
from keystone.catalog import routers

View File

@ -20,18 +20,9 @@ import uuid
from keystone.catalog import core
from keystone.common import controller
from keystone.common import wsgi
from keystone import identity
from keystone import policy
from keystone import token
class Service(wsgi.Application):
def __init__(self):
self.catalog_api = core.Manager()
self.identity_api = identity.Manager()
self.policy_api = policy.Manager()
self.token_api = token.Manager()
super(Service, self).__init__()
class Service(controller.V2Controller):
def get_services(self, context):
self.assert_admin(context)
@ -57,14 +48,7 @@ class Service(wsgi.Application):
return {'OS-KSADM:service': new_service_ref}
class Endpoint(wsgi.Application):
def __init__(self):
self.catalog_api = core.Manager()
self.identity_api = identity.Manager()
self.policy_api = policy.Manager()
self.token_api = token.Manager()
super(Endpoint, self).__init__()
class Endpoint(controller.V2Controller):
def get_endpoints(self, context):
self.assert_admin(context)
endpoint_list = self.catalog_api.list_endpoints(context)

View File

@ -0,0 +1,25 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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.catalog import controllers
from keystone.common import router
from keystone.common import wsgi
def append_v3_routers(mapper, routers, apis):
routers.append(router.Router(controllers.ServiceV3(**apis),
'services', 'service'))
routers.append(router.Router(controllers.EndpointV3(**apis),
'endpoints', 'endpoint'))

57
keystone/common/router.py Normal file
View File

@ -0,0 +1,57 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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 import config
class Router(wsgi.ComposableRouter):
def __init__(self, controller, collection_key, key):
self.controller = controller
self.key = key
self.collection_key = collection_key
def add_routes(self, mapper):
collection_path = '/%(collection_key)s' % {
'collection_key': self.collection_key}
entity_path = '/%(collection_key)s/{%(key)s_id}' % {
'collection_key': self.collection_key,
'key': self.key}
mapper.connect(
collection_path,
controller=self.controller,
action='create_%s' % self.key,
conditions=dict(method=['POST']))
mapper.connect(
collection_path,
controller=self.controller,
action='list_%s' % self.collection_key,
conditions=dict(method=['GET']))
mapper.connect(
entity_path,
controller=self.controller,
action='get_%s' % self.key,
conditions=dict(method=['GET']))
mapper.connect(
entity_path,
controller=self.controller,
action='update_%s' % self.key,
conditions=dict(method=['PATCH']))
mapper.connect(
entity_path,
controller=self.controller,
action='delete_%s' % self.key,
conditions=dict(method=['DELETE']))

View File

@ -13,10 +13,11 @@
# 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 import catalog
from keystone.common import wsgi
from keystone import identity
from keystone import policy
from keystone import token
class CrudExtension(wsgi.ExtensionRouter):
@ -27,11 +28,16 @@ class CrudExtension(wsgi.ExtensionRouter):
"""
def add_routes(self, mapper):
tenant_controller = identity.controllers.Tenant()
user_controller = identity.controllers.User()
role_controller = identity.controllers.Role()
service_controller = catalog.controllers.Service()
endpoint_controller = catalog.controllers.Endpoint()
apis = dict(catalog_api=catalog.Manager(),
identity_api=identity.Manager(),
policy_api=policy.Manager(),
token_api=token.Manager())
tenant_controller = identity.controllers.Tenant(**apis)
user_controller = identity.controllers.User(**apis)
role_controller = identity.controllers.Role(**apis)
service_controller = catalog.controllers.Service(**apis)
endpoint_controller = catalog.controllers.Endpoint(**apis)
# Tenant Operations
mapper.connect(

View File

@ -18,21 +18,19 @@ import copy
import uuid
from keystone import exception
from keystone.common import controller
from keystone.common import logging
from keystone.common import wsgi
from keystone import catalog
from keystone import identity
from keystone import policy
from keystone import token
LOG = logging.getLogger(__name__)
class UserController(wsgi.Application):
def __init__(self):
self.identity_api = identity.Manager()
self.token_api = token.Manager()
self.user_controller = identity.controllers.User()
class UserController(identity.controllers.User):
def set_user_password(self, context, user_id, user):
token_id = context.get('token_id')
original_password = user.get('original_password')
@ -62,9 +60,9 @@ class UserController(wsgi.Application):
admin_context = copy.copy(context)
admin_context['is_admin'] = True
self.user_controller.set_user_password(admin_context,
user_id,
update_dict)
super(UserController, self).set_user_password(admin_context,
user_id,
update_dict)
token_id = uuid.uuid4().hex
new_token_ref = copy.copy(token_ref)
@ -83,7 +81,12 @@ class CrudExtension(wsgi.ExtensionRouter):
"""
def add_routes(self, mapper):
user_controller = UserController()
apis = dict(catalog_api=catalog.Manager(),
identity_api=identity.Manager(),
policy_api=policy.Manager(),
token_api=token.Manager())
user_controller = UserController(**apis)
mapper.connect('/OS-KSCRUD/users/{user_id}',
controller=user_controller,

144
keystone/controllers.py Normal file
View File

@ -0,0 +1,144 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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 import catalog
from keystone import exception
class Extensions(wsgi.Application):
"""Base extensions controller to be extended by public and admin API's."""
def __init__(self, extensions=None):
super(Extensions, self).__init__()
self.extensions = extensions or {}
def get_extensions_info(self, context):
return {'extensions': {'values': self.extensions.values()}}
def get_extension_info(self, context, extension_alias):
try:
return {'extension': self.extensions[extension_alias]}
except KeyError:
raise exception.NotFound(target=extension_alias)
class AdminExtensions(Extensions):
def __init__(self, *args, **kwargs):
super(AdminExtensions, self).__init__(*args, **kwargs)
# TODO(dolph): Extensions should obviously provide this information
# themselves, but hardcoding it here allows us to match
# the API spec in the short term with minimal complexity.
self.extensions['OS-KSADM'] = {
'name': 'Openstack Keystone Admin',
'namespace': 'http://docs.openstack.org/identity/api/ext/'
'OS-KSADM/v1.0',
'alias': 'OS-KSADM',
'updated': '2011-08-19T13:25:27-06:00',
'description': 'Openstack extensions to Keystone v2.0 API '
'enabling Admin Operations.',
'links': [
{
'rel': 'describedby',
# TODO(dolph): link needs to be revised after
# bug 928059 merges
'type': 'text/html',
'href': 'https://github.com/openstack/identity-api',
}
]
}
class PublicExtensions(Extensions):
pass
class Version(wsgi.Application):
def __init__(self, version_type):
self.catalog_api = catalog.Manager()
self.url_key = '%sURL' % version_type
super(Version, self).__init__()
def _get_identity_url(self, context):
catalog_ref = self.catalog_api.get_catalog(context=context,
user_id=None,
tenant_id=None)
for region, region_ref in catalog_ref.iteritems():
for service, service_ref in region_ref.iteritems():
if service == 'identity':
return service_ref[self.url_key]
raise exception.NotImplemented()
def _get_versions_list(self, context):
"""The list of versions is dependent on the context."""
identity_url = self._get_identity_url(context)
if not identity_url.endswith('/'):
identity_url = identity_url + '/'
versions = {}
versions['v2.0'] = {
'id': 'v2.0',
'status': 'beta',
'updated': '2011-11-19T00:00:00Z',
'links': [
{
'rel': 'self',
'href': identity_url,
}, {
'rel': 'describedby',
'type': 'text/html',
'href': 'http://docs.openstack.org/api/openstack-'
'identity-service/2.0/content/'
}, {
'rel': 'describedby',
'type': 'application/pdf',
'href': 'http://docs.openstack.org/api/openstack-'
'identity-service/2.0/identity-dev-guide-'
'2.0.pdf'
}
],
'media-types': [
{
'base': 'application/json',
'type': 'application/vnd.openstack.identity-v2.0'
'+json'
}, {
'base': 'application/xml',
'type': 'application/vnd.openstack.identity-v2.0'
'+xml'
}
]
}
return versions
def get_versions(self, context):
versions = self._get_versions_list(context)
return wsgi.render_response(status=(300, 'Multiple Choices'), body={
'versions': {
'values': versions.values()
}
})
def get_version(self, context):
versions = self._get_versions_list(context)
return wsgi.render_response(body={
'version': versions['v2.0']
})

View File

@ -32,13 +32,7 @@ from keystone import token
LOG = logging.getLogger(__name__)
class Tenant(wsgi.Application):
def __init__(self):
self.identity_api = core.Manager()
self.policy_api = policy.Manager()
self.token_api = token.Manager()
super(Tenant, self).__init__()
class Tenant(controller.V2Controller):
def get_all_tenants(self, context, **kw):
"""Gets a list of all tenants for an admin user."""
if 'name' in context['query_string']:
@ -157,13 +151,7 @@ class Tenant(wsgi.Application):
return o
class User(wsgi.Application):
def __init__(self):
self.identity_api = core.Manager()
self.policy_api = policy.Manager()
self.token_api = token.Manager()
super(User, self).__init__()
class User(controller.V2Controller):
def get_user(self, context, user_id):
self.assert_admin(context)
return {'user': self.identity_api.get_user(context, user_id)}
@ -240,13 +228,7 @@ class User(wsgi.Application):
return self.update_user(context, user_id, user)
class Role(wsgi.Application):
def __init__(self):
self.identity_api = core.Manager()
self.token_api = token.Manager()
self.policy_api = policy.Manager()
super(Role, self).__init__()
class Role(controller.V2Controller):
# COMPAT(essex-3)
def get_user_roles(self, context, user_id, tenant_id=None):
"""Get the roles for a user and tenant pair.

View File

@ -13,16 +13,19 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""WSGI Routers for the Identity service."""
from keystone.common import wsgi
from keystone.identity import controllers
from keystone.common import router
class Public(wsgi.ComposableRouter):
def __init__(self, apis):
self.apis = apis
super(Public, self).__init__()
def add_routes(self, mapper):
tenant_controller = controllers.Tenant()
tenant_controller = controllers.Tenant(**self.apis)
mapper.connect('/tenants',
controller=tenant_controller,
action='get_tenants_for_token',
@ -30,9 +33,13 @@ class Public(wsgi.ComposableRouter):
class Admin(wsgi.ComposableRouter):
def __init__(self, apis):
self.apis = apis
super(Admin, self).__init__()
def add_routes(self, mapper):
# Tenant Operations
tenant_controller = controllers.Tenant()
tenant_controller = controllers.Tenant(**self.apis)
mapper.connect('/tenants',
controller=tenant_controller,
action='get_all_tenants',
@ -43,14 +50,14 @@ class Admin(wsgi.ComposableRouter):
conditions=dict(method=['GET']))
# User Operations
user_controller = controllers.User()
user_controller = controllers.User(**self.apis)
mapper.connect('/users/{user_id}',
controller=user_controller,
action='get_user',
conditions=dict(method=['GET']))
# Role Operations
roles_controller = controllers.Role()
roles_controller = controllers.Role(**self.apis)
mapper.connect('/tenants/{tenant_id}/users/{user_id}/roles',
controller=roles_controller,
action='get_user_roles',
@ -59,3 +66,57 @@ class Admin(wsgi.ComposableRouter):
controller=roles_controller,
action='get_user_roles',
conditions=dict(method=['GET']))
def append_v3_routers(mapper, routers, apis):
routers.append(
router.Router(controllers.DomainV3(**apis),
'domains', 'domain'))
project_controller = controllers.ProjectV3(**apis)
routers.append(
router.Router(project_controller,
'projects', 'project'))
mapper.connect('/users/{user_id}/projects',
controller=project_controller,
action='list_user_projects',
conditions=dict(method=['GET']))
routers.append(
router.Router(controllers.UserV3(**apis),
'users', 'user'))
routers.append(
router.Router(controllers.CredentialV3(**apis),
'credentials', 'credential'))
role_controller = controllers.RoleV3(**apis)
routers.append(router.Router(role_controller, 'roles', 'role'))
mapper.connect('/projects/{project_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='create_grant',
conditions=dict(method=['PUT']))
mapper.connect('/projects/{project_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='check_grant',
conditions=dict(method=['HEAD']))
mapper.connect('/projects/{project_id}/users/{user_id}/roles',
controller=role_controller,
action='list_grants',
conditions=dict(method=['GET']))
mapper.connect('/projects/{project_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='revoke_grant',
conditions=dict(method=['DELETE']))
mapper.connect('/domains/{domain_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='create_grant',
conditions=dict(method=['PUT']))
mapper.connect('/domains/{domain_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='check_grant',
conditions=dict(method=['HEAD']))
mapper.connect('/domains/{domain_id}/users/{user_id}/roles',
controller=role_controller,
action='list_grants',
conditions=dict(method=['GET']))
mapper.connect('/domains/{domain_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='revoke_grant',
conditions=dict(method=['DELETE']))

View File

@ -16,3 +16,4 @@
from keystone.policy.core import *
from keystone.policy import controllers
from keystone.policy import routers

View File

@ -0,0 +1,22 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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.policy import controllers
from keystone.common import router
def append_v3_routers(mapper, routers, apis):
policy_controller = controllers.PolicyV3(**apis)
routers.append(router.Router(policy_controller, 'policies', 'policy'))

68
keystone/routers.py Normal file
View File

@ -0,0 +1,68 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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.
"""
The only types of routers in this file should be ComposingRouters.
The routers for the submodules should be in the module specific router files
for example, the Composable Router for identity belongs in
keystone/identity/routers.py
"""
from keystone.common import wsgi
from keystone import catalog
from keystone import controllers
from keystone import exception
class Extension(wsgi.ComposableRouter):
def __init__(self, is_admin=True):
if is_admin:
self.controller = controllers.AdminExtensions()
else:
self.controller = controllers.PublicExtensions()
def add_routes(self, mapper):
extensions_controller = self.controller
mapper.connect('/extensions',
controller=extensions_controller,
action='get_extensions_info',
conditions=dict(method=['GET']))
mapper.connect('/extensions/{extension_alias}',
controller=extensions_controller,
action='get_extension_info',
conditions=dict(method=['GET']))
class Version(wsgi.ComposableRouter):
def __init__(self, description):
self.description = description
def add_routes(self, mapper):
version_controller = controllers.Version(self.description)
mapper.connect('/',
controller=version_controller,
action='get_version')
class Versions(wsgi.ComposableRouter):
def __init__(self, description):
self.description = description
def add_routes(self, mapper):
version_controller = controllers.Version(self.description)
mapper.connect('/',
controller=version_controller,
action='get_versions')

View File

@ -22,484 +22,64 @@ from keystone.common import wsgi
from keystone import exception
from keystone import identity
from keystone import policy
from keystone import routers
from keystone import token
LOG = logging.getLogger(__name__)
class V3Router(wsgi.ComposingRouter):
def crud_routes(self, mapper, controller, collection_key, key):
collection_path = '/%(collection_key)s' % {
'collection_key': collection_key}
entity_path = '/%(collection_key)s/{%(key)s_id}' % {
'collection_key': collection_key,
'key': key}
mapper.connect(
collection_path,
controller=controller,
action='create_%s' % key,
conditions=dict(method=['POST']))
mapper.connect(
collection_path,
controller=controller,
action='list_%s' % collection_key,
conditions=dict(method=['GET']))
mapper.connect(
entity_path,
controller=controller,
action='get_%s' % key,
conditions=dict(method=['GET']))
mapper.connect(
entity_path,
controller=controller,
action='update_%s' % key,
conditions=dict(method=['PATCH']))
mapper.connect(
entity_path,
controller=controller,
action='delete_%s' % key,
conditions=dict(method=['DELETE']))
def __init__(self):
mapper = routes.Mapper()
apis = dict(
catalog_api=catalog.Manager(),
identity_api=identity.Manager(),
policy_api=policy.Manager(),
token_api=token.Manager())
# Catalog
self.crud_routes(
mapper,
catalog.controllers.ServiceV3(**apis),
'services',
'service')
self.crud_routes(
mapper,
catalog.controllers.EndpointV3(**apis),
'endpoints',
'endpoint')
# Identity
self.crud_routes(
mapper,
identity.controllers.DomainV3(**apis),
'domains',
'domain')
project_controller = identity.controllers.ProjectV3(**apis)
self.crud_routes(
mapper,
project_controller,
'projects',
'project')
mapper.connect(
'/users/{user_id}/projects',
controller=project_controller,
action='list_user_projects',
conditions=dict(method=['GET']))
self.crud_routes(
mapper,
identity.controllers.UserV3(**apis),
'users',
'user')
self.crud_routes(
mapper,
identity.controllers.CredentialV3(**apis),
'credentials',
'credential')
role_controller = identity.controllers.RoleV3(**apis)
self.crud_routes(
mapper,
role_controller,
'roles',
'role')
mapper.connect(
'/projects/{project_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='create_grant',
conditions=dict(method=['PUT']))
mapper.connect(
'/projects/{project_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='check_grant',
conditions=dict(method=['HEAD']))
mapper.connect(
'/projects/{project_id}/users/{user_id}/roles',
controller=role_controller,
action='list_grants',
conditions=dict(method=['GET']))
mapper.connect(
'/projects/{project_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='revoke_grant',
conditions=dict(method=['DELETE']))
mapper.connect(
'/domains/{domain_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='create_grant',
conditions=dict(method=['PUT']))
mapper.connect(
'/domains/{domain_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='check_grant',
conditions=dict(method=['HEAD']))
mapper.connect(
'/domains/{domain_id}/users/{user_id}/roles',
controller=role_controller,
action='list_grants',
conditions=dict(method=['GET']))
mapper.connect(
'/domains/{domain_id}/users/{user_id}/roles/{role_id}',
controller=role_controller,
action='revoke_grant',
conditions=dict(method=['DELETE']))
# Policy
policy_controller = policy.controllers.PolicyV3(**apis)
self.crud_routes(
mapper,
policy_controller,
'policies',
'policy')
# Token
"""
# v2.0 LEGACY
mapper.connect('/tokens/{token_id}',
controller=auth_controller,
action='validate_token',
conditions=dict(method=['GET']))
mapper.connect('/tokens/{token_id}',
controller=auth_controller,
action='validate_token_head',
conditions=dict(method=['HEAD']))
mapper.connect('/tokens/{token_id}',
controller=auth_controller,
action='delete_token',
conditions=dict(method=['DELETE']))
mapper.connect('/tokens/{token_id}/endpoints',
controller=auth_controller,
action='endpoints',
conditions=dict(method=['GET']))
"""
super(V3Router, self).__init__(mapper, [])
class AdminRouter(wsgi.ComposingRouter):
def __init__(self):
mapper = routes.Mapper()
apis = dict(
catalog_api=catalog.Manager(),
identity_api=identity.Manager(),
policy_api=policy.Manager(),
token_api=token.Manager())
version_controller = VersionController('admin')
mapper.connect('/',
controller=version_controller,
action='get_version')
# Token Operations
auth_controller = token.controllers.Auth(**apis)
mapper.connect('/tokens',
controller=auth_controller,
action='authenticate',
conditions=dict(method=['POST']))
mapper.connect('/tokens/revoked',
controller=auth_controller,
action='revocation_list',
conditions=dict(method=['GET']))
mapper.connect('/tokens/{token_id}',
controller=auth_controller,
action='validate_token',
conditions=dict(method=['GET']))
mapper.connect('/tokens/{token_id}',
controller=auth_controller,
action='validate_token_head',
conditions=dict(method=['HEAD']))
mapper.connect('/tokens/{token_id}',
controller=auth_controller,
action='delete_token',
conditions=dict(method=['DELETE']))
mapper.connect('/tokens/{token_id}/endpoints',
controller=auth_controller,
action='endpoints',
conditions=dict(method=['GET']))
# Certificates used to verify auth tokens
mapper.connect('/certificates/ca',
controller=auth_controller,
action='ca_cert',
conditions=dict(method=['GET']))
mapper.connect('/certificates/signing',
controller=auth_controller,
action='signing_cert',
conditions=dict(method=['GET']))
# Miscellaneous Operations
extensions_controller = AdminExtensionsController()
mapper.connect('/extensions',
controller=extensions_controller,
action='get_extensions_info',
conditions=dict(method=['GET']))
mapper.connect('/extensions/{extension_alias}',
controller=extensions_controller,
action='get_extension_info',
conditions=dict(method=['GET']))
identity_router = identity.routers.Admin()
routers = [identity_router]
super(AdminRouter, self).__init__(mapper, routers)
class PublicRouter(wsgi.ComposingRouter):
def __init__(self):
mapper = routes.Mapper()
apis = dict(
catalog_api=catalog.Manager(),
identity_api=identity.Manager(),
policy_api=policy.Manager(),
token_api=token.Manager())
version_controller = VersionController('public')
mapper.connect('/',
controller=version_controller,
action='get_version')
# Token Operations
auth_controller = token.controllers.Auth(**apis)
mapper.connect('/tokens',
controller=auth_controller,
action='authenticate',
conditions=dict(method=['POST']))
mapper.connect('/certificates/ca',
controller=auth_controller,
action='ca_cert',
conditions=dict(method=['GET']))
mapper.connect('/certificates/signing',
controller=auth_controller,
action='signing_cert',
conditions=dict(method=['GET']))
# Miscellaneous
extensions_controller = PublicExtensionsController()
mapper.connect('/extensions',
controller=extensions_controller,
action='get_extensions_info',
conditions=dict(method=['GET']))
mapper.connect('/extensions/{extension_alias}',
controller=extensions_controller,
action='get_extension_info',
conditions=dict(method=['GET']))
identity_router = identity.routers.Public()
routers = [identity_router]
super(PublicRouter, self).__init__(mapper, routers)
class PublicVersionRouter(wsgi.ComposingRouter):
def __init__(self):
mapper = routes.Mapper()
version_controller = VersionController('public')
mapper.connect('/',
controller=version_controller,
action='get_versions')
routers = []
super(PublicVersionRouter, self).__init__(mapper, routers)
class AdminVersionRouter(wsgi.ComposingRouter):
def __init__(self):
mapper = routes.Mapper()
version_controller = VersionController('admin')
mapper.connect('/',
controller=version_controller,
action='get_versions')
routers = []
super(AdminVersionRouter, self).__init__(mapper, routers)
class VersionController(wsgi.Application):
def __init__(self, version_type):
self.catalog_api = catalog.Manager()
self.url_key = '%sURL' % version_type
super(VersionController, self).__init__()
def _get_identity_url(self, context):
catalog_ref = self.catalog_api.get_catalog(context=context,
user_id=None,
tenant_id=None)
for region, region_ref in catalog_ref.iteritems():
for service, service_ref in region_ref.iteritems():
if service == 'identity':
return service_ref[self.url_key]
raise exception.NotImplemented()
def _get_versions_list(self, context):
"""The list of versions is dependent on the context."""
identity_url = self._get_identity_url(context)
if not identity_url.endswith('/'):
identity_url = identity_url + '/'
versions = {}
versions['v2.0'] = {
'id': 'v2.0',
'status': 'beta',
'updated': '2011-11-19T00:00:00Z',
'links': [
{
'rel': 'self',
'href': identity_url,
}, {
'rel': 'describedby',
'type': 'text/html',
'href': 'http://docs.openstack.org/api/openstack-'
'identity-service/2.0/content/'
}, {
'rel': 'describedby',
'type': 'application/pdf',
'href': 'http://docs.openstack.org/api/openstack-'
'identity-service/2.0/identity-dev-guide-'
'2.0.pdf'
}
],
'media-types': [
{
'base': 'application/json',
'type': 'application/vnd.openstack.identity-v2.0'
'+json'
}, {
'base': 'application/xml',
'type': 'application/vnd.openstack.identity-v2.0'
'+xml'
}
]
}
return versions
def get_versions(self, context):
versions = self._get_versions_list(context)
return wsgi.render_response(status=(300, 'Multiple Choices'), body={
'versions': {
'values': versions.values()
}
})
def get_version(self, context):
versions = self._get_versions_list(context)
return wsgi.render_response(body={
'version': versions['v2.0']
})
class NoopController(wsgi.Application):
def __init__(self):
super(NoopController, self).__init__()
def noop(self, context):
return {}
class ExtensionsController(wsgi.Application):
"""Base extensions controller to be extended by public and admin API's."""
def __init__(self, extensions=None):
super(ExtensionsController, self).__init__()
self.extensions = extensions or {}
def get_extensions_info(self, context):
return {'extensions': {'values': self.extensions.values()}}
def get_extension_info(self, context, extension_alias):
try:
return {'extension': self.extensions[extension_alias]}
except KeyError:
raise exception.NotFound(target=extension_alias)
class PublicExtensionsController(ExtensionsController):
pass
class AdminExtensionsController(ExtensionsController):
def __init__(self, *args, **kwargs):
super(AdminExtensionsController, self).__init__(*args, **kwargs)
# TODO(dolph): Extensions should obviously provide this information
# themselves, but hardcoding it here allows us to match
# the API spec in the short term with minimal complexity.
self.extensions['OS-KSADM'] = {
'name': 'Openstack Keystone Admin',
'namespace': 'http://docs.openstack.org/identity/api/ext/'
'OS-KSADM/v1.0',
'alias': 'OS-KSADM',
'updated': '2011-08-19T13:25:27-06:00',
'description': 'Openstack extensions to Keystone v2.0 API '
'enabling Admin Operations.',
'links': [
{
'rel': 'describedby',
# TODO(dolph): link needs to be revised after
# bug 928059 merges
'type': 'text/html',
'href': 'https://github.com/openstack/identity-api',
}
]
}
def _apis():
return dict(catalog_api=catalog.Manager(),
identity_api=identity.Manager(),
policy_api=policy.Manager(),
token_api=token.Manager())
@logging.fail_gracefully
def public_app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return PublicRouter()
return wsgi.ComposingRouter(routes.Mapper(),
[identity.routers.Public(_apis()),
token.routers.Router(_apis()),
routers.Version('public'),
routers.Extension(False)])
@logging.fail_gracefully
def admin_app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return AdminRouter()
return wsgi.ComposingRouter(routes.Mapper(),
[identity.routers.Admin(_apis()),
token.routers.Router(_apis()),
routers.Version('admin'),
routers.Extension()])
@logging.fail_gracefully
def public_version_app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return PublicVersionRouter()
return wsgi.ComposingRouter(routes.Mapper(),
[routers.Versions('public')])
@logging.fail_gracefully
def admin_version_app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return AdminVersionRouter()
return wsgi.ComposingRouter(routes.Mapper(),
[routers.Versions('admin')])
@logging.fail_gracefully
def v3_app_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return V3Router()
mapper = routes.Mapper()
v3routers = []
for module in [catalog, identity, policy]:
module.routers.append_v3_routers(mapper, v3routers, _apis())
#TODO put token routes here
return wsgi.ComposingRouter(mapper, v3routers)

View File

@ -16,3 +16,4 @@
from keystone.token.core import *
from keystone.token import controllers
from keystone.token import routers

61
keystone/token/routers.py Normal file
View File

@ -0,0 +1,61 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC
#
# 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 __init__(self, apis):
self.apis = apis
super(Router, self).__init__()
def add_routes(self, mapper):
token_controller = controllers.Auth(**self.apis)
mapper.connect('/tokens',
controller=token_controller,
action='authenticate',
conditions=dict(method=['POST']))
mapper.connect('/tokens/revoked',
controller=token_controller,
action='revocation_list',
conditions=dict(method=['GET']))
mapper.connect('/tokens/{token_id}',
controller=token_controller,
action='validate_token',
conditions=dict(method=['GET']))
mapper.connect('/tokens/{token_id}',
controller=token_controller,
action='validate_token_head',
conditions=dict(method=['HEAD']))
mapper.connect('/tokens/{token_id}',
controller=token_controller,
action='delete_token',
conditions=dict(method=['DELETE']))
mapper.connect('/tokens/{token_id}/endpoints',
controller=token_controller,
action='endpoints',
conditions=dict(method=['GET']))
# Certificates used to verify auth tokens
mapper.connect('/certificates/ca',
controller=token_controller,
action='ca_cert',
conditions=dict(method=['GET']))
mapper.connect('/certificates/signing',
controller=token_controller,
action='signing_cert',
conditions=dict(method=['GET']))