Merge "Adds caching of credentials"
This commit is contained in:
commit
3d2b293d7e
@ -46,12 +46,29 @@ share this repository with the repository used to manage keys for Fernet
|
|||||||
tokens.
|
tokens.
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
|
caching = cfg.BoolOpt(
|
||||||
|
'caching',
|
||||||
|
default=True,
|
||||||
|
help=utils.fmt("""
|
||||||
|
Toggle for caching only on retrieval of user credentials. This has no effect
|
||||||
|
unless global caching is enabled.
|
||||||
|
"""))
|
||||||
|
|
||||||
|
cache_time = cfg.IntOpt(
|
||||||
|
'cache_time',
|
||||||
|
help=utils.fmt("""
|
||||||
|
Time to cache credential data in seconds. This has no effect unless global
|
||||||
|
caching is enabled.
|
||||||
|
"""))
|
||||||
|
|
||||||
|
|
||||||
GROUP_NAME = __name__.split('.')[-1]
|
GROUP_NAME = __name__.split('.')[-1]
|
||||||
ALL_OPTS = [
|
ALL_OPTS = [
|
||||||
driver,
|
driver,
|
||||||
provider,
|
provider,
|
||||||
key_repository
|
key_repository,
|
||||||
|
caching,
|
||||||
|
cache_time
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from keystone.common import cache
|
||||||
from keystone.common import driver_hints
|
from keystone.common import driver_hints
|
||||||
from keystone.common import manager
|
from keystone.common import manager
|
||||||
from keystone.common import provider_api
|
from keystone.common import provider_api
|
||||||
@ -24,6 +25,7 @@ from keystone import exception
|
|||||||
|
|
||||||
|
|
||||||
CONF = keystone.conf.CONF
|
CONF = keystone.conf.CONF
|
||||||
|
MEMOIZE = cache.get_memoization_decorator(group='credential')
|
||||||
PROVIDERS = provider_api.ProviderAPIs
|
PROVIDERS = provider_api.ProviderAPIs
|
||||||
|
|
||||||
|
|
||||||
@ -91,21 +93,39 @@ class Manager(manager.Manager):
|
|||||||
return credentials
|
return credentials
|
||||||
|
|
||||||
def list_credentials_for_user(self, user_id, type=None):
|
def list_credentials_for_user(self, user_id, type=None):
|
||||||
"""List credentials for a specific user."""
|
credentials = self._list_credentials_for_user(user_id, type)
|
||||||
credentials = self.driver.list_credentials_for_user(user_id, type=type)
|
|
||||||
for credential in credentials:
|
for credential in credentials:
|
||||||
credential = self._decrypt_credential(credential)
|
credential = self._decrypt_credential(credential)
|
||||||
return credentials
|
return credentials
|
||||||
|
|
||||||
|
@MEMOIZE
|
||||||
|
def _list_credentials_for_user(self, user_id, type):
|
||||||
|
"""List credentials for a specific user."""
|
||||||
|
return self.driver.list_credentials_for_user(user_id, type)
|
||||||
|
|
||||||
def get_credential(self, credential_id):
|
def get_credential(self, credential_id):
|
||||||
"""Return a credential reference."""
|
"""Return a credential reference."""
|
||||||
credential = self.driver.get_credential(credential_id)
|
credential = self._get_credential(credential_id)
|
||||||
return self._decrypt_credential(credential)
|
return self._decrypt_credential(credential)
|
||||||
|
|
||||||
|
@MEMOIZE
|
||||||
|
def _get_credential(self, credential_id):
|
||||||
|
return self.driver.get_credential(credential_id)
|
||||||
|
|
||||||
def create_credential(self, credential_id, credential):
|
def create_credential(self, credential_id, credential):
|
||||||
"""Create a credential."""
|
"""Create a credential."""
|
||||||
credential_copy = self._encrypt_credential(credential)
|
credential_copy = self._encrypt_credential(credential)
|
||||||
ref = self.driver.create_credential(credential_id, credential_copy)
|
ref = self.driver.create_credential(credential_id, credential_copy)
|
||||||
|
if MEMOIZE.should_cache(ref):
|
||||||
|
self._get_credential.set(ref,
|
||||||
|
credential_copy,
|
||||||
|
credential_id)
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
ref['user_id'],
|
||||||
|
ref['type'])
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
ref['user_id'],
|
||||||
|
None)
|
||||||
ref.pop('key_hash', None)
|
ref.pop('key_hash', None)
|
||||||
ref.pop('encrypted_blob', None)
|
ref.pop('encrypted_blob', None)
|
||||||
ref['blob'] = credential['blob']
|
ref['blob'] = credential['blob']
|
||||||
@ -133,6 +153,14 @@ class Manager(manager.Manager):
|
|||||||
existing_credential = self.get_credential(credential_id)
|
existing_credential = self.get_credential(credential_id)
|
||||||
existing_blob = existing_credential['blob']
|
existing_blob = existing_credential['blob']
|
||||||
ref = self.driver.update_credential(credential_id, credential_copy)
|
ref = self.driver.update_credential(credential_id, credential_copy)
|
||||||
|
if MEMOIZE.should_cache(ref):
|
||||||
|
self._get_credential.set(ref, self, credential_id)
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
ref['user_id'],
|
||||||
|
ref['type'])
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
ref['user_id'],
|
||||||
|
None)
|
||||||
ref.pop('key_hash', None)
|
ref.pop('key_hash', None)
|
||||||
ref.pop('encrypted_blob', None)
|
ref.pop('encrypted_blob', None)
|
||||||
# If the update request contains a `blob` attribute - we should return
|
# If the update request contains a `blob` attribute - we should return
|
||||||
@ -143,3 +171,44 @@ class Manager(manager.Manager):
|
|||||||
else:
|
else:
|
||||||
ref['blob'] = existing_blob
|
ref['blob'] = existing_blob
|
||||||
return ref
|
return ref
|
||||||
|
|
||||||
|
def delete_credential(self, credential_id):
|
||||||
|
"""Delete a credential."""
|
||||||
|
cred = self.get_credential(credential_id)
|
||||||
|
self.driver.delete_credential(credential_id)
|
||||||
|
self._get_credential.invalidate(self, credential_id)
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
cred['user_id'],
|
||||||
|
cred['type'])
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
cred['user_id'],
|
||||||
|
None)
|
||||||
|
|
||||||
|
def delete_credentials_for_project(self, project_id):
|
||||||
|
"""Delete all credentials for a project."""
|
||||||
|
hints = driver_hints.Hints()
|
||||||
|
hints.add_filter('project_id', project_id)
|
||||||
|
creds = self.driver.list_credentials(hints)
|
||||||
|
|
||||||
|
self.driver.delete_credentials_for_project(project_id)
|
||||||
|
for cred in creds:
|
||||||
|
self._get_credential.invalidate(self, cred['id'])
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
cred['user_id'],
|
||||||
|
cred['type'])
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
cred['user_id'],
|
||||||
|
None)
|
||||||
|
|
||||||
|
def delete_credentials_for_user(self, user_id):
|
||||||
|
"""Delete all credentials for a user."""
|
||||||
|
creds = self.driver.list_credentials_for_user(user_id)
|
||||||
|
self.driver.delete_credentials_for_user(user_id)
|
||||||
|
for cred in creds:
|
||||||
|
self._get_credential.invalidate(self, cred['id'])
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
user_id,
|
||||||
|
cred['type'])
|
||||||
|
self._list_credentials_for_user.invalidate(self,
|
||||||
|
cred['user_id'],
|
||||||
|
None)
|
||||||
|
7
releasenotes/notes/bug-1815771-ae0e4118c552f01e.yaml
Normal file
7
releasenotes/notes/bug-1815771-ae0e4118c552f01e.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
[`bug 1815771 <https://bugs.launchpad.net/keystone/+bug/1815771>`_]
|
||||||
|
Allows operators to cache credentials to avoid lookups on the database.
|
||||||
|
This operation can be turned on/off through the configuration parameter of
|
||||||
|
keystone.conf [credential] caching.
|
Loading…
x
Reference in New Issue
Block a user