Impose limits on application credentials

In order to protect against possible abuse or bloat, add a config option
to set a limit on the number of application credentials a user may have.

bp application-credentials

Change-Id: Ieab33c3265fa0c0b1b1c6d586e5ea8a9a39edfb1
This commit is contained in:
Colleen Murphy 2018-01-22 20:39:35 +01:00
parent 5e97f2d052
commit d827e6e3ab
4 changed files with 41 additions and 0 deletions

View File

@ -91,6 +91,14 @@ class Manager(manager.Manager):
actor_id=user_id,
target_id=project_id)
def _assert_limit_not_exceeded(self, user_id):
user_limit = CONF.application_credential.user_limit
if user_limit >= 0:
app_cred_count = len(self.list_application_credentials(user_id))
if app_cred_count >= user_limit:
raise exception.ApplicationCredentialLimitExceeded(
limit=user_limit)
def _get_role_list(self, app_cred_roles):
roles = []
for role in app_cred_roles:
@ -126,6 +134,8 @@ class Manager(manager.Manager):
user_id = application_credential['user_id']
project_id = application_credential['project_id']
roles = application_credential.pop('roles', [])
self._assert_limit_not_exceeded(user_id)
self._require_user_has_role_in_project(roles, user_id, project_id)
unhashed_secret = application_credential['secret']
ref = self.driver.create_application_credential(

View File

@ -40,12 +40,23 @@ Time to cache application credential data in seconds. This has no effect
unless global caching is enabled.
"""))
user_limit = cfg.IntOpt(
'user_limit',
default=-1,
help=utils.fmt("""
Maximum number of application credentials a user is permitted to create. A
value of -1 means unlimited. If a limit is not set, users are permitted to
create application 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 = [
driver,
caching,
cache_time,
user_limit,
]

View File

@ -205,6 +205,11 @@ class RegionDeletionError(ForbiddenNotSecurity):
"its child regions have associated endpoints.")
class ApplicationCredentialLimitExceeded(ForbiddenNotSecurity):
message_format = _("Unable to create additional application credentials, "
"maximum of %(limit)d already exceeded for user.")
class SecurityError(Error):
"""Security error exception.

View File

@ -13,6 +13,8 @@
import datetime
import uuid
from oslo_config import fixture as config_fixture
from keystone.common import driver_hints
from keystone.common import provider_api
import keystone.conf
@ -92,6 +94,19 @@ class ApplicationCredentialTests(object):
app_cred.pop('roles')
self.assertDictEqual(app_cred, resp)
def test_application_credential_limits(self):
config_fixture_ = self.user = self.useFixture(config_fixture.Config())
config_fixture_.config(group='application_credential', user_limit=2)
app_cred = self._new_app_cred_data(self.user_foo['id'],
self.tenant_bar['id'])
self.app_cred_api.create_application_credential(app_cred)
app_cred['name'] = 'two'
self.app_cred_api.create_application_credential(app_cred)
app_cred['name'] = 'three'
self.assertRaises(exception.ApplicationCredentialLimitExceeded,
self.app_cred_api.create_application_credential,
app_cred)
def test_get_application_credential(self):
app_cred = self._new_app_cred_data(self.user_foo['id'],
project_id=self.tenant_bar['id'])