Fix duplicate paths in secret hrefs

Reconstructing the base URL from a request when
host_href is not set must take into account that
an URL path may consist of and endpoint part followed
by a resource path, e.g.:

'http://localhost/key-manager/v1/secrets/25a24d6b-605e-4226-ab39-7e2d8e10f559'

where the endpoint URL is `http://localhost/key-manager/v1`

The pecan.request.application_url is used instead of
pecan.request.url to retrieve the base URL part
(`http://localhost/key-manager/v1`) excluding the resource
path. However, the /v1 version particle is included into the
application_url value because it is implemented by a wsgi
application rather than a pecan controller, so the /v1 bit
also needs to be removed from the base URL when present.

Change-Id: I3c05f3d2f9a970213ca8347d7bbe1aac203af0a1
Closes-Bug: #1749217
(cherry picked from commit ff55d17034)
This commit is contained in:
Stefan Nica 2018-02-14 17:26:16 +01:00 committed by Matt Riedemann
parent 9314499b2b
commit 27cf2f37f6
2 changed files with 7 additions and 3 deletions

View File

@ -24,6 +24,7 @@ import uuid
from oslo_log import log from oslo_log import log
from oslo_utils import uuidutils from oslo_utils import uuidutils
import pecan import pecan
import re
import six import six
from six.moves.urllib import parse from six.moves.urllib import parse
@ -76,8 +77,8 @@ def get_base_url_from_request():
Some of unit tests does not have pecan context that's why using request Some of unit tests does not have pecan context that's why using request
attr check on pecan instance. attr check on pecan instance.
""" """
if not CONF.host_href and hasattr(pecan.request, 'url'): if not CONF.host_href and hasattr(pecan.request, 'application_url'):
p_url = parse.urlsplit(pecan.request.url) p_url = parse.urlsplit(pecan.request.application_url)
# Pecan does not handle X_FORWARDED_PROTO yet, so we need to # Pecan does not handle X_FORWARDED_PROTO yet, so we need to
# handle it ourselves. see lp#1445290 # handle it ourselves. see lp#1445290
scheme = pecan.request.environ.get('HTTP_X_FORWARDED_PROTO', 'http') scheme = pecan.request.environ.get('HTTP_X_FORWARDED_PROTO', 'http')
@ -86,7 +87,9 @@ def get_base_url_from_request():
netloc = pecan.request.environ.get('HTTP_HOST', p_url.netloc) netloc = pecan.request.environ.get('HTTP_HOST', p_url.netloc)
# FIXME: implement SERVER_NAME lookup if HTTP_HOST is not set # FIXME: implement SERVER_NAME lookup if HTTP_HOST is not set
if p_url.path: if p_url.path:
base_url = '%s://%s%s' % (scheme, netloc, p_url.path) # Remove the version from the path to extract the base path
base_path = re.sub('/v[0-9\.]+$', '', p_url.path)
base_url = '%s://%s%s' % (scheme, netloc, base_path)
else: else:
base_url = '%s://%s' % (scheme, netloc) base_url = '%s://%s' % (scheme, netloc)
return base_url return base_url

View File

@ -50,6 +50,7 @@ def mock_pecan_request(test_instance, host=None):
test_instance.addCleanup(patcher_obj.stop) test_instance.addCleanup(patcher_obj.stop)
mock_req.url = host mock_req.url = host
mock_req.environ = os.environ.copy() mock_req.environ = os.environ.copy()
mock_req.application_url = host
@contextmanager @contextmanager