diff --git a/api/base.py b/api/base.py index 36056990c..a3e385ca0 100644 --- a/api/base.py +++ b/api/base.py @@ -9,6 +9,7 @@ from . import util from . import config +from . import validators log = config.log @@ -128,6 +129,8 @@ def handle_exception(self, exception, debug): # Otherwise use a generic 500 error code. if isinstance(exception, webapp2.HTTPException): code = exception.code + elif isinstance(exception, validators.InputValidationException): + code = 400 else: code = 500 util.send_json_http_exception(self.response, str(exception), code) diff --git a/api/handlers/containerhandler.py b/api/handlers/containerhandler.py index ab35e96e0..2a156383f 100644 --- a/api/handlers/containerhandler.py +++ b/api/handlers/containerhandler.py @@ -308,8 +308,8 @@ def get_groups_with_project(self): def _get_validators(self): - mongo_validator = validators.mongo_from_schema_file(self, self.config.get('storage_schema_file')) - payload_validator = validators.payload_from_schema_file(self, self.config.get('payload_schema_file')) + mongo_validator = validators.mongo_from_schema_file(self.config.get('storage_schema_file')) + payload_validator = validators.payload_from_schema_file(self.config.get('payload_schema_file')) return mongo_validator, payload_validator def _get_parent_container(self, payload): diff --git a/api/handlers/grouphandler.py b/api/handlers/grouphandler.py index e1bcde0aa..db62be4e2 100644 --- a/api/handlers/grouphandler.py +++ b/api/handlers/grouphandler.py @@ -58,8 +58,8 @@ def put(self, _id): self.abort(404, 'no such Group: ' + _id) permchecker = groupauth.default(self, group) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'group.json') - payload_validator = validators.payload_from_schema_file(self, 'group.json') + mongo_validator = validators.mongo_from_schema_file('group.json') + payload_validator = validators.payload_from_schema_file('group.json') payload_validator(payload, 'PUT') result = mongo_validator(permchecker(self.storage.exec_op))('PUT', _id=_id, payload=payload) if result.modified_count == 1: @@ -71,8 +71,8 @@ def post(self): self._init_storage() permchecker = groupauth.default(self, None) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'group.json') - payload_validator = validators.payload_from_schema_file(self, 'group.json') + mongo_validator = validators.mongo_from_schema_file('group.json') + payload_validator = validators.payload_from_schema_file('group.json') payload_validator(payload, 'POST') payload['created'] = payload['modified'] = datetime.datetime.utcnow() payload['roles'] = [{'_id': self.uid, 'access': 'admin', 'site': self.user_site}] diff --git a/api/handlers/listhandler.py b/api/handlers/listhandler.py index 7abc40ae2..ff9c9a538 100644 --- a/api/handlers/listhandler.py +++ b/api/handlers/listhandler.py @@ -181,9 +181,9 @@ def _initialize_request(self, cont_name, list_name, _id, query_params=None): permchecker = permchecker(self, container) else: self.abort(404, 'Element {} not found in container {}'.format(_id, storage.cont_name)) - mongo_validator = validators.mongo_from_schema_file(self, config.get('storage_schema_file')) - input_validator = validators.payload_from_schema_file(self, config.get('input_schema_file')) - keycheck = validators.key_check(self, config.get('storage_schema_file')) + mongo_validator = validators.mongo_from_schema_file(config.get('storage_schema_file')) + input_validator = validators.payload_from_schema_file(config.get('input_schema_file')) + keycheck = validators.key_check(config.get('storage_schema_file')) return container, permchecker, storage, mongo_validator, input_validator, keycheck diff --git a/api/handlers/userhandler.py b/api/handlers/userhandler.py index 608087f7c..42b6e65e6 100644 --- a/api/handlers/userhandler.py +++ b/api/handlers/userhandler.py @@ -64,8 +64,8 @@ def put(self, _id): user = self._get_user(_id) permchecker = userauth.default(self, user) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'user.json') - payload_validator = validators.payload_from_schema_file(self, 'user.json') + mongo_validator = validators.mongo_from_schema_file('user.json') + payload_validator = validators.payload_from_schema_file('user.json') payload_validator(payload, 'PUT') payload['modified'] = datetime.datetime.utcnow() result = mongo_validator(permchecker(self.storage.exec_op))('PUT', _id=_id, payload=payload) @@ -78,8 +78,8 @@ def post(self): self._init_storage() permchecker = userauth.default(self) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'user.json') - payload_validator = validators.payload_from_schema_file(self, 'user.json') + mongo_validator = validators.mongo_from_schema_file('user.json') + payload_validator = validators.payload_from_schema_file('user.json') payload_validator(payload, 'POST') payload['created'] = payload['modified'] = datetime.datetime.utcnow() payload['root'] = payload.get('root', False) diff --git a/api/upload.py b/api/upload.py index 3ec641dfb..a72d2a312 100644 --- a/api/upload.py +++ b/api/upload.py @@ -62,7 +62,7 @@ def uploader(self): self.abort(400, str(e)) if not file_store.metadata: self.abort(400, 'metadata is missing') - metadata_validator = validators.payload_from_schema_file(self, 'uploader.json') + metadata_validator = validators.payload_from_schema_file('uploader.json') metadata_validator(file_store.metadata, 'POST') try: target_containers = reaperutil.create_root_to_leaf_hierarchy(file_store.metadata, file_store.files) @@ -108,7 +108,7 @@ def engine(self): self.abort(400, str(e)) if not file_store.metadata: self.abort(400, 'metadata is missing') - metadata_validator = validators.payload_from_schema_file(self, 'enginemetadata.json') + metadata_validator = validators.payload_from_schema_file('enginemetadata.json') metadata_validator(file_store.metadata, 'POST') file_infos = file_store.metadata['acquisition'].pop('files', []) now = datetime.datetime.utcnow() diff --git a/api/validators.py b/api/validators.py index d31b0e587..ede73c5a0 100644 --- a/api/validators.py +++ b/api/validators.py @@ -6,6 +6,12 @@ log = config.log +class InputValidationException(Exception): + pass + +class DBValidationException(Exception): + pass + # following https://github.com/Julian/jsonschema/issues/98 # json schema files are expected to be in the schemas folder relative to this module schema_path = os.path.abspath(os.path.dirname(__file__)) @@ -69,7 +75,7 @@ def _validate_json(json_data, schema, resolver): def no_op(g, *args): return g -def mongo_from_schema_file(handler, schema_file): +def mongo_from_schema_file(schema_file): if schema_file is None: return no_op schema = resolver_mongo.resolve(schema_file)[1] @@ -86,12 +92,12 @@ def mongo_val(method, **kwargs): try: _validate_json(payload, _schema, resolver_mongo) except jsonschema.ValidationError as e: - handler.abort(500, str(e)) + raise DBValidationException(str(e)) return exec_op(method, **kwargs) return mongo_val return g -def payload_from_schema_file(handler, schema_file): +def payload_from_schema_file(schema_file): if schema_file is None: return no_op schema = resolver_input.resolve(schema_file)[1] @@ -105,10 +111,10 @@ def g(payload, method): try: _validate_json(payload, _schema, resolver_input) except jsonschema.ValidationError as e: - handler.abort(400, str(e)) + raise InputValidationException(str(e)) return g -def key_check(handler, schema_file): +def key_check(schema_file): """ for sublists of mongo container there is no automatic key check when creating, updating or deleting an object. We are adding a custom array field to the json schemas ("key_fields"). @@ -135,7 +141,7 @@ def f(method, _id, query_params = None, payload = None, exclude_params=None): try: exclude_params = _post_exclude_params(schema.get('key_fields', []), payload) except KeyError as e: - handler.abort(400, 'missing key {} in payload'.format(e.args)) + raise InputValidationException('missing key {} in payload'.format(e.args)) else: _check_query_params(schema.get('key_fields'), query_params) if method == 'PUT' and schema.get('key_fields'):