I am trying to send an oauth request from another application to Django. Django is hosted on 8000 port and the application on 8080. Here is the URL called from the application:
http://localhost:8000/o/authorize/?client_id=MM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG&response_type=token&redirect_url=http://localhost:8080/auth/add_token
This will get redirected to a wrong location:
http://192.168.56.101:8000/o/authorize/accounts/login/?next=/o/authorize/%3Fclient_id%3DMM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG%26response_type%3Dtoken%26redirect_url%3Dhttp%3A//192.168.56.101%3A8080/auth/add_token
when I expect it to be without the prefix /o/authorize
which is is generated by WSGI handler using HTTP header called PATH_INFO:
http://192.168.56.101:8000/accounts/login/?next=/o/authorize/%3Fclient_id%3DMM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG%26response_type%3Dtoken%26redirect_url%3Dhttp%3A//192.168.56.101%3A8080/auth/add_token
I have following routes in urls.py and they work properly if it is not for the weird redirection I am facing.
url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
# OAuth User Info
url(r'^o/api/get_userinfo/$', oauth2.GetuserInfoView.as_view(), name="get-userinfo"),
In settings.py I have:
LOGIN_URL = "/accounts/login"
Now here are the lines of Django code that I find problematic.
django/core/handlers/base.py:220
# Apply response middleware, regardless of the response
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
# Complain if the response middleware returned None (a common error).
if response is None:
raise ValueError(
"%s.process_response didn't return an "
"HttpResponse object. It returned None instead."
% (middleware_method.__self__.__class__.__name__))
response = self.apply_response_fixes(request, response)
# ^^^------------this will lead to fix_location_header being called.
django/http/utils.py
def fix_location_header(request, response):
"""
Ensures that we always use an absolute URI in any location header in the
response. This is required by RFC 2616, section 14.30.
Code constructing response objects is free to insert relative paths, as
this function converts them to absolute paths.
"""
if 'Location' in response:
response['Location'] = request.build_absolute_uri(response['Location'])
return response
django/request.py
def build_absolute_uri(self, location=None):
"""
Builds an absolute URI from the location and the variables available in
this request. If no ``location`` is specified, the absolute URI is
built on ``request.get_full_path()``. Anyway, if the location is
absolute, it is simply converted to an RFC 3987 compliant URI and
returned and if location is relative or is scheme-relative (i.e.,
``//example.com/``), it is urljoined to a base URL constructed from the
request variables.
"""
if location is None:
# Make it an absolute url (but schemeless and domainless) for the
# edge case that the path starts with '//'.
location = '//%s' % self.get_full_path()
bits = urlsplit(location)
if not (bits.scheme and bits.netloc):
current_uri = '{scheme}://{host}{path}'.format(scheme=self.scheme,
host=self.get_host(),
path=self.path)
# ^^^---The location URL forming logic that I find problematic.
# Join the constructed URL with the provided location, which will
# allow the provided ``location`` to apply query strings to the
# base path as well as override the host, if it begins with //
location = urljoin(current_uri, location)
return iri_to_uri(location)
I included the comments from the source file so the reader could know there are use cases for them.
So what is the proper way of getting around apply_reponse_fix
? 1) inherit and rewrite the function 2) modify HTTP header PATH_INFO... somehow 3) change the logic for Location
header in response so that it is a full URI with http://
prefix so that bits.scheme
is not None. None of them seem like a proper fix for me, so I am wondering if I overlooked a convention. Any insight will be very helpful.