New config option 'user_limit' in credentials

This patch allows adds new config option 'user_limit'
to credentials to set maximum number of credentials a
user is permitted to create.
Closes-Bug: #1872732

Change-Id: Ic9dc9a4a9ec1ecbf01842c865e19a7a100e5041d
This commit is contained in:
Vishakha Agarwal 2020-04-17 23:08:40 +05:30
parent 111f0bdf12
commit a49ee620fa
5 changed files with 43 additions and 1 deletions

View File

@ -69,6 +69,15 @@ The length of time in minutes for which a signed EC2 or S3 token request is
valid from the timestamp contained in the token request.
"""))
user_limit = cfg.IntOpt(
'user_limit',
default=-1,
help=utils.fmt("""
Maximum number of credentials a user is permitted to create. A value of
-1 means unlimited. If a limit is not set, users are permitted to create
credentials at will, which could lead to bloat in the keystone database
or open keystone to a DoS attack.
"""))
GROUP_NAME = __name__.split('.')[-1]
ALL_OPTS = [
@ -77,7 +86,8 @@ ALL_OPTS = [
key_repository,
caching,
cache_time,
auth_ttl
auth_ttl,
user_limit,
]

View File

@ -86,6 +86,14 @@ class Manager(manager.Manager):
credential_copy.pop('blob', None)
return credential_copy
def _assert_limit_not_exceeded(self, user_id):
user_limit = CONF.credential.user_limit
if user_limit >= 0:
cred_count = len(self.list_credentials_for_user(user_id))
if cred_count >= user_limit:
raise exception.CredentialLimitExceeded(
limit=user_limit)
@manager.response_truncated
def list_credentials(self, hints=None):
credentials = self.driver.list_credentials(
@ -119,6 +127,8 @@ class Manager(manager.Manager):
initiator=None):
"""Create a credential."""
credential_copy = self._encrypt_credential(credential)
user_id = credential_copy['user_id']
self._assert_limit_not_exceeded(user_id)
ref = self.driver.create_credential(credential_id, credential_copy)
if MEMOIZE.should_cache(ref):
self._get_credential.set(ref,

View File

@ -222,6 +222,11 @@ class ApplicationCredentialLimitExceeded(ForbiddenNotSecurity):
"maximum of %(limit)d already exceeded for user.")
class CredentialLimitExceeded(ForbiddenNotSecurity):
message_format = _("Unable to create additional credentials, maximum "
"of %(limit)d already exceeded for user.")
class SecurityError(Error):
"""Security error exception.

View File

@ -12,6 +12,8 @@
import uuid
from oslo_config import fixture as config_fixture
from keystone.common import provider_api
from keystone.credential.providers import fernet as credential_provider
from keystone.tests import unit
@ -20,6 +22,7 @@ from keystone.tests.unit import ksfixtures
from keystone.tests.unit.ksfixtures import database
from keystone.credential.backends import sql as credential_sql
from keystone import exception
PROVIDERS = provider_api.ProviderAPIs
@ -102,3 +105,11 @@ class SqlCredential(SqlTests):
# Make sure CredentialModel is handing over a text string
# to the database. To avoid encoding issues
self.assertIsInstance(ref.encrypted_blob, str)
def test_credential_limits(self):
config_fixture_ = self.user = self.useFixture(config_fixture.Config())
config_fixture_.config(group='credential', user_limit=4)
self._create_credential_with_user_id(self.user_foo['id'])
self.assertRaises(exception.CredentialLimitExceeded,
self._create_credential_with_user_id,
self.user_foo['id'])

View File

@ -0,0 +1,6 @@
---
features:
- >
[`bug 1872732 <https://bugs.launchpad.net/keystone/+bug/1872732>`_]
'user_limit' is added to config file of credentials that allows user to set
maximum number of credentials a user is permitted to create.