From 3fbe68f690f86a9e07d054daafedf980217827e9 Mon Sep 17 00:00:00 2001 From: Kieran Spear Date: Fri, 16 Nov 2012 17:20:51 +1100 Subject: [PATCH] Honour LOGIN_URL when redirecting to login page Currently the redirect is always made to the url of the 'login' view. This change makes redirects go to LOGIN_URL, so the default login view can be replaced with a view at another url/name. Fixes bug 1079444. Change-Id: Ib56200679668dd053d3c6ac24807d2a2affc0df8 --- horizon/middleware.py | 17 ++++++++++------ horizon/test/tests/base.py | 7 +++---- horizon/test/tests/middleware.py | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 horizon/test/tests/middleware.py diff --git a/horizon/middleware.py b/horizon/middleware.py index 9cd2a6a98..edd4359fc 100644 --- a/horizon/middleware.py +++ b/horizon/middleware.py @@ -26,8 +26,10 @@ import logging from django import http from django import shortcuts +from django.conf import settings from django.contrib import messages as django_messages from django.contrib.auth import REDIRECT_FIELD_NAME +from django.contrib.auth.views import redirect_to_login from django.core.urlresolvers import reverse from django.utils import timezone from django.utils.encoding import iri_to_uri @@ -59,20 +61,23 @@ class HorizonMiddleware(object): """ if isinstance(exception, (exceptions.NotAuthorized, exceptions.NotAuthenticated)): - auth_url = reverse("login") + auth_url = settings.LOGIN_URL next_url = iri_to_uri(request.get_full_path()) if next_url != auth_url: - param = "?%s=%s" % (REDIRECT_FIELD_NAME, next_url) - redirect_to = "".join((auth_url, param)) + field_name = REDIRECT_FIELD_NAME else: - redirect_to = auth_url + field_name = None + login_url = request.build_absolute_uri(auth_url) + response = redirect_to_login(next_url, login_url=login_url, + redirect_field_name=field_name) + # TODO(gabriel): Find a way to display an appropriate message to # the user *on* the login form... if request.is_ajax(): response_401 = http.HttpResponse(status=401) - response_401['X-Horizon-Location'] = redirect_to + response_401['X-Horizon-Location'] = response['location'] return response_401 - return shortcuts.redirect(redirect_to) + return response # If an internal "NotFound" error gets this far, return a real 404. if isinstance(exception, exceptions.NotFound): diff --git a/horizon/test/tests/base.py b/horizon/test/tests/base.py index 65b01dc5f..468219d5d 100644 --- a/horizon/test/tests/base.py +++ b/horizon/test/tests/base.py @@ -226,7 +226,7 @@ class HorizonTests(BaseHorizonTests): self.client.logout() resp = self.client.get(url) - redirect_url = "?".join([urlresolvers.reverse("login"), + redirect_url = "?".join(['http://testserver' + settings.LOGIN_URL, "next=%s" % url]) self.assertRedirects(resp, redirect_url) @@ -235,8 +235,7 @@ class HorizonTests(BaseHorizonTests): # Response should be HTTP 401 with redirect header self.assertEquals(resp.status_code, 401) self.assertEquals(resp["X-Horizon-Location"], - "?".join([urlresolvers.reverse("login"), - "next=%s" % url])) + redirect_url) def test_required_permissions(self): dash = horizon.get_dashboard("cats") @@ -275,7 +274,7 @@ class HorizonTests(BaseHorizonTests): dogs = horizon.get_dashboard("dogs") puppies = dogs.get_panel("puppies") url = puppies.get_absolute_url() - redirect_url = "?".join([urlresolvers.reverse("login"), + redirect_url = "?".join([settings.LOGIN_URL, "next=%s" % url]) self.client.logout() diff --git a/horizon/test/tests/middleware.py b/horizon/test/tests/middleware.py new file mode 100644 index 000000000..958e4233f --- /dev/null +++ b/horizon/test/tests/middleware.py @@ -0,0 +1,34 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack LLC. +# All Rights Reserved. +# +# 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. + +from django.conf import settings + +from horizon import exceptions +from horizon import middleware +from horizon.test import helpers as test + + +class MiddlewareTests(test.TestCase): + def test_redirect_login_fail_to_login(self): + url = settings.LOGIN_URL + request = self.factory.post(url) + + mw = middleware.HorizonMiddleware() + resp = mw.process_exception(request, exceptions.NotAuthorized()) + resp.client = self.client + + self.assertRedirects(resp, url)