Properly replace flask view args in links
When the API Prefix is used in a Flask API, it is possible the flask view argument specification will bleed through to the self link instead of a properly formated url. The add_self_reference_links mechanism in keystone.server.flask.common now substitutes out the self link to the {} substitution and applies a .format() utilizing the view args to the URI in the self link. Change-Id: Ic5c89c285ed964de7411b273567bb97fcf43da06 closes-bug: #1794552
This commit is contained in:
parent
30bd48c205
commit
1efecc92c0
|
@ -676,6 +676,14 @@ class ResourceBase(flask_restful.Resource):
|
|||
collection_element = collection_name or cls.collection_key
|
||||
if cls.api_prefix:
|
||||
api_prefix = cls.api_prefix.lstrip('/').rstrip('/')
|
||||
# ensure we have substituted the flask-arg specification
|
||||
# to the "keystone" mechanism, then format the string
|
||||
api_prefix = _URL_SUBST.sub('{\\1}', api_prefix)
|
||||
if flask.request.view_args:
|
||||
# if a prefix has substitutions it is *required* that the
|
||||
# values are passed as view_args to the HTTP action method
|
||||
# (e.g. head/get/post/...).
|
||||
api_prefix = api_prefix.format(**flask.request.view_args)
|
||||
collection_element = '/'.join(
|
||||
[api_prefix, collection_name or cls.collection_key])
|
||||
self_link = base_url(path='/'.join([collection_element, ref['id']]))
|
||||
|
|
|
@ -884,6 +884,8 @@ class TestCase(BaseTestCase):
|
|||
app.register_error_handler(404, page_not_found_teapot)
|
||||
|
||||
self.test_client = app.test_client
|
||||
self.test_request_context = app.test_request_context
|
||||
self.cleanup_instance('test_request_context')
|
||||
self.cleanup_instance('test_client')
|
||||
return keystone_flask.setup_app_middleware(app)
|
||||
|
||||
|
|
|
@ -610,3 +610,34 @@ class TestKeystoneFlaskCommon(rest.RestfulTestCase):
|
|||
self.assertRaises(exception.ValidationError,
|
||||
flask_common.ResourceBase._normalize_domain_id,
|
||||
ref=ref_without_domain_id)
|
||||
|
||||
def test_api_prefix_self_referential_link_substitution(self):
|
||||
|
||||
view_arg = uuid.uuid4().hex
|
||||
|
||||
class TestResource(flask_common.ResourceBase):
|
||||
api_prefix = '/<string:test_value>/nothing'
|
||||
|
||||
# use a dummy request context, no enforcement is happening
|
||||
# therefore we don't need the heavy lifting of a full request
|
||||
# run.
|
||||
with self.test_request_context(
|
||||
path='/%s/nothing/values' % view_arg,
|
||||
base_url='https://localhost/'):
|
||||
# explicitly set the view_args, this is a special case
|
||||
# for a synthetic test case, usually one would rely on
|
||||
# a full request stack to set these.
|
||||
flask.request.view_args = {'test_value': view_arg}
|
||||
|
||||
# create dummy ref
|
||||
ref = {'id': uuid.uuid4().hex}
|
||||
|
||||
# add the self referential link
|
||||
TestResource._add_self_referential_link(
|
||||
ref, collection_name='values')
|
||||
|
||||
# Check that the link in fact starts with what we expect
|
||||
# including the explicit view arg.
|
||||
self.assertTrue(ref['links']['self'].startswith(
|
||||
'https://localhost/v3/%s' % view_arg)
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue