diff options
-rw-r--r-- | .zuul.yaml | 2 | ||||
-rw-r--r-- | keystone/api/users.py | 47 | ||||
-rw-r--r-- | keystone/locale/en_GB/LC_MESSAGES/keystone.po | 16 | ||||
-rw-r--r-- | keystone/tests/protection/v3/test_application_credential.py | 66 | ||||
-rw-r--r-- | releasenotes/notes/bug-1901207-13762f85b8a04481.yaml | 7 | ||||
-rw-r--r-- | releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po | 127 | ||||
-rw-r--r-- | releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po | 120 | ||||
-rw-r--r-- | releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po | 202 |
8 files changed, 257 insertions, 330 deletions
diff --git a/.zuul.yaml b/.zuul.yaml index 1af47ece5..4e98dc70c 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -204,13 +204,13 @@ - project: templates: - openstack-cover-jobs - - openstack-lower-constraints-jobs - openstack-python3-victoria-jobs - publish-openstack-docs-pti - periodic-stable-jobs - check-requirements - integrated-gate-py3 - release-notes-jobs-python3 + - openstack-python3-wallaby-jobs-arm64 check: jobs: - keystone-dsvm-py3-functional: diff --git a/keystone/api/users.py b/keystone/api/users.py index f7f1ec0cf..10f26bd42 100644 --- a/keystone/api/users.py +++ b/keystone/api/users.py @@ -121,6 +121,41 @@ def _build_enforcer_target_data_owner_and_user_id_match(): return ref +def _update_request_user_id_attribute(): + # This method handles a special case in policy enforcement. The application + # credential API is underneath the user path (e.g., + # /v3/users/{user_id}/application_credentials/{application_credential_id}). + # The RBAC enforcer thinks the user to evaluate for application credential + # ownership comes from the path, but it should come from the actual + # application credential reference. By ensuring we pull the user ID from + # the application credential, we close a loop hole where users could + # effectively bypass authorization to view or delete any application + # credential in the system, assuming the attacker knows the application + # credential ID of another user. So long as the attacker matches the user + # ID in the request path to the user in the token of the request, they can + # pass the `rule:owner` policy check. This method protects against that by + # ensuring we use the application credential user ID and not something + # determined from the client. + try: + app_cred = ( + PROVIDERS.application_credential_api.get_application_credential( + flask.request.view_args.get('application_credential_id') + ) + ) + flask.request.view_args['user_id'] = app_cred['user_id'] + + # This target isn't really used in the default policy for application + # credentials, but we return it since we're using this method as a hook + # to update the flask request variables, which are used later in the + # keystone RBAC enforcer to populate the policy_dict, which ultimately + # turns into target attributes. + return {'user_id': app_cred['user_id']} + except ks_exception.NotFound: # nosec + # Defer existance in the event the application credential doesn't + # exist, we'll check this later anyway. + pass + + def _format_role_entity(role_id): role = PROVIDERS.role_api.get_role(role_id) formatted_entity = role.copy() @@ -652,7 +687,11 @@ class UserAppCredGetDeleteResource(ks_flask.ResourceBase): GET/HEAD /v3/users/{user_id}/application_credentials/ {application_credential_id} """ - ENFORCER.enforce_call(action='identity:get_application_credential') + target = _update_request_user_id_attribute() + ENFORCER.enforce_call( + action='identity:get_application_credential', + target_attr=target, + ) ref = PROVIDERS.application_credential_api.get_application_credential( application_credential_id) return self.wrap_member(ref) @@ -663,7 +702,11 @@ class UserAppCredGetDeleteResource(ks_flask.ResourceBase): DELETE /v3/users/{user_id}/application_credentials/ {application_credential_id} """ - ENFORCER.enforce_call(action='identity:delete_application_credential') + target = _update_request_user_id_attribute() + ENFORCER.enforce_call( + action='identity:delete_application_credential', + target_attr=target + ) token = self.auth_context['token'] _check_unrestricted_application_credential(token) PROVIDERS.application_credential_api.delete_application_credential( diff --git a/keystone/locale/en_GB/LC_MESSAGES/keystone.po b/keystone/locale/en_GB/LC_MESSAGES/keystone.po index 5e6cdf89b..191ed5596 100644 --- a/keystone/locale/en_GB/LC_MESSAGES/keystone.po +++ b/keystone/locale/en_GB/LC_MESSAGES/keystone.po @@ -12,11 +12,11 @@ msgid "" msgstr "" "Project-Id-Version: keystone VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2020-06-18 11:23+0000\n" +"POT-Creation-Date: 2021-01-08 19:57+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2020-06-15 05:35+0000\n" +"PO-Revision-Date: 2020-10-28 02:12+0000\n" "Last-Translator: Andi Chandler <andi@gowling.com>\n" "Language: en_GB\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -1384,6 +1384,14 @@ msgstr "" #, python-format msgid "" +"Unable to create additional credentials, maximum of %(limit)d already " +"exceeded for user." +msgstr "" +"Unable to create additional credentials, maximum of %(limit)d already " +"exceeded for user." + +#, python-format +msgid "" "Unable to delete immutable %(type)s resource: `%(resource_id)s. Set resource " "option \"immutable\" to false first." msgstr "" @@ -1492,6 +1500,10 @@ msgstr "" "%(group_id)s, Project: %(project_id)s, Domain: %(domain_id)s." #, python-format +msgid "Unexpected evaluation type \"%(eval_type)s\"" +msgstr "Unexpected evaluation type \"%(eval_type)s\"" + +#, python-format msgid "Unexpected status requested for JSON Home response, %s" msgstr "Unexpected status requested for JSON Home response, %s" diff --git a/keystone/tests/protection/v3/test_application_credential.py b/keystone/tests/protection/v3/test_application_credential.py index 5807d7f90..5f7c2a202 100644 --- a/keystone/tests/protection/v3/test_application_credential.py +++ b/keystone/tests/protection/v3/test_application_credential.py @@ -418,6 +418,72 @@ class OwnerTests(_TestAppCredBase, def test_owner_can_delete_application_credential(self): self._test_delete_application_credential() + def test_user_cannot_lookup_application_credential_for_another_user(self): + # create another user + another_user = unit.new_user_ref( + domain_id=CONF.identity.default_domain_id + ) + another_user_id = PROVIDERS.identity_api.create_user( + another_user + )['id'] + + auth = self.build_authentication_request( + user_id=another_user_id, + password=another_user['password'] + ) + + # authenticate for a token as a completely different user with + # completely different authorization + with self.test_client() as c: + r = c.post('/v3/auth/tokens', json=auth) + another_user_token = r.headers['X-Subject-Token'] + + # create an application credential as the self.user_id user on a + # project that the user above doesn't have any authorization on + app_cred = self._create_application_credential() + + # attempt to lookup the application credential as another user + with self.test_client() as c: + c.get( + '/v3/users/%s/application_credentials/%s' % ( + another_user_id, + app_cred['id']), + expected_status_code=http.client.FORBIDDEN, + headers={'X-Auth-Token': another_user_token}) + + def test_user_cannot_delete_application_credential_for_another_user(self): + # create another user + another_user = unit.new_user_ref( + domain_id=CONF.identity.default_domain_id + ) + another_user_id = PROVIDERS.identity_api.create_user( + another_user + )['id'] + + auth = self.build_authentication_request( + user_id=another_user_id, + password=another_user['password'] + ) + + # authenticate for a token as a completely different user with + # completely different authorization + with self.test_client() as c: + r = c.post('/v3/auth/tokens', json=auth) + another_user_token = r.headers['X-Subject-Token'] + + # create an application credential as the self.user_id user on a + # project that the user above doesn't have any authorization on + app_cred = self._create_application_credential() + + # attempt to delete the application credential as another user + with self.test_client() as c: + c.delete( + '/v3/users/%s/application_credentials/%s' % ( + another_user_id, + app_cred['id']), + expected_status_code=http.client.FORBIDDEN, + headers={'X-Auth-Token': another_user_token}) + class DomainAdminTests(_TestAppCredBase, common_auth.AuthTestMixin, diff --git a/releasenotes/notes/bug-1901207-13762f85b8a04481.yaml b/releasenotes/notes/bug-1901207-13762f85b8a04481.yaml new file mode 100644 index 000000000..26e957a0d --- /dev/null +++ b/releasenotes/notes/bug-1901207-13762f85b8a04481.yaml @@ -0,0 +1,7 @@ +--- +security: + - | + [`bug 1901207 <https://bugs.launchpad.net/keystone/+bug/1901207>`_] + Policy enforcement for application credentials has been updated to protect + against invalid ownership checks resulting in unauthorized users being able + to get and delete application credentials for other users. diff --git a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po index 618965f0b..600d9e0b0 100644 --- a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po +++ b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po @@ -1,14 +1,15 @@ # Andi Chandler <andi@gowling.com>, 2017. #zanata # Andi Chandler <andi@gowling.com>, 2018. #zanata +# Andi Chandler <andi@gowling.com>, 2020. #zanata msgid "" msgstr "" -"Project-Id-Version: keystone\n" +"Project-Id-Version: Keystone Release Notes\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-30 20:15+0000\n" +"POT-Creation-Date: 2021-01-08 19:54+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2018-08-08 09:01+0000\n" +"PO-Revision-Date: 2020-12-19 01:35+0000\n" "Last-Translator: Andi Chandler <andi@gowling.com>\n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" @@ -59,12 +60,60 @@ msgstr "12.0.0" msgid "12.0.1" msgstr "12.0.1" +msgid "12.0.2" +msgstr "12.0.2" + +msgid "12.0.3" +msgstr "12.0.3" + +msgid "12.0.3-9" +msgstr "12.0.3-9" + msgid "13.0.0" msgstr "13.0.0" msgid "13.0.1" msgstr "13.0.1" +msgid "13.0.2" +msgstr "13.0.2" + +msgid "13.0.3" +msgstr "13.0.3" + +msgid "14.0.0" +msgstr "14.0.0" + +msgid "14.0.1" +msgstr "14.0.1" + +msgid "14.1.0" +msgstr "14.1.0" + +msgid "14.2.0" +msgstr "14.2.0" + +msgid "14.2.0-4" +msgstr "14.2.0-4" + +msgid "15.0.0" +msgstr "15.0.0" + +msgid "15.0.1" +msgstr "15.0.1" + +msgid "16.0.0" +msgstr "16.0.0" + +msgid "16.0.1" +msgstr "16.0.1" + +msgid "17.0.0" +msgstr "17.0.0" + +msgid "17.0.0-6" +msgstr "17.0.0-6" + msgid "8.0.1" msgstr "8.0.1" @@ -78,6 +127,23 @@ msgid "9.2.0" msgstr "9.2.0" msgid "" +"A Federated user gets an entry in the shadow-users table. This entry has a " +"unique ID. It was generated using a UUID. This fix changes to reuse the " +"mechanism for LDAP, where the ID is generated from the domain ID + the local " +"id of the user (an attribute that uniquely ids the user from the IdP). This " +"generator is specified by the configuration file. Now Both LDAP and " +"Federated Ids are generated the same way. It also means that Federated IDs " +"can be kept in sync between two independtent Keystone servers." +msgstr "" +"A Federated user gets an entry in the shadow-users table. This entry has a " +"unique ID. It was generated using a UUID. This fix changes to reuse the " +"mechanism for LDAP, where the ID is generated from the domain ID + the local " +"id of the user (an attribute that uniquely ids the user from the IdP). This " +"generator is specified by the configuration file. Now Both LDAP and " +"Federated Ids are generated the same way. It also means that Federated IDs " +"can be kept in sync between two independent Keystone servers." + +msgid "" "A new ``secure_proxy_ssl_header`` configuration option is available when " "running keystone behind a proxy." msgstr "" @@ -152,6 +218,30 @@ msgstr "" "details on this change." msgid "" +"All policies in ``policy.v3cloudsample.json`` that are redundant with the " +"defaults in code have been removed. This improves maintainability and leaves " +"the ``policy.v3cloudsample.json`` policy file with only overrides. These " +"overrides will eventually be moved into code or new defaults in keystone " +"directly. If you're using the policies removed from ``policy.v3cloudsample." +"json`` please check to see if you can migrate to the new defaults or " +"continue maintaining the policy as an override." +msgstr "" +"All policies in ``policy.v3cloudsample.json`` that are redundant with the " +"defaults in code have been removed. This improves maintainability and leaves " +"the ``policy.v3cloudsample.json`` policy file with only overrides. These " +"overrides will eventually be moved into code or new defaults in keystone " +"directly. If you're using the policies removed from ``policy.v3cloudsample." +"json`` please check to see if you can migrate to the new defaults or " +"continue maintaining the policy as an override." + +msgid "" +"Allow the creating of a domain with the additional, optional parameter of " +"`explicit_domain_id` instead of auto-creating a domain_id from a uuid." +msgstr "" +"Allow the creating of a domain with the additional, optional parameter of " +"`explicit_domain_id` instead of auto-creating a domain_id from a UUID." + +msgid "" "Any auth methods that are not defined in ``keystone.conf`` in the ``[auth] " "methods`` option are ignored when the rules are processed. Empty rules are " "not allowed. If a rule is empty due to no-valid auth methods existing within " @@ -167,6 +257,13 @@ msgstr "" "any single configured auth method is sufficient to receive a token." msgid "" +"Any middleware defined in Keystone's tree is no longer loaded via stevedore, " +"and likewise the entry points were removed." +msgstr "" +"Any middleware defined in Keystone's tree is no longer loaded via Stevedore, " +"and likewise the entry points were removed." + +msgid "" "As a performance improvement, the base mapping driver's method " "``get_domain_mapping_list`` now accepts an optional named argument " "``entity_type`` that can be used to get the mappings for a given entity type " @@ -233,6 +330,15 @@ msgstr "" "only)." msgid "" +"Dropping the Python2 support in OpenStack Ussuri according to `the TC " +"deprecation timeline <https://governance.openstack.org/tc/" +"resolutions/20180529-python2-deprecation-timeline.html>`_" +msgstr "" +"Dropping the Python2 support in OpenStack Ussuri according to `the TC " +"deprecation timeline <https://governance.openstack.org/tc/" +"resolutions/20180529-python2-deprecation-timeline.html>`_" + +msgid "" "Each list of methods specifies a rule. If the auth methods provided by a " "user match (or exceed) the auth methods in the list, that rule is used. The " "first rule found (rules will not be processed in a specific order) that " @@ -329,6 +435,21 @@ msgstr "" "``[security_compliance] unique_last_password_count``." msgid "" +"If expiring user group memberships are enabled via the `[federation] " +"default_authorization_ttl` configuration option, or on an idp by idp basis " +"by setting `authorization_ttl`, there will be a lag between when a user is " +"removed from a group in an identity provider, and when that will be " +"reflected in keystone. That amount of time will be equal to the last time " +"the user logged in + idp ttl." +msgstr "" +"If expiring user group memberships are enabled via the `[federation] " +"default_authorization_ttl` configuration option, or on an idp by idp basis " +"by setting `authorization_ttl`, there will be a lag between when a user is " +"removed from a group in an identity provider, and when that will be " +"reflected in keystone. That amount of time will be equal to the last time " +"the user logged in + idp ttl." + +msgid "" "If performing rolling upgrades, set `[identity] " "rolling_upgrade_password_hash_compat` to `True`. This will instruct keystone " "to continue to hash passwords in a manner that older (pre Pike release) " diff --git a/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po deleted file mode 100644 index f20c441f9..000000000 --- a/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,120 +0,0 @@ -# Gérald LONLAS <g.lonlas@gmail.com>, 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: Keystone Release Notes\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-30 05:00+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-10-22 05:03+0000\n" -"Last-Translator: Gérald LONLAS <g.lonlas@gmail.com>\n" -"Language-Team: French\n" -"Language: fr\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" - -msgid "10.0.0" -msgstr "10.0.0" - -msgid "8.0.1" -msgstr "8.0.1" - -msgid "8.1.0" -msgstr "8.1.0" - -msgid "9.0.0" -msgstr "9.0.0" - -msgid "9.2.0" -msgstr "9.2.0" - -msgid "Bug Fixes" -msgstr "Corrections de bugs" - -msgid "Critical Issues" -msgstr "Erreurs critiques" - -msgid "Current Series Release Notes" -msgstr "Note de la release actuelle" - -msgid "Deprecation Notes" -msgstr "Notes dépréciées " - -msgid "Keystone Release Notes" -msgstr "Note de release de Keystone" - -msgid "Liberty Series Release Notes" -msgstr "Note de release pour Liberty" - -msgid "Mitaka Series Release Notes" -msgstr "Note de release pour Mitaka" - -msgid "New Features" -msgstr "Nouvelles fonctionnalités" - -msgid "Newton Series Release Notes" -msgstr "Note de release pour Newton" - -msgid "Other Notes" -msgstr "Autres notes" - -msgid "Security Issues" -msgstr "Problèmes de sécurités" - -msgid "Upgrade Notes" -msgstr "Notes de mises à jours" - -msgid "``add user to group``" -msgstr "``add user to group``" - -msgid "``create group``" -msgstr "``create group``" - -msgid "``create user``" -msgstr "``create user``" - -msgid "``delete group``" -msgstr "``delete group``" - -msgid "``delete user``" -msgstr "``delete user``" - -msgid "``keystone/common/cache/backends/memcache_pool``" -msgstr "``keystone/common/cache/backends/memcache_pool``" - -msgid "``keystone/common/cache/backends/mongo``" -msgstr "``keystone/common/cache/backends/mongo``" - -msgid "``keystone/common/cache/backends/noop``" -msgstr "``keystone/common/cache/backends/noop``" - -msgid "``keystone/contrib/admin_crud``" -msgstr "``keystone/contrib/admin_crud``" - -msgid "``keystone/contrib/endpoint_filter``" -msgstr "``keystone/contrib/endpoint_filter``" - -msgid "``keystone/contrib/federation``" -msgstr "``keystone/contrib/federation``" - -msgid "``keystone/contrib/oauth1``" -msgstr "``keystone/contrib/oauth1``" - -msgid "``keystone/contrib/revoke``" -msgstr "``keystone/contrib/revoke``" - -msgid "``keystone/contrib/simple_cert``" -msgstr "``keystone/contrib/simple_cert``" - -msgid "``keystone/contrib/user_crud``" -msgstr "``keystone/contrib/user_crud``" - -msgid "``remove user from group``" -msgstr "``remove user from group``" - -msgid "``update group``" -msgstr "``update group``" - -msgid "``update user``" -msgstr "``update user``" diff --git a/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po deleted file mode 100644 index 5999f69cc..000000000 --- a/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,202 +0,0 @@ -# Sungjin Kang <gang.sungjin@gmail.com>, 2017. #zanata -# Ian Y. Choi <ianyrchoi@gmail.com>, 2018. #zanata -msgid "" -msgstr "" -"Project-Id-Version: Keystone Release Notes\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-30 05:00+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2018-02-14 07:39+0000\n" -"Last-Translator: Ian Y. Choi <ianyrchoi@gmail.com>\n" -"Language-Team: Korean (South Korea)\n" -"Language: ko_KR\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=1; plural=0\n" - -msgid "'/' and ',' are not allowed to be in a tag" -msgstr "'/' 및 ',' 는 태그 내에서 허용하지 않습니다" - -msgid "" -"**Experimental** - Domain specific configuration options can be stored in " -"SQL instead of configuration files, using the new REST APIs." -msgstr "" -"**실험적 기능** - 도메인에 특화된 구성 옵션을 구성 파일 대신 SQL에 새로운 " -"REST API를 사용하여 저장 가능합니다." - -msgid "" -"**Experimental** - Keystone now supports tokenless authorization with X.509 " -"SSL client certificate." -msgstr "" -"**실험적 기능** - Keystone이 이제 X.509 SSL 클라이언트 인증서를 사용한 토큰" -"이 없는 인증 방식 (tokenless authorization)을 지원합니다." - -msgid "10.0.0" -msgstr "10.0.0" - -msgid "10.0.1" -msgstr "10.0.1" - -msgid "10.0.3" -msgstr "10.0.3" - -msgid "11.0.0" -msgstr "11.0.0" - -msgid "11.0.1" -msgstr "11.0.1" - -msgid "11.0.3" -msgstr "11.0.3" - -msgid "12.0.0" -msgstr "12.0.0" - -msgid "8.0.1" -msgstr "8.0.1" - -msgid "8.1.0" -msgstr "8.1.0" - -msgid "9.0.0" -msgstr "9.0.0" - -msgid "9.2.0" -msgstr "9.2.0" - -msgid "Bug Fixes" -msgstr "버그 수정" - -msgid "Critical Issues" -msgstr "치명적인 이슈" - -msgid "Current Series Release Notes" -msgstr "현재 시리즈 릴리즈 노트" - -msgid "Deprecation Notes" -msgstr "지원 종료된 기능 노트" - -msgid "" -"For additional details see: `event notifications <See https://docs.openstack." -"org/developer/keystone/event_notifications.html>`_" -msgstr "" -"추가적으로 자세한 사항을 확인하려면 : `event notifications <See https://docs." -"openstack.org/developer/keystone/event_notifications.html>`_" - -msgid "Keystone Release Notes" -msgstr "Keystone 릴리즈 노트" - -msgid "Liberty Series Release Notes" -msgstr "Liberty 시리즈 릴리즈 노트" - -msgid "Mitaka Series Release Notes" -msgstr "Mitaka 시리즈 릴리즈 노트" - -msgid "New Features" -msgstr "새로운 기능" - -msgid "Newton Series Release Notes" -msgstr "Newton 시리즈 릴리즈 노트" - -msgid "Ocata Series Release Notes" -msgstr "Ocata 시리즈 릴리즈 노트" - -msgid "Other Notes" -msgstr "기타 기능" - -msgid "Pike Series Release Notes" -msgstr "Pike 시리즈 릴리즈 노트" - -msgid "Queens Series Release Notes" -msgstr "Queens 시리즈 릴리즈 노트" - -msgid "Security Issues" -msgstr "보안 이슈" - -msgid "To::" -msgstr "To::" - -msgid "Upgrade Notes" -msgstr "업그레이드 노트" - -msgid "``add user to group``" -msgstr "``add user to group``" - -msgid "``create group``" -msgstr "``create group``" - -msgid "``create user``" -msgstr "``create user``" - -msgid "``delete group``" -msgstr "``delete group``" - -msgid "``delete user``" -msgstr "``delete user``" - -msgid "``issue_v2_token``" -msgstr "``issue_v2_token``" - -msgid "``issue_v3_token``" -msgstr "``issue_v3_token``" - -msgid "``keystone.common.kvs.backends.inmemdb.MemoryBackend``" -msgstr "``keystone.common.kvs.backends.inmemdb.MemoryBackend``" - -msgid "``keystone.common.kvs.backends.memcached.MemcachedBackend``" -msgstr "``keystone.common.kvs.backends.memcached.MemcachedBackend``" - -msgid "``keystone.token.persistence.backends.kvs.Token``" -msgstr "``keystone.token.persistence.backends.kvs.Token``" - -msgid "``keystone/common/cache/backends/memcache_pool``" -msgstr "``keystone/common/cache/backends/memcache_pool``" - -msgid "``keystone/common/cache/backends/mongo``" -msgstr "``keystone/common/cache/backends/mongo``" - -msgid "``keystone/common/cache/backends/noop``" -msgstr "``keystone/common/cache/backends/noop``" - -msgid "``keystone/contrib/admin_crud``" -msgstr "``keystone/contrib/admin_crud``" - -msgid "``keystone/contrib/endpoint_filter``" -msgstr "``keystone/contrib/endpoint_filter``" - -msgid "``keystone/contrib/federation``" -msgstr "``keystone/contrib/federation``" - -msgid "``keystone/contrib/oauth1``" -msgstr "``keystone/contrib/oauth1``" - -msgid "``keystone/contrib/revoke``" -msgstr "``keystone/contrib/revoke``" - -msgid "``keystone/contrib/simple_cert``" -msgstr "``keystone/contrib/simple_cert``" - -msgid "``keystone/contrib/user_crud``" -msgstr "``keystone/contrib/user_crud``" - -msgid "``remove user from group``" -msgstr "``remove user from group``" - -msgid "``update group``" -msgstr "``update group``" - -msgid "``update user``" -msgstr "``update user``" - -msgid "``validate_non_persistent_token``" -msgstr "``validate_non_persistent_token``" - -msgid "``validate_v2_token``" -msgstr "``validate_v2_token``" - -msgid "``validate_v3_token``" -msgstr "``validate_v3_token``" - -msgid "to::" -msgstr "to::" |