Implement validation on Credential V3

Use jsonschema to validate create and update operations on V3
Credentials.

bp: api-validation

Change-Id: Ib61902ce6bf037b2185c405de7b407ad49ed423b
This commit is contained in:
Lance Bragstad 2014-07-23 19:47:02 +00:00 committed by Steve Martinelli
parent 28f60cfa69
commit 67289e689a
4 changed files with 145 additions and 4 deletions

View File

@ -16,6 +16,8 @@ import hashlib
from keystone.common import controller
from keystone.common import dependency
from keystone.common import validation
from keystone.credential import schema
from keystone import exception
from keystone.i18n import _
from keystone.openstack.common import jsonutils
@ -58,6 +60,7 @@ class CredentialV3(controller.V3Controller):
return super(CredentialV3, self)._assign_unique_id(ref)
@controller.protected()
@validation.validated(schema.credential_create, 'credential')
def create_credential(self, context, credential):
trust_id = self._get_trust_id_for_request(context)
ref = self._assign_unique_id(self._normalize_dict(credential),
@ -92,6 +95,7 @@ class CredentialV3(controller.V3Controller):
return CredentialV3.wrap_member(context, ret_ref)
@controller.protected()
@validation.validated(schema.credential_update, 'credential')
def update_credential(self, context, credential_id, credential):
self._require_matching_id(credential_id, credential)

View File

@ -0,0 +1,41 @@
# 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.
_credential_properties = {
'blob': {
'type': 'string'
},
'project_id': {
'type': 'string'
},
'type': {
'type': 'string'
},
'user_id': {
'type': 'string'
}
}
credential_create = {
'type': 'object',
'properties': _credential_properties,
'required': ['blob', 'type', 'user_id'],
'additionalProperties': True
}
credential_update = {
'type': 'object',
'properties': _credential_properties,
'minProperties': 1,
'additionalProperties': True
}

View File

@ -316,11 +316,16 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase,
ref['domain_id'] = domain_id
return ref
def new_credential_ref(self, user_id, project_id=None):
ref = self.new_ref()
def new_credential_ref(self, user_id, project_id=None, cred_type=None):
ref = dict()
ref['id'] = uuid.uuid4().hex
ref['user_id'] = user_id
ref['blob'] = uuid.uuid4().hex
ref['type'] = uuid.uuid4().hex
if cred_type == 'ec2':
ref['type'] = 'ec2'
ref['blob'] = {'blah': 'test'}
else:
ref['type'] = 'cert'
ref['blob'] = uuid.uuid4().hex
if project_id:
ref['project_id'] = project_id
return ref
@ -967,6 +972,7 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase,
resp,
'credentials',
self.assertValidCredential,
keys_to_check=['blob', 'user_id', 'type'],
*args,
**kwargs)
@ -975,6 +981,7 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase,
resp,
'credential',
self.assertValidCredential,
keys_to_check=['blob', 'user_id', 'type'],
*args,
**kwargs)

View File

@ -19,6 +19,7 @@ from keystone.assignment import schema as assignment_schema
from keystone.common import validation
from keystone.common.validation import parameter_types
from keystone.common.validation import validators
from keystone.credential import schema as credential_schema
from keystone import exception
from keystone.policy import schema as policy_schema
@ -610,3 +611,91 @@ class PolicyValidationTestCase(testtools.TestCase):
self.assertRaises(exception.SchemaValidationError,
self.update_policy_validator.validate,
request_to_validate)
class CredentialValidationTestCase(testtools.TestCase):
"""Test for V3 Credential API validation."""
def setUp(self):
super(CredentialValidationTestCase, self).setUp()
create = credential_schema.credential_create
update = credential_schema.credential_update
self.create_credential_validator = validators.SchemaValidator(create)
self.update_credential_validator = validators.SchemaValidator(update)
def test_validate_credential_succeeds(self):
"""Test that we validate a credential request."""
request_to_validate = {'blob': 'some string',
'project_id': uuid.uuid4().hex,
'type': 'ec2',
'user_id': uuid.uuid4().hex}
self.create_credential_validator.validate(request_to_validate)
def test_validate_credential_without_blob_fails(self):
"""Exception raised without `blob` in create request."""
request_to_validate = {'type': 'ec2',
'user_id': uuid.uuid4().hex}
self.assertRaises(exception.SchemaValidationError,
self.create_credential_validator.validate,
request_to_validate)
def test_validate_credential_without_user_id_fails(self):
"""Exception raised without `user_id` in create request."""
request_to_validate = {'blob': 'some credential blob',
'type': 'ec2'}
self.assertRaises(exception.SchemaValidationError,
self.create_credential_validator.validate,
request_to_validate)
def test_validate_credential_without_type_fails(self):
"""Exception raised without `type` in create request."""
request_to_validate = {'blob': 'some credential blob',
'user_id': uuid.uuid4().hex}
self.assertRaises(exception.SchemaValidationError,
self.create_credential_validator.validate,
request_to_validate)
def test_validate_credential_with_types_succeeds(self):
"""Test that credential type works for ec2 and cert."""
cred_types = ['ec2', 'cert', uuid.uuid4().hex]
for c_type in cred_types:
request_to_validate = {'blob': 'some blob',
'type': c_type,
'user_id': uuid.uuid4().hex}
# Make sure an exception isn't raised
self.create_credential_validator.validate(request_to_validate)
def test_validate_credential_with_extra_parameters_succeeds(self):
"""Validate create request with extra parameters."""
request_to_validate = {'blob': 'some string',
'extra': False,
'project_id': uuid.uuid4().hex,
'type': 'ec2',
'user_id': uuid.uuid4().hex}
self.create_credential_validator.validate(request_to_validate)
def test_validate_credential_update_succeeds(self):
"""Test that a credential request is properly validated."""
request_to_validate = {'blob': 'some string',
'project_id': uuid.uuid4().hex,
'type': 'ec2',
'user_id': uuid.uuid4().hex}
self.update_credential_validator.validate(request_to_validate)
def test_validate_credential_update_without_parameters_fails(self):
"""Exception is raised on update without parameters."""
request_to_validate = {}
self.assertRaises(exception.SchemaValidationError,
self.update_credential_validator.validate,
request_to_validate)
def test_validate_credential_update_with_extra_parameters_succeeds(self):
"""Validate credential update with extra parameters."""
request_to_validate = {'blob': 'some string',
'extra': False,
'project_id': uuid.uuid4().hex,
'type': 'ec2',
'user_id': uuid.uuid4().hex}
self.update_credential_validator.validate(request_to_validate)