diff --git a/horizon/exceptions.py b/horizon/exceptions.py index 14b8c3b460..6eafe2d9a0 100644 --- a/horizon/exceptions.py +++ b/horizon/exceptions.py @@ -201,6 +201,7 @@ class HandledException(HorizonException): UNAUTHORIZED = tuple(HORIZON_CONFIG['exceptions']['unauthorized']) +UNAUTHORIZED += (NotAuthorized,) NOT_FOUND = tuple(HORIZON_CONFIG['exceptions']['not_found']) RECOVERABLE = (AlreadyExists, Conflict, NotAvailable, ServiceCatalogException) RECOVERABLE += tuple(HORIZON_CONFIG['exceptions']['recoverable']) @@ -279,7 +280,8 @@ def handle_recoverable(request, message, redirect, ignore, escalate, handled, HANDLE_EXC_METHODS = [ - {'exc': UNAUTHORIZED, 'handler': handle_unauthorized, 'set_wrap': False}, + {'exc': UNAUTHORIZED, 'handler': handle_unauthorized, + 'set_wrap': False, 'escalate': True}, {'exc': NOT_FOUND, 'handler': handle_notfound, 'set_wrap': True}, {'exc': RECOVERABLE, 'handler': handle_recoverable, 'set_wrap': True}, ] @@ -346,7 +348,8 @@ def handle(request, message=None, redirect=None, ignore=False, if exc_handler['set_wrap']: wrap = True handler = exc_handler['handler'] - ret = handler(request, message, redirect, ignore, escalate, + ret = handler(request, message, redirect, ignore, + exc_handler.get('escalate', escalate), handled, force_silence, force_log, log_method, log_entry, log_level) if ret: diff --git a/horizon/middleware.py b/horizon/middleware.py index 885489e5c5..d39f4da265 100644 --- a/horizon/middleware.py +++ b/horizon/middleware.py @@ -158,6 +158,12 @@ class HorizonMiddleware(object): login_url = request.build_absolute_uri(auth_url) response = redirect_to_login(next_url, login_url=login_url, redirect_field_name=field_name) + if isinstance(exception, exceptions.NotAuthorized): + logout_reason = _("Unauthorized. Please try logging in again.") + utils.add_logout_reason(request, response, logout_reason) + # delete messages, created in get_data() method + # since we are going to redirect user to the login page + response.delete_cookie('messages') if request.is_ajax(): response_401 = http.HttpResponse(status=401) diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py index 10c43fde7a..6dd984caed 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py @@ -17,10 +17,12 @@ # under the License. import json +import logging import sys import django from django.conf import settings +from django.contrib.auth import REDIRECT_FIELD_NAME # noqa from django.core.urlresolvers import reverse from django.forms import widgets from django import http @@ -889,9 +891,18 @@ class InstanceTests(helpers.TestCase): url = reverse('horizon:project:instances:detail', args=[server.id]) - res = self.client.get(url) - self.assertRedirectsNoFollow(res, INDEX_URL) + # Avoid the log message in the test + # when unauthorized exception will be logged + logging.disable(logging.ERROR) + res = self.client.get(url) + logging.disable(logging.NOTSET) + + self.assertEqual(302, res.status_code) + self.assertEqual(('Location', settings.TESTSERVER + + settings.LOGIN_URL + '?' + + REDIRECT_FIELD_NAME + '=' + url), + res._headers.get('location', None),) def test_instance_details_flavor_not_found(self): server = self.servers.first() diff --git a/openstack_dashboard/dashboards/project/overview/tests.py b/openstack_dashboard/dashboards/project/overview/tests.py index 97ae955de9..e382488008 100644 --- a/openstack_dashboard/dashboards/project/overview/tests.py +++ b/openstack_dashboard/dashboards/project/overview/tests.py @@ -17,7 +17,10 @@ # under the License. import datetime +import logging +from django.conf import settings +from django.contrib.auth import REDIRECT_FIELD_NAME # noqa from django.core.urlresolvers import reverse from django import http from django.utils import timezone @@ -140,18 +143,32 @@ class UsageViewTests(test.TestCase): self._common_assertions(nova_stu_enabled, maxTotalFloatingIps=10) + @test.create_stubs({api.nova: ('usage_get', + 'extension_supported')}) + def _stub_nova_api_calls_unauthorized(self, exception): + api.nova.extension_supported( + 'SimpleTenantUsage', IsA(http.HttpRequest)) \ + .AndReturn(True) + self._nova_stu_enabled(exception) + def test_unauthorized(self): - self._stub_nova_api_calls( - stu_exception=self.exceptions.nova_unauthorized) - self._stub_neutron_api_calls() - self._stub_cinder_api_calls() + self._stub_nova_api_calls_unauthorized( + self.exceptions.nova_unauthorized) self.mox.ReplayAll() url = reverse('horizon:project:overview:index') + + # Avoid the log message in the test + # when unauthorized exception will be logged + logging.disable(logging.ERROR) res = self.client.get(url) - self.assertTemplateUsed(res, 'project/overview/usage.html') - self.assertMessageCount(res, error=1) - self.assertContains(res, 'Unauthorized:') + logging.disable(logging.NOTSET) + + self.assertEqual(302, res.status_code) + self.assertEqual(('Location', settings.TESTSERVER + + settings.LOGIN_URL + '?' + + REDIRECT_FIELD_NAME + '=' + url), + res._headers.get('location', None),) def test_usage_csv(self): self._test_usage_csv(nova_stu_enabled=True)