Skip to content
Permalink
Browse files Browse the repository at this point in the history
Merge "Add size validations for /tokens." into stable/folsom
  • Loading branch information
Jenkins authored and openstack-gerrit committed Feb 5, 2013
2 parents b3bd5fd + bb2226f commit 82c87e5
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 0 deletions.
3 changes: 3 additions & 0 deletions keystone/config.py
Expand Up @@ -117,6 +117,9 @@ def register_cli_int(*args, **kw):
register_str('public_port', default=5000)
register_str('onready')
register_str('auth_admin_prefix', default='')
register_int('max_param_size', default=64)
# we allow tokens to be a bit larger to accomidate PKI
register_int('max_token_size', default=8192)

#ssl options
register_bool('enable', group='ssl', default=False)
Expand Down
13 changes: 13 additions & 0 deletions keystone/exception.py
Expand Up @@ -51,6 +51,19 @@ class ValidationError(Error):
title = 'Bad Request'


class ValidationSizeError(Error):
"""Request attribute %(attribute)s must be less than or equal to %(size)i.
The server could not comply with the request because the attribute
size is invalid (too large).
The client is assumed to be in error.
"""
code = 400
title = 'Bad Request'


class Unauthorized(Error):
"""The request you have made requires authentication."""
code = 401
Expand Down
27 changes: 27 additions & 0 deletions keystone/service.py
Expand Up @@ -22,6 +22,7 @@
from keystone import catalog
from keystone.common import cms
from keystone.common import logging
from keystone.common import utils
from keystone.common import wsgi
from keystone import exception
from keystone import identity
Expand All @@ -31,6 +32,8 @@


LOG = logging.getLogger(__name__)
MAX_PARAM_SIZE = config.CONF.max_param_size
MAX_TOKEN_SIZE = config.CONF.max_token_size


class AdminRouter(wsgi.ComposingRouter):
Expand Down Expand Up @@ -288,9 +291,23 @@ def authenticate(self, context, auth=None):

if 'passwordCredentials' in auth:
user_id = auth['passwordCredentials'].get('userId', None)
if user_id and len(user_id) > MAX_PARAM_SIZE:
raise exception.ValidationSizeError(attribute='userId',
size=MAX_PARAM_SIZE)
username = auth['passwordCredentials'].get('username', '')
if len(username) > MAX_PARAM_SIZE:
raise exception.ValidationSizeError(attribute='username',
size=MAX_PARAM_SIZE)
password = auth['passwordCredentials'].get('password', '')
max_pw_size = utils.MAX_PASSWORD_LENGTH
if len(password) > max_pw_size:
raise exception.ValidationSizeError(attribute='password',
size=max_pw_size)

tenant_name = auth.get('tenantName', None)
if tenant_name and len(tenant_name) > MAX_PARAM_SIZE:
raise exception.ValidationSizeError(attribute='tenantName',
size=MAX_PARAM_SIZE)

if username:
try:
Expand All @@ -302,6 +319,9 @@ def authenticate(self, context, auth=None):

# more compat
tenant_id = auth.get('tenantId', None)
if tenant_id and len(tenant_id) > MAX_PARAM_SIZE:
raise exception.ValidationSizeError(attribute='tenantId',
size=MAX_PARAM_SIZE)
if tenant_name:
try:
tenant_ref = self.identity_api.get_tenant_by_name(
Expand Down Expand Up @@ -342,7 +362,14 @@ def authenticate(self, context, auth=None):
catalog_ref = {}
elif 'token' in auth:
old_token = auth['token'].get('id', None)

if len(old_token) > MAX_TOKEN_SIZE:
raise exception.ValidationSizeError(attribute='token',
size=MAX_TOKEN_SIZE)
tenant_name = auth.get('tenantName')
if tenant_name and len(tenant_name) > MAX_PARAM_SIZE:
raise exception.ValidationSizeError(attribute='tenantName',
size=MAX_PARAM_SIZE)

try:
old_token_ref = self.token_api.get_token(context=context,
Expand Down
75 changes: 75 additions & 0 deletions tests/test_service.py
Expand Up @@ -17,6 +17,7 @@
import default_fixtures

from keystone import config
from keystone import exception
from keystone import service
from keystone import test
from keystone.identity.backends import kvs as kvs_identity
Expand All @@ -25,6 +26,31 @@
CONF = config.CONF


def _build_user_auth(token=None, user_id=None, username=None,
password=None, tenant_id=None, tenant_name=None):
"""Build auth dictionary.
It will create an auth dictionary based on all the arguments
that it receives.
"""
auth_json = {}
if token is not None:
auth_json['token'] = token
if username or password:
auth_json['passwordCredentials'] = {}
if username is not None:
auth_json['passwordCredentials']['username'] = username
if user_id is not None:
auth_json['passwordCredentials']['userId'] = user_id
if password is not None:
auth_json['passwordCredentials']['password'] = password
if tenant_name is not None:
auth_json['tenantName'] = tenant_name
if tenant_id is not None:
auth_json['tenantId'] = tenant_id
return auth_json


class TokenExpirationTest(test.TestCase):
def setUp(self):
super(TokenExpirationTest, self).setUp()
Expand Down Expand Up @@ -75,3 +101,52 @@ def _maintain_token_expiration(self):
def test_maintain_uuid_token_expiration(self):
self.opt_in_group('signing', token_format='UUID')
self._maintain_token_expiration()


class AuthTest(test.TestCase):
def setUp(self):
super(AuthTest, self).setUp()

CONF.identity.driver = 'keystone.identity.backends.kvs.Identity'
self.load_backends()
self.load_fixtures(default_fixtures)
self.api = service.TokenController()

def test_authenticate_user_id_too_large(self):
"""Verify sending large 'userId' raises the right exception."""
body_dict = _build_user_auth(user_id='0' * 65, username='FOO',
password='foo2')
self.assertRaises(exception.ValidationSizeError, self.api.authenticate,
{}, body_dict)

def test_authenticate_username_too_large(self):
"""Verify sending large 'username' raises the right exception."""
body_dict = _build_user_auth(username='0' * 65, password='foo2')
self.assertRaises(exception.ValidationSizeError, self.api.authenticate,
{}, body_dict)

def test_authenticate_tenant_id_too_large(self):
"""Verify sending large 'tenantId' raises the right exception."""
body_dict = _build_user_auth(username='FOO', password='foo2',
tenant_id='0' * 65)
self.assertRaises(exception.ValidationSizeError, self.api.authenticate,
{}, body_dict)

def test_authenticate_tenant_name_too_large(self):
"""Verify sending large 'tenantName' raises the right exception."""
body_dict = _build_user_auth(username='FOO', password='foo2',
tenant_name='0' * 65)
self.assertRaises(exception.ValidationSizeError, self.api.authenticate,
{}, body_dict)

def test_authenticate_token_too_large(self):
"""Verify sending large 'token' raises the right exception."""
body_dict = _build_user_auth(token={'id': '0' * 8193})
self.assertRaises(exception.ValidationSizeError, self.api.authenticate,
{}, body_dict)

def test_authenticate_password_too_large(self):
"""Verify sending large 'password' raises the right exception."""
body_dict = _build_user_auth(username='FOO', password='0' * 8193)
self.assertRaises(exception.ValidationSizeError, self.api.authenticate,
{}, body_dict)

0 comments on commit 82c87e5

Please sign in to comment.