summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.zuul.yaml2
-rw-r--r--keystone/api/users.py47
-rw-r--r--keystone/locale/en_GB/LC_MESSAGES/keystone.po16
-rw-r--r--keystone/tests/protection/v3/test_application_credential.py66
-rw-r--r--releasenotes/notes/bug-1901207-13762f85b8a04481.yaml7
-rw-r--r--releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po127
-rw-r--r--releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po120
-rw-r--r--releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po202
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::"