d1294d7e67
Need update password before send out notification. Otherwise, any process which monitors the "updated" notification will still get old password from Keyring. Partial-Bug: 1853017 Change-Id: Id1c94fedca41abe96c7b38880bf325d4a25a95eb Signed-off-by: Shuicheng Lin <shuicheng.lin@intel.com>
148 lines
5.8 KiB
Diff
148 lines
5.8 KiB
Diff
From dfe0978f6590818487bb9fc5e9b8156e77a25590 Mon Sep 17 00:00:00 2001
|
|
From: rpm-build <rpm-build>
|
|
Date: Mon, 8 Apr 2019 15:25:28 -0400
|
|
Subject: [PATCH 1/1] Rebasing Keyring integration
|
|
|
|
---
|
|
keystone/exception.py | 6 ++++++
|
|
keystone/identity/core.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++
|
|
requirements.txt | 1 +
|
|
3 files changed, 61 insertions(+)
|
|
|
|
diff --git a/keystone/exception.py b/keystone/exception.py
|
|
index b85878b..56601ce 100644
|
|
--- a/keystone/exception.py
|
|
+++ b/keystone/exception.py
|
|
@@ -224,6 +224,12 @@ class ApplicationCredentialLimitExceeded(ForbiddenNotSecurity):
|
|
"maximum of %(limit)d already exceeded for user.")
|
|
|
|
|
|
+class WRSForbiddenAction(Error):
|
|
+ message_format = _("That action is not permitted")
|
|
+ code = 403
|
|
+ title = 'Forbidden'
|
|
+
|
|
+
|
|
class SecurityError(Error):
|
|
"""Security error exception.
|
|
|
|
diff --git a/keystone/identity/core.py b/keystone/identity/core.py
|
|
index ed43e76..da7e7ba 100644
|
|
--- a/keystone/identity/core.py
|
|
+++ b/keystone/identity/core.py
|
|
@@ -17,6 +17,7 @@
|
|
import copy
|
|
import functools
|
|
import itertools
|
|
+import keyring
|
|
import operator
|
|
import os
|
|
import threading
|
|
@@ -54,6 +55,7 @@ MEMOIZE_ID_MAPPING = cache.get_memoization_decorator(group='identity',
|
|
|
|
DOMAIN_CONF_FHEAD = 'keystone.'
|
|
DOMAIN_CONF_FTAIL = '.conf'
|
|
+KEYRING_CGCS_SERVICE = "CGCS"
|
|
|
|
# The number of times we will attempt to register a domain to use the SQL
|
|
# driver, if we find that another process is in the middle of registering or
|
|
@@ -1069,6 +1071,26 @@ class Manager(manager.Manager):
|
|
if new_ref['domain_id'] != orig_ref['domain_id']:
|
|
raise exception.ValidationError(_('Cannot change Domain ID'))
|
|
|
|
+ def _update_keyring_password(self, user, new_password):
|
|
+ """Update user password in Keyring backend.
|
|
+ This method Looks up user entries in Keyring backend
|
|
+ and accordingly update the corresponding user password.
|
|
+ :param user : keyring user struct
|
|
+ :param new_password : new password to set
|
|
+ """
|
|
+ if (new_password is not None) and ('name' in user):
|
|
+ try:
|
|
+ # only update if an entry exists
|
|
+ if (keyring.get_password(KEYRING_CGCS_SERVICE, user['name'])):
|
|
+ keyring.set_password(KEYRING_CGCS_SERVICE,
|
|
+ user['name'], new_password)
|
|
+ except (keyring.errors.PasswordSetError, RuntimeError):
|
|
+ msg = ('Failed to Update Keyring Password for the user %s')
|
|
+ LOG.warning(msg, user['name'])
|
|
+ # only raise an exception if this is the admin user
|
|
+ if (user['name'] == 'admin'):
|
|
+ raise exception.WRSForbiddenAction(msg % user['name'])
|
|
+
|
|
@domains_configured
|
|
@exception_translated('user')
|
|
def update_user(self, user_id, user_ref, initiator=None):
|
|
@@ -1099,6 +1121,17 @@ class Manager(manager.Manager):
|
|
|
|
ref = driver.update_user(entity_id, user)
|
|
|
|
+ # Certain local Keystone users are stored in Keystone as opposed
|
|
+ # to the default SQL Identity backend, such as the admin user.
|
|
+ # When its password is updated, we need to update Keyring as well
|
|
+ # as certain services retrieve this user context from Keyring and
|
|
+ # will get auth failures
|
|
+ # Need update password before send out notification. Otherwise,
|
|
+ # any process monitor the notification will still get old password
|
|
+ # from Keyring.
|
|
+ if ('password' in user) and ('name' in ref):
|
|
+ self._update_keyring_password(ref, user['password'])
|
|
+
|
|
notifications.Audit.updated(self._USER, user_id, initiator)
|
|
|
|
enabled_change = ((user.get('enabled') is False) and
|
|
@@ -1128,6 +1161,7 @@ class Manager(manager.Manager):
|
|
hints.add_filter('user_id', user_id)
|
|
fed_users = PROVIDERS.shadow_users_api.list_federated_users_info(hints)
|
|
|
|
+ username = user_old.get('name', "")
|
|
driver.delete_user(entity_id)
|
|
PROVIDERS.assignment_api.delete_user_assignments(user_id)
|
|
self.get_user.invalidate(self, user_id)
|
|
@@ -1141,6 +1175,18 @@ class Manager(manager.Manager):
|
|
|
|
PROVIDERS.credential_api.delete_credentials_for_user(user_id)
|
|
PROVIDERS.id_mapping_api.delete_id_mapping(user_id)
|
|
+
|
|
+ # Delete the keyring entry associated with this user (if present)
|
|
+ try:
|
|
+ keyring.delete_password(KEYRING_CGCS_SERVICE, username)
|
|
+ except keyring.errors.PasswordDeleteError:
|
|
+ LOG.warning(('delete_user: PasswordDeleteError for %s'),
|
|
+ username)
|
|
+ pass
|
|
+ except exception.UserNotFound:
|
|
+ LOG.warning(('delete_user: UserNotFound for %s'),
|
|
+ username)
|
|
+ pass
|
|
notifications.Audit.deleted(self._USER, user_id, initiator)
|
|
|
|
# Invalidate user role assignments cache region, as it may be caching
|
|
@@ -1390,6 +1436,14 @@ class Manager(manager.Manager):
|
|
notifications.Audit.updated(self._USER, user_id, initiator)
|
|
self._persist_revocation_event_for_user(user_id)
|
|
|
|
+ user = self.get_user(user_id)
|
|
+ # Update Keyring password for the 'user' if it
|
|
+ # has an entry in Keyring
|
|
+ if (original_password) and ('name' in user):
|
|
+ # Change the 'user' password in keyring, provided the user
|
|
+ # has an entry in Keyring backend
|
|
+ self._update_keyring_password(user, new_password)
|
|
+
|
|
@MEMOIZE
|
|
def _shadow_nonlocal_user(self, user):
|
|
try:
|
|
diff --git a/requirements.txt b/requirements.txt
|
|
index e3de1c6..e6d3536 100644
|
|
--- a/requirements.txt
|
|
+++ b/requirements.txt
|
|
@@ -42,3 +42,4 @@ pycadf!=2.0.0,>=1.1.0 # Apache-2.0
|
|
msgpack>=0.5.0 # Apache-2.0
|
|
osprofiler>=1.4.0 # Apache-2.0
|
|
pytz>=2013.6 # MIT
|
|
+keyring>=5.3
|
|
--
|
|
1.8.3.1
|
|
|