From 28f60cfa693c8c0a04d0cc1d895d472d4e7c940c Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Wed, 23 Jul 2014 20:01:32 +0000 Subject: [PATCH] Implement validation on Policy V3 API Use JSONSchema to validate create and update operations on V3 Policy API. Change-Id: I43146fce5018330eba2119194325bde29e4759bb bp: api-validation --- keystone/policy/controllers.py | 6 ++- keystone/policy/schema.py | 36 +++++++++++++++ keystone/tests/test_validation.py | 76 +++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 keystone/policy/schema.py diff --git a/keystone/policy/controllers.py b/keystone/policy/controllers.py index 44b9a47255..f8d3657f75 100644 --- a/keystone/policy/controllers.py +++ b/keystone/policy/controllers.py @@ -14,6 +14,8 @@ from keystone.common import controller from keystone.common import dependency +from keystone.common import validation +from keystone.policy import schema @dependency.requires('policy_api') @@ -22,10 +24,9 @@ class PolicyV3(controller.V3Controller): member_name = 'policy' @controller.protected() + @validation.validated(schema.policy_create, 'policy') def create_policy(self, context, policy): ref = self._assign_unique_id(self._normalize_dict(policy)) - self._require_attribute(ref, 'blob') - self._require_attribute(ref, 'type') ref = self.policy_api.create_policy(ref['id'], ref) return PolicyV3.wrap_member(context, ref) @@ -42,6 +43,7 @@ class PolicyV3(controller.V3Controller): return PolicyV3.wrap_member(context, ref) @controller.protected() + @validation.validated(schema.policy_update, 'policy') def update_policy(self, context, policy_id, policy): ref = self.policy_api.update_policy(policy_id, policy) return PolicyV3.wrap_member(context, ref) diff --git a/keystone/policy/schema.py b/keystone/policy/schema.py new file mode 100644 index 0000000000..512c4ce7a1 --- /dev/null +++ b/keystone/policy/schema.py @@ -0,0 +1,36 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +_policy_properties = { + 'blob': { + 'type': 'string' + }, + 'type': { + 'type': 'string', + 'maxLength': 255 + } +} + +policy_create = { + 'type': 'object', + 'properties': _policy_properties, + 'required': ['blob', 'type'], + 'additionalProperties': True +} + +policy_update = { + 'type': 'object', + 'properties': _policy_properties, + 'minProperties': 1, + 'additionalProperties': True +} diff --git a/keystone/tests/test_validation.py b/keystone/tests/test_validation.py index c8ab1f63f9..3c4a11a36d 100644 --- a/keystone/tests/test_validation.py +++ b/keystone/tests/test_validation.py @@ -20,6 +20,7 @@ from keystone.common import validation from keystone.common.validation import parameter_types from keystone.common.validation import validators from keystone import exception +from keystone.policy import schema as policy_schema """Example model to validate create requests against. Assume that this is the only backend for the create and validate schemas. This is just an @@ -534,3 +535,78 @@ class RoleValidationTestCase(testtools.TestCase): self.assertRaises(exception.SchemaValidationError, self.update_role_validator.validate, request_to_validate) + + +class PolicyValidationTestCase(testtools.TestCase): + """Test for V3 Policy API validation.""" + + def setUp(self): + super(PolicyValidationTestCase, self).setUp() + + create = policy_schema.policy_create + update = policy_schema.policy_update + self.create_policy_validator = validators.SchemaValidator(create) + self.update_policy_validator = validators.SchemaValidator(update) + + def test_validate_policy_succeeds(self): + """Test that we validate a create policy request.""" + request_to_validate = {'blob': 'some blob information', + 'type': 'application/json'} + self.create_policy_validator.validate(request_to_validate) + + def test_validate_policy_without_blob_fails(self): + """Exception raised without `blob` in request.""" + request_to_validate = {'type': 'application/json'} + self.assertRaises(exception.SchemaValidationError, + self.create_policy_validator.validate, + request_to_validate) + + def test_validate_policy_without_type_fails(self): + """Exception raised without `type` in request.""" + request_to_validate = {'blob': 'some blob information'} + self.assertRaises(exception.SchemaValidationError, + self.create_policy_validator.validate, + request_to_validate) + + def test_validate_policy_create_with_extra_parameters_succeeds(self): + """Validate policy create with extra parameters.""" + request_to_validate = {'blob': 'some blob information', + 'type': 'application/json', + 'extra': 'some extra stuff'} + self.create_policy_validator.validate(request_to_validate) + + def test_validate_policy_create_with_invalid_type_fails(self): + """Exception raised when `blob` and `type` are boolean.""" + for prop in ['blob', 'type']: + request_to_validate = {prop: False} + self.assertRaises(exception.SchemaValidationError, + self.create_policy_validator.validate, + request_to_validate) + + def test_validate_policy_update_without_parameters_fails(self): + """Exception raised when updating policy without parameters.""" + request_to_validate = {} + self.assertRaises(exception.SchemaValidationError, + self.update_policy_validator.validate, + request_to_validate) + + def test_validate_policy_update_with_extra_parameters_succeeds(self): + """Validate policy update request with extra parameters.""" + request_to_validate = {'blob': 'some blob information', + 'type': 'application/json', + 'extra': 'some extra stuff'} + self.update_policy_validator.validate(request_to_validate) + + def test_validate_policy_update_succeeds(self): + """Test that we validate a policy update request.""" + request_to_validate = {'blob': 'some blob information', + 'type': 'application/json'} + self.update_policy_validator.validate(request_to_validate) + + def test_validate_policy_update_with_invalid_type_fails(self): + """Exception raised when invalid `type` on policy update.""" + for prop in ['blob', 'type']: + request_to_validate = {prop: False} + self.assertRaises(exception.SchemaValidationError, + self.update_policy_validator.validate, + request_to_validate)