diff --git a/etc/keystone-paste.ini b/etc/keystone-paste.ini index 125dcbc1a4..6e2051432d 100644 --- a/etc/keystone-paste.ini +++ b/etc/keystone-paste.ini @@ -18,12 +18,6 @@ use = egg:keystone#admin_token_auth [filter:json_body] use = egg:keystone#json_body -[filter:user_crud_extension] -use = egg:keystone#user_crud_extension - -[filter:crud_extension] -use = egg:keystone#crud_extension - [filter:ec2_extension] use = egg:keystone#ec2_extension @@ -51,12 +45,12 @@ use = egg:keystone#admin_service [pipeline:public_api] # The last item in this pipeline must be public_service or an equivalent # application. It cannot be a filter. -pipeline = sizelimit url_normalize request_id build_auth_context token_auth admin_token_auth json_body ec2_extension user_crud_extension public_service +pipeline = sizelimit url_normalize request_id build_auth_context token_auth admin_token_auth json_body ec2_extension public_service [pipeline:admin_api] # The last item in this pipeline must be admin_service or an equivalent # application. It cannot be a filter. -pipeline = sizelimit url_normalize request_id build_auth_context token_auth admin_token_auth json_body ec2_extension s3_extension crud_extension admin_service +pipeline = sizelimit url_normalize request_id build_auth_context token_auth admin_token_auth json_body ec2_extension s3_extension admin_service [pipeline:api_v3] # The last item in this pipeline must be service_v3 or an equivalent diff --git a/keystone/contrib/admin_crud/core.py b/keystone/contrib/admin_crud/core.py index de07815de9..739cc0ff10 100644 --- a/keystone/contrib/admin_crud/core.py +++ b/keystone/contrib/admin_crud/core.py @@ -12,229 +12,21 @@ # License for the specific language governing permissions and limitations # under the License. -from keystone import assignment -from keystone import catalog -from keystone.common import extension +from oslo_log import log +from oslo_log import versionutils + from keystone.common import wsgi -from keystone import identity -from keystone import resource +from keystone.i18n import _ -extension.register_admin_extension( - 'OS-KSADM', { - 'name': 'OpenStack Keystone Admin', - 'namespace': 'http://docs.openstack.org/identity/api/ext/' - 'OS-KSADM/v1.0', - 'alias': 'OS-KSADM', - 'updated': '2013-07-11T17:14:00-00:00', - 'description': 'OpenStack extensions to Keystone v2.0 API ' - 'enabling Administrative Operations.', - 'links': [ - { - 'rel': 'describedby', - 'type': 'text/html', - 'href': 'http://developer.openstack.org/' - 'api-ref-identity-v2-ext.html', - } - ]}) +LOG = log.getLogger(__name__) -class CrudExtension(wsgi.ExtensionRouter): - """Previously known as the OS-KSADM extension. - - Provides a bunch of CRUD operations for internal data types. - - """ - - def add_routes(self, mapper): - tenant_controller = resource.controllers.Tenant() - assignment_tenant_controller = ( - assignment.controllers.TenantAssignment()) - user_controller = identity.controllers.User() - role_controller = assignment.controllers.Role() - assignment_role_controller = assignment.controllers.RoleAssignmentV2() - service_controller = catalog.controllers.Service() - endpoint_controller = catalog.controllers.Endpoint() - - # Tenant Operations - mapper.connect( - '/tenants', - controller=tenant_controller, - action='create_project', - conditions=dict(method=['POST'])) - mapper.connect( - '/tenants/{tenant_id}', - controller=tenant_controller, - action='update_project', - conditions=dict(method=['PUT', 'POST'])) - mapper.connect( - '/tenants/{tenant_id}', - controller=tenant_controller, - action='delete_project', - conditions=dict(method=['DELETE'])) - mapper.connect( - '/tenants/{tenant_id}/users', - controller=assignment_tenant_controller, - action='get_project_users', - conditions=dict(method=['GET'])) - - # User Operations - mapper.connect( - '/users', - controller=user_controller, - action='get_users', - conditions=dict(method=['GET'])) - mapper.connect( - '/users', - controller=user_controller, - action='create_user', - conditions=dict(method=['POST'])) - # NOTE(termie): not in diablo - mapper.connect( - '/users/{user_id}', - controller=user_controller, - action='update_user', - conditions=dict(method=['PUT'])) - mapper.connect( - '/users/{user_id}', - controller=user_controller, - action='delete_user', - conditions=dict(method=['DELETE'])) - - # COMPAT(diablo): the copy with no OS-KSADM is from diablo - mapper.connect( - '/users/{user_id}/password', - controller=user_controller, - action='set_user_password', - conditions=dict(method=['PUT'])) - mapper.connect( - '/users/{user_id}/OS-KSADM/password', - controller=user_controller, - action='set_user_password', - conditions=dict(method=['PUT'])) - - # COMPAT(diablo): the copy with no OS-KSADM is from diablo - mapper.connect( - '/users/{user_id}/tenant', - controller=user_controller, - action='update_user', - conditions=dict(method=['PUT'])) - mapper.connect( - '/users/{user_id}/OS-KSADM/tenant', - controller=user_controller, - action='update_user', - conditions=dict(method=['PUT'])) - - # COMPAT(diablo): the copy with no OS-KSADM is from diablo - mapper.connect( - '/users/{user_id}/enabled', - controller=user_controller, - action='set_user_enabled', - conditions=dict(method=['PUT'])) - mapper.connect( - '/users/{user_id}/OS-KSADM/enabled', - controller=user_controller, - action='set_user_enabled', - conditions=dict(method=['PUT'])) - - # User Roles - mapper.connect( - '/users/{user_id}/roles/OS-KSADM/{role_id}', - controller=assignment_role_controller, - action='add_role_to_user', - conditions=dict(method=['PUT'])) - mapper.connect( - '/users/{user_id}/roles/OS-KSADM/{role_id}', - controller=assignment_role_controller, - action='remove_role_from_user', - conditions=dict(method=['DELETE'])) - - # COMPAT(diablo): User Roles - mapper.connect( - '/users/{user_id}/roleRefs', - controller=assignment_role_controller, - action='get_role_refs', - conditions=dict(method=['GET'])) - mapper.connect( - '/users/{user_id}/roleRefs', - controller=assignment_role_controller, - action='create_role_ref', - conditions=dict(method=['POST'])) - mapper.connect( - '/users/{user_id}/roleRefs/{role_ref_id}', - controller=assignment_role_controller, - action='delete_role_ref', - conditions=dict(method=['DELETE'])) - - # User-Tenant Roles - mapper.connect( - '/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}', - controller=assignment_role_controller, - action='add_role_to_user', - conditions=dict(method=['PUT'])) - mapper.connect( - '/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}', - controller=assignment_role_controller, - action='remove_role_from_user', - conditions=dict(method=['DELETE'])) - - # Service Operations - mapper.connect( - '/OS-KSADM/services', - controller=service_controller, - action='get_services', - conditions=dict(method=['GET'])) - mapper.connect( - '/OS-KSADM/services', - controller=service_controller, - action='create_service', - conditions=dict(method=['POST'])) - mapper.connect( - '/OS-KSADM/services/{service_id}', - controller=service_controller, - action='delete_service', - conditions=dict(method=['DELETE'])) - mapper.connect( - '/OS-KSADM/services/{service_id}', - controller=service_controller, - action='get_service', - conditions=dict(method=['GET'])) - - # Endpoint Templates - mapper.connect( - '/endpoints', - controller=endpoint_controller, - action='get_endpoints', - conditions=dict(method=['GET'])) - mapper.connect( - '/endpoints', - controller=endpoint_controller, - action='create_endpoint', - conditions=dict(method=['POST'])) - mapper.connect( - '/endpoints/{endpoint_id}', - controller=endpoint_controller, - action='delete_endpoint', - conditions=dict(method=['DELETE'])) - - # Role Operations - mapper.connect( - '/OS-KSADM/roles', - controller=role_controller, - action='create_role', - conditions=dict(method=['POST'])) - mapper.connect( - '/OS-KSADM/roles', - controller=role_controller, - action='get_roles', - conditions=dict(method=['GET'])) - mapper.connect( - '/OS-KSADM/roles/{role_id}', - controller=role_controller, - action='get_role', - conditions=dict(method=['GET'])) - mapper.connect( - '/OS-KSADM/roles/{role_id}', - controller=role_controller, - action='delete_role', - conditions=dict(method=['DELETE'])) +class CrudExtension(wsgi.Middleware): + def __init__(self, application): + super(CrudExtension, self).__init__(application) + msg = _("Remove admin_crud_extension from the paste pipeline, the " + "admin_crud extension is now always available. Update" + "the [pipeline:admin_api] section in keystone-paste.ini " + "accordingly, as it will be removed in the O release.") + versionutils.report_deprecated_feature(LOG, msg) diff --git a/keystone/contrib/user_crud/core.py b/keystone/contrib/user_crud/core.py index 8011703b66..b37157eaaa 100644 --- a/keystone/contrib/user_crud/core.py +++ b/keystone/contrib/user_crud/core.py @@ -12,123 +12,21 @@ # License for the specific language governing permissions and limitations # under the License. -import copy -import uuid - from oslo_log import log +from oslo_log import versionutils -from keystone.common import dependency -from keystone.common import extension from keystone.common import wsgi -from keystone import exception -from keystone import identity -from keystone.models import token_model +from keystone.i18n import _ LOG = log.getLogger(__name__) -extension.register_public_extension( - 'OS-KSCRUD', { - 'name': 'OpenStack Keystone User CRUD', - 'namespace': 'http://docs.openstack.org/identity/api/ext/' - 'OS-KSCRUD/v1.0', - 'alias': 'OS-KSCRUD', - 'updated': '2013-07-07T12:00:0-00:00', - 'description': 'OpenStack extensions to Keystone v2.0 API ' - 'enabling User Operations.', - 'links': [ - { - 'rel': 'describedby', - 'type': 'text/html', - 'href': 'http://developer.openstack.org/' - 'api-ref-identity-v2-ext.html', - } - ]}) - - -@dependency.requires('catalog_api', 'identity_api', 'resource_api', - 'token_provider_api') -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') - - token_data = self.token_provider_api.validate_token(token_id) - token_ref = token_model.KeystoneToken(token_id=token_id, - token_data=token_data) - - if token_ref.user_id != user_id: - raise exception.Forbidden('Token belongs to another user') - if original_password is None: - raise exception.ValidationError(target='user', - attribute='original password') - - try: - user_ref = self.identity_api.authenticate( - context, - user_id=token_ref.user_id, - password=original_password) - if not user_ref.get('enabled', True): - # NOTE(dolph): why can't you set a disabled user's password? - raise exception.Unauthorized('User is disabled') - except AssertionError: - raise exception.Unauthorized() - - update_dict = {'password': user['password'], 'id': user_id} - - admin_context = copy.copy(context) - admin_context['is_admin'] = True - super(UserController, self).set_user_password(admin_context, - user_id, - update_dict) - - # Issue a new token based upon the original token data. This will - # always be a V2.0 token. - - # TODO(morganfainberg): Add a mechanism to issue a new token directly - # from a token model so that this code can go away. This is likely - # not the norm as most cases do not need to yank apart a token to - # issue a new one. - new_token_ref = {} - metadata_ref = {} - roles_ref = None - - new_token_ref['user'] = user_ref - if token_ref.bind: - new_token_ref['bind'] = token_ref.bind - if token_ref.project_id: - new_token_ref['tenant'] = self.resource_api.get_project( - token_ref.project_id) - if token_ref.role_names: - roles_ref = [dict(name=value) - for value in token_ref.role_names] - if token_ref.role_ids: - metadata_ref['roles'] = token_ref.role_ids - if token_ref.trust_id: - metadata_ref['trust'] = { - 'id': token_ref.trust_id, - 'trustee_user_id': token_ref.trustee_user_id} - new_token_ref['metadata'] = metadata_ref - new_token_ref['id'] = uuid.uuid4().hex - - catalog_ref = self.catalog_api.get_catalog(user_id, - token_ref.project_id) - - new_token_id, new_token_data = self.token_provider_api.issue_v2_token( - token_ref=new_token_ref, roles_ref=roles_ref, - catalog_ref=catalog_ref) - LOG.debug('TOKEN_REF %s', new_token_data) - return new_token_data - - -class CrudExtension(wsgi.ExtensionRouter): - """Provides a subset of CRUD operations for internal data types.""" - - def add_routes(self, mapper): - user_controller = UserController() - - mapper.connect('/OS-KSCRUD/users/{user_id}', - controller=user_controller, - action='set_user_password', - conditions=dict(method=['PATCH'])) +class CrudExtension(wsgi.Middleware): + def __init__(self, application): + super(CrudExtension, self).__init__(application) + msg = _("Remove user_crud_extension from the paste pipeline, the " + "user_crud extension is now always available. Update" + "the [pipeline:public_api] section in keystone-paste.ini " + "accordingly, as it will be removed in the O release.") + versionutils.report_deprecated_feature(LOG, msg) diff --git a/keystone/v2_crud/__init__.py b/keystone/v2_crud/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/keystone/v2_crud/admin_crud.py b/keystone/v2_crud/admin_crud.py new file mode 100644 index 0000000000..86ccfcd8a6 --- /dev/null +++ b/keystone/v2_crud/admin_crud.py @@ -0,0 +1,240 @@ +# 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 import assignment +from keystone import catalog +from keystone.common import extension +from keystone.common import wsgi +from keystone import identity +from keystone import resource + + +extension.register_admin_extension( + 'OS-KSADM', { + 'name': 'OpenStack Keystone Admin', + 'namespace': 'http://docs.openstack.org/identity/api/ext/' + 'OS-KSADM/v1.0', + 'alias': 'OS-KSADM', + 'updated': '2013-07-11T17:14:00-00:00', + 'description': 'OpenStack extensions to Keystone v2.0 API ' + 'enabling Administrative Operations.', + 'links': [ + { + 'rel': 'describedby', + 'type': 'text/html', + 'href': 'http://developer.openstack.org/' + 'api-ref-identity-v2-ext.html', + } + ]}) + + +class Router(wsgi.ComposableRouter): + """Previously known as the OS-KSADM extension. + + Provides a bunch of CRUD operations for internal data types. + + """ + + def add_routes(self, mapper): + tenant_controller = resource.controllers.Tenant() + assignment_tenant_controller = ( + assignment.controllers.TenantAssignment()) + user_controller = identity.controllers.User() + role_controller = assignment.controllers.Role() + assignment_role_controller = assignment.controllers.RoleAssignmentV2() + service_controller = catalog.controllers.Service() + endpoint_controller = catalog.controllers.Endpoint() + + # Tenant Operations + mapper.connect( + '/tenants', + controller=tenant_controller, + action='create_project', + conditions=dict(method=['POST'])) + mapper.connect( + '/tenants/{tenant_id}', + controller=tenant_controller, + action='update_project', + conditions=dict(method=['PUT', 'POST'])) + mapper.connect( + '/tenants/{tenant_id}', + controller=tenant_controller, + action='delete_project', + conditions=dict(method=['DELETE'])) + mapper.connect( + '/tenants/{tenant_id}/users', + controller=assignment_tenant_controller, + action='get_project_users', + conditions=dict(method=['GET'])) + + # User Operations + mapper.connect( + '/users', + controller=user_controller, + action='get_users', + conditions=dict(method=['GET'])) + mapper.connect( + '/users', + controller=user_controller, + action='create_user', + conditions=dict(method=['POST'])) + # NOTE(termie): not in diablo + mapper.connect( + '/users/{user_id}', + controller=user_controller, + action='update_user', + conditions=dict(method=['PUT'])) + mapper.connect( + '/users/{user_id}', + controller=user_controller, + action='delete_user', + conditions=dict(method=['DELETE'])) + + # COMPAT(diablo): the copy with no OS-KSADM is from diablo + mapper.connect( + '/users/{user_id}/password', + controller=user_controller, + action='set_user_password', + conditions=dict(method=['PUT'])) + mapper.connect( + '/users/{user_id}/OS-KSADM/password', + controller=user_controller, + action='set_user_password', + conditions=dict(method=['PUT'])) + + # COMPAT(diablo): the copy with no OS-KSADM is from diablo + mapper.connect( + '/users/{user_id}/tenant', + controller=user_controller, + action='update_user', + conditions=dict(method=['PUT'])) + mapper.connect( + '/users/{user_id}/OS-KSADM/tenant', + controller=user_controller, + action='update_user', + conditions=dict(method=['PUT'])) + + # COMPAT(diablo): the copy with no OS-KSADM is from diablo + mapper.connect( + '/users/{user_id}/enabled', + controller=user_controller, + action='set_user_enabled', + conditions=dict(method=['PUT'])) + mapper.connect( + '/users/{user_id}/OS-KSADM/enabled', + controller=user_controller, + action='set_user_enabled', + conditions=dict(method=['PUT'])) + + # User Roles + mapper.connect( + '/users/{user_id}/roles/OS-KSADM/{role_id}', + controller=assignment_role_controller, + action='add_role_to_user', + conditions=dict(method=['PUT'])) + mapper.connect( + '/users/{user_id}/roles/OS-KSADM/{role_id}', + controller=assignment_role_controller, + action='remove_role_from_user', + conditions=dict(method=['DELETE'])) + + # COMPAT(diablo): User Roles + mapper.connect( + '/users/{user_id}/roleRefs', + controller=assignment_role_controller, + action='get_role_refs', + conditions=dict(method=['GET'])) + mapper.connect( + '/users/{user_id}/roleRefs', + controller=assignment_role_controller, + action='create_role_ref', + conditions=dict(method=['POST'])) + mapper.connect( + '/users/{user_id}/roleRefs/{role_ref_id}', + controller=assignment_role_controller, + action='delete_role_ref', + conditions=dict(method=['DELETE'])) + + # User-Tenant Roles + mapper.connect( + '/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}', + controller=assignment_role_controller, + action='add_role_to_user', + conditions=dict(method=['PUT'])) + mapper.connect( + '/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}', + controller=assignment_role_controller, + action='remove_role_from_user', + conditions=dict(method=['DELETE'])) + + # Service Operations + mapper.connect( + '/OS-KSADM/services', + controller=service_controller, + action='get_services', + conditions=dict(method=['GET'])) + mapper.connect( + '/OS-KSADM/services', + controller=service_controller, + action='create_service', + conditions=dict(method=['POST'])) + mapper.connect( + '/OS-KSADM/services/{service_id}', + controller=service_controller, + action='delete_service', + conditions=dict(method=['DELETE'])) + mapper.connect( + '/OS-KSADM/services/{service_id}', + controller=service_controller, + action='get_service', + conditions=dict(method=['GET'])) + + # Endpoint Templates + mapper.connect( + '/endpoints', + controller=endpoint_controller, + action='get_endpoints', + conditions=dict(method=['GET'])) + mapper.connect( + '/endpoints', + controller=endpoint_controller, + action='create_endpoint', + conditions=dict(method=['POST'])) + mapper.connect( + '/endpoints/{endpoint_id}', + controller=endpoint_controller, + action='delete_endpoint', + conditions=dict(method=['DELETE'])) + + # Role Operations + mapper.connect( + '/OS-KSADM/roles', + controller=role_controller, + action='create_role', + conditions=dict(method=['POST'])) + mapper.connect( + '/OS-KSADM/roles', + controller=role_controller, + action='get_roles', + conditions=dict(method=['GET'])) + mapper.connect( + '/OS-KSADM/roles/{role_id}', + controller=role_controller, + action='get_role', + conditions=dict(method=['GET'])) + mapper.connect( + '/OS-KSADM/roles/{role_id}', + controller=role_controller, + action='delete_role', + conditions=dict(method=['DELETE'])) diff --git a/keystone/v2_crud/user_crud.py b/keystone/v2_crud/user_crud.py new file mode 100644 index 0000000000..9da7f31f3d --- /dev/null +++ b/keystone/v2_crud/user_crud.py @@ -0,0 +1,134 @@ +# Copyright 2012 Red Hat, Inc +# +# 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 copy +import uuid + +from oslo_log import log + +from keystone.common import dependency +from keystone.common import extension +from keystone.common import wsgi +from keystone import exception +from keystone import identity +from keystone.models import token_model + + +LOG = log.getLogger(__name__) + + +extension.register_public_extension( + 'OS-KSCRUD', { + 'name': 'OpenStack Keystone User CRUD', + 'namespace': 'http://docs.openstack.org/identity/api/ext/' + 'OS-KSCRUD/v1.0', + 'alias': 'OS-KSCRUD', + 'updated': '2013-07-07T12:00:0-00:00', + 'description': 'OpenStack extensions to Keystone v2.0 API ' + 'enabling User Operations.', + 'links': [ + { + 'rel': 'describedby', + 'type': 'text/html', + 'href': 'http://developer.openstack.org/' + 'api-ref-identity-v2-ext.html', + } + ]}) + + +@dependency.requires('catalog_api', 'identity_api', 'resource_api', + 'token_provider_api') +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') + + token_data = self.token_provider_api.validate_token(token_id) + token_ref = token_model.KeystoneToken(token_id=token_id, + token_data=token_data) + + if token_ref.user_id != user_id: + raise exception.Forbidden('Token belongs to another user') + if original_password is None: + raise exception.ValidationError(target='user', + attribute='original password') + + try: + user_ref = self.identity_api.authenticate( + context, + user_id=token_ref.user_id, + password=original_password) + if not user_ref.get('enabled', True): + # NOTE(dolph): why can't you set a disabled user's password? + raise exception.Unauthorized('User is disabled') + except AssertionError: + raise exception.Unauthorized() + + update_dict = {'password': user['password'], 'id': user_id} + + admin_context = copy.copy(context) + admin_context['is_admin'] = True + super(UserController, self).set_user_password(admin_context, + user_id, + update_dict) + + # Issue a new token based upon the original token data. This will + # always be a V2.0 token. + + # TODO(morganfainberg): Add a mechanism to issue a new token directly + # from a token model so that this code can go away. This is likely + # not the norm as most cases do not need to yank apart a token to + # issue a new one. + new_token_ref = {} + metadata_ref = {} + roles_ref = None + + new_token_ref['user'] = user_ref + if token_ref.bind: + new_token_ref['bind'] = token_ref.bind + if token_ref.project_id: + new_token_ref['tenant'] = self.resource_api.get_project( + token_ref.project_id) + if token_ref.role_names: + roles_ref = [dict(name=value) + for value in token_ref.role_names] + if token_ref.role_ids: + metadata_ref['roles'] = token_ref.role_ids + if token_ref.trust_id: + metadata_ref['trust'] = { + 'id': token_ref.trust_id, + 'trustee_user_id': token_ref.trustee_user_id} + new_token_ref['metadata'] = metadata_ref + new_token_ref['id'] = uuid.uuid4().hex + + catalog_ref = self.catalog_api.get_catalog(user_id, + token_ref.project_id) + + new_token_id, new_token_data = self.token_provider_api.issue_v2_token( + token_ref=new_token_ref, roles_ref=roles_ref, + catalog_ref=catalog_ref) + LOG.debug('TOKEN_REF %s', new_token_data) + return new_token_data + + +class Router(wsgi.ComposableRouter): + """Provides a subset of CRUD operations for internal data types.""" + + def add_routes(self, mapper): + user_controller = UserController() + + mapper.connect('/OS-KSCRUD/users/{user_id}', + controller=user_controller, + action='set_user_password', + conditions=dict(method=['PATCH'])) diff --git a/keystone/version/service.py b/keystone/version/service.py index 6d873405ec..b0ed3b7655 100644 --- a/keystone/version/service.py +++ b/keystone/version/service.py @@ -36,6 +36,8 @@ 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.v2_crud import user_crud from keystone.version import controllers from keystone.version import routers @@ -85,6 +87,7 @@ def public_app_factory(global_conf, **local_conf): return wsgi.ComposingRouter(routes.Mapper(), [assignment_routers.Public(), token_routers.Router(), + user_crud.Router(), routers.VersionV2('public'), routers.Extension(False)]) @@ -98,6 +101,7 @@ def admin_app_factory(global_conf, **local_conf): assignment_routers.Admin(), token_routers.Router(), resource_routers.Admin(), + admin_crud.Router(), routers.VersionV2('admin'), routers.Extension()]) diff --git a/releasenotes/notes/extensions-to-core-a0d270d216d47276.yaml b/releasenotes/notes/extensions-to-core-a0d270d216d47276.yaml index 80af9ae948..8bfd4c1bed 100644 --- a/releasenotes/notes/extensions-to-core-a0d270d216d47276.yaml +++ b/releasenotes/notes/extensions-to-core-a0d270d216d47276.yaml @@ -8,6 +8,13 @@ upgrade: and ``[filter:revoke_extension]``. See the sample `keystone-paste.ini `_ file for guidance. + - > + The ``keystone-paste.ini`` file must be updated to remove extension filters, + and their use in ``[pipeline:public_api]`` and ``[pipeline:admin_api]`` pipelines. + Remove the following filters: ``[filter:user_crud_extension]``, + ``[filter:crud_extension]``. See the sample `keystone-paste.ini + `_ + file for guidance. other: - > [`blueprint move-extensions `_]