From 5eedeaa2c9ebb819f1f55d24fe8d30d47c8cff44 Mon Sep 17 00:00:00 2001 From: gage hugo Date: Wed, 20 Jul 2016 14:45:28 -0500 Subject: [PATCH] Add schema validation to update user v2 Added validation for update user in v2 Partially implements: bp schema-validation-extent Change-Id: I5eb6004467a6cf00dd3e02e5ee008b8fb2e26d82 --- keystone/identity/controllers.py | 5 +- keystone/identity/schema.py | 22 +++++++ keystone/tests/unit/identity/test_backends.py | 38 ------------ keystone/tests/unit/test_v2_validation.py | 58 +++++++++++++++++++ 4 files changed, 81 insertions(+), 42 deletions(-) diff --git a/keystone/identity/controllers.py b/keystone/identity/controllers.py index 6749a5ace0..e62afbec46 100644 --- a/keystone/identity/controllers.py +++ b/keystone/identity/controllers.py @@ -95,13 +95,10 @@ class User(controller.V2Controller): @controller.v2_deprecated def update_user(self, request, user_id, user): # NOTE(termie): this is really more of a patch than a put + validation.lazy_validate(schema.user_update_v2, user) user = self.normalize_username_in_request(user) self.assert_admin(request) - if 'enabled' in user and not isinstance(user['enabled'], bool): - msg = _('Enabled field should be a boolean') - raise exception.ValidationError(message=msg) - default_project_id = user.pop('tenantId', None) if default_project_id is not None: user['default_project_id'] = default_project_id diff --git a/keystone/identity/schema.py b/keystone/identity/schema.py index f0d1695100..4e0db3676b 100644 --- a/keystone/identity/schema.py +++ b/keystone/identity/schema.py @@ -22,6 +22,28 @@ _identity_name = { 'pattern': '[\S]+' } +# Schema for Identity v2 API + +_user_properties_v2 = { + 'description': validation.nullable(parameter_types.description), + 'enabled': parameter_types.boolean, + 'tenantId': validation.nullable(parameter_types.id_string), + 'name': _identity_name, + 'username': _identity_name, + 'password': { + 'type': ['string', 'null'] + } +} + +user_update_v2 = { + 'type': 'object', + 'properties': _user_properties_v2, + 'minProperties': 0, + 'additionalProperties': True +} + +# Schema for Identity v3 API + _user_properties = { 'default_project_id': validation.nullable(parameter_types.id_string), 'description': validation.nullable(parameter_types.description), diff --git a/keystone/tests/unit/identity/test_backends.py b/keystone/tests/unit/identity/test_backends.py index 77a7c283fb..bdcf629211 100644 --- a/keystone/tests/unit/identity/test_backends.py +++ b/keystone/tests/unit/identity/test_backends.py @@ -447,31 +447,6 @@ class IdentityTests(object): user['id'], user) - def test_update_user_blank_name_fails(self): - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user = self.identity_api.create_user(user) - user['name'] = '' - self.assertRaises(exception.ValidationError, - self.identity_api.update_user, - user['id'], - user) - - def test_update_user_invalid_name_fails(self): - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user = self.identity_api.create_user(user) - - user['name'] = None - self.assertRaises(exception.ValidationError, - self.identity_api.update_user, - user['id'], - user) - - user['name'] = 123 - self.assertRaises(exception.ValidationError, - self.identity_api.update_user, - user['id'], - user) - def test_list_users(self): users = self.identity_api.list_users( domain_scope=self._set_domain_scope( @@ -568,19 +543,6 @@ class IdentityTests(object): user_ref = self.identity_api.get_user(user_ref['id']) self.assertEqual(changed_name, user_ref['name']) - def test_update_user_enable_fails(self): - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user = self.identity_api.create_user(user) - user_ref = self.identity_api.get_user(user['id']) - self.assertTrue(user_ref['enabled']) - - # Strings are not valid boolean values - user['enabled'] = 'false' - self.assertRaises(exception.ValidationError, - self.identity_api.update_user, - user['id'], - user) - def test_add_user_to_group(self): domain = self._get_domain_fixture() new_group = unit.new_group_ref(domain_id=domain['id']) diff --git a/keystone/tests/unit/test_v2_validation.py b/keystone/tests/unit/test_v2_validation.py index 00ceb7d5f0..98627a4759 100644 --- a/keystone/tests/unit/test_v2_validation.py +++ b/keystone/tests/unit/test_v2_validation.py @@ -17,6 +17,7 @@ from keystone.assignment import schema as assignment_schema from keystone.catalog import schema as catalog_schema from keystone.common.validation import validators from keystone import exception +from keystone.identity import schema as identity_schema from keystone.resource import schema as resource_schema from keystone.tests import unit @@ -302,3 +303,60 @@ class ServiceValidationTestCase(unit.BaseTestCase): self.assertRaises(exception.SchemaValidationError, self.create_validator.validate, request) + + +class UserValidationTestCase(unit.BaseTestCase): + """Test for V2 User API Validation.""" + + def setUp(self): + super(UserValidationTestCase, self).setUp() + + schema_user_update = identity_schema.user_update_v2 + self.update_validator = validators.SchemaValidator(schema_user_update) + + def test_validate_user_update_succeeds_with_name(self): + request = { + 'name': uuid.uuid4().hex, + 'enabled': True + } + self.update_validator.validate(request) + + def test_validate_user_update_succeeds_with_username(self): + request = { + 'username': uuid.uuid4().hex, + 'enabled': True + } + self.update_validator.validate(request) + + def test_validate_user_update_succeeds_with_no_params(self): + request = {} + self.update_validator.validate(request) + + def test_validate_user_update_fails_with_invalid_name(self): + for invalid_name in _INVALID_NAMES: + request = { + 'name': invalid_name + } + self.assertRaises(exception.SchemaValidationError, + self.update_validator.validate, + request) + + def test_validate_user_update_with_enabled(self): + """Validate `enabled` as boolean-like values.""" + for valid_enabled in _VALID_ENABLED_FORMATS: + request = { + 'name': uuid.uuid4().hex, + 'enabled': valid_enabled + } + self.update_validator.validate(request) + + def test_validate_user_update_with_invalid_enabled_fails(self): + """Exception is raised when `enabled` isn't a boolean-like value.""" + for invalid_enabled in _INVALID_ENABLED_FORMATS: + request = { + 'name': uuid.uuid4().hex, + 'enabled': invalid_enabled + } + self.assertRaises(exception.SchemaValidationError, + self.update_validator.validate, + request)