Source code for keystone.server.flask.request_processing.json_body

# 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.

# Before request processing for JSON Body enforcement

import flask
from werkzeug import exceptions as werkzeug_exceptions

from keystone import exception
from keystone.i18n import _
from keystone.server.flask import common as ks_flask_common


[docs]def json_body_before_request(): """Enforce JSON Request Body.""" # TODO(morgan): Allow other content-types when OpenAPI Doc or improved # federation is implemented for known/valid paths. This function should # be removed long term. # exit if there is nothing to be done, (no body) if not flask.request.get_data(): return None elif flask.request.path and flask.request.path.startswith( '/v3/OS-OAUTH2/'): # When the user makes a request to the OAuth2.0 token endpoint, # the user should use the "application/x-www-form-urlencoded" format # with a character encoding of UTF-8 in the HTTP request entity-body. # At the scenario there is nothing to be done and exit. return None try: # flask does loading for us for json, use the flask default loader # in the case that the data is *not* json or a dict, we should see a # raise of werkzeug.exceptions.BadRequest, re-spin this to the keystone # ValidationError message (as expected by our contract) # Explicitly check if the content is supposed to be json. if (flask.request.is_json or flask.request.headers.get('Content-Type', '') == ''): json_decoded = flask.request.get_json(force=True) if not isinstance(json_decoded, dict): # In the case that the returned value was not a dict, force # a raise that will be caught the same way that a Decode error # would be handled. raise werkzeug_exceptions.BadRequest( _('resulting JSON load was not a dict')) else: # We no longer need enforcement on this API, set unenforced_ok # we already hit a validation error. This is required as the # request is never hitting the resource methods, meaning # @unenforced_api is not called. Without marking the request # as "unenforced_ok" the assertion check to ensure enforcement # was called would raise up causing a 500 error. ks_flask_common.set_unenforced_ok() raise exception.ValidationError(attribute='application/json', target='Content-Type header') except werkzeug_exceptions.BadRequest: # We no longer need enforcement on this API, set unenforced_ok # we already hit a validation error. This is required as the # request is never hitting the resource methods, meaning # @unenforced_api is not called. Without marking the request # as "unenforced_ok" the assertion check to ensure enforcement # was called would raise up causing a 500 error. ks_flask_common.set_unenforced_ok() raise exception.ValidationError(attribute='valid JSON', target='request body')