From 0fa0fd006662420b8f77ad0c6bd909126fccbaab Mon Sep 17 00:00:00 2001 From: Yves-Gwenael Bourhis Date: Tue, 8 Oct 2013 18:53:25 +0200 Subject: [PATCH] Logging user out after self password change Admin users where not logged out after changing their own password in the user settings pannel, and error messages where displayed afterwards. Fixes bug 1226829 Change-Id: Iec0e34484e2bbc28a300d6259aab1a682e4a00ff (cherry-picked from commit 0aab590) --- horizon/middleware.py | 11 +++++++++++ horizon/static/horizon/js/horizon.modals.js | 8 ++++++-- horizon/utils/functions.py | 16 ++++++++++++++++ openstack_dashboard/api/keystone.py | 14 +++++++++++--- .../dashboards/admin/users/forms.py | 11 ++++++++--- 5 files changed, 52 insertions(+), 8 deletions(-) diff --git a/horizon/middleware.py b/horizon/middleware.py index c2a1344961..6cd9d420a8 100644 --- a/horizon/middleware.py +++ b/horizon/middleware.py @@ -122,11 +122,22 @@ class HorizonMiddleware(object): getattr(django_messages, tag)(request, message, extra_tags) if response['location'].startswith(settings.LOGOUT_URL): redirect_response = http.HttpResponse(status=401) + # This header is used for handling the logout in JS + redirect_response['logout'] = True if self.logout_reason is not None: utils.add_logout_reason( request, redirect_response, self.logout_reason) else: redirect_response = http.HttpResponse() + # Copy cookies from HttpResponseRedirect towards HttpResponse + for cookie_name, cookie in response.cookies.iteritems(): + cookie_kwargs = dict(( + (key, value) for key, value in cookie.iteritems() + if key in ('max_age', 'expires', 'path', 'domain', + 'secure', 'httponly') and value + )) + redirect_response.set_cookie( + cookie_name, cookie.value, **cookie_kwargs) redirect_response['X-Horizon-Location'] = response['location'] return redirect_response if queued_msgs: diff --git a/horizon/static/horizon/js/horizon.modals.js b/horizon/static/horizon/js/horizon.modals.js index a47b706d2d..23bbdc2495 100644 --- a/horizon/static/horizon/js/horizon.modals.js +++ b/horizon/static/horizon/js/horizon.modals.js @@ -121,8 +121,12 @@ horizon.addInitFunction(function() { } }, error: function (jqXHR, status, errorThrown) { - $form.closest(".modal").modal("hide"); - horizon.alert("error", gettext("There was an error submitting the form. Please try again.")); + if (jqXHR.getResponseHeader('logout')) { + location.href = jqXHR.getResponseHeader("X-Horizon-Location"); + } else { + $form.closest(".modal").modal("hide"); + horizon.alert("error", gettext("There was an error submitting the form. Please try again.")); + } } }); }); diff --git a/horizon/utils/functions.py b/horizon/utils/functions.py index 1144d17e18..adc1737b8e 100644 --- a/horizon/utils/functions.py +++ b/horizon/utils/functions.py @@ -1,5 +1,8 @@ import math +from django.conf import settings # noqa +from django.contrib.auth import logout # noqa +from django import http from django.utils.encoding import force_unicode # noqa from django.utils.functional import lazy # noqa from django.utils import translation @@ -24,3 +27,16 @@ def add_logout_reason(request, response, reason): with translation.override(lang): reason = unicode(reason).encode('utf-8') response.set_cookie('logout_reason', reason, max_age=30) + + +def logout_with_message(request, msg): + """Send HttpResponseRedirect to LOGOUT_URL. + + `msg` is a message displayed on the login page after the logout, to explain + the logout reson. + """ + logout(request) + response = http.HttpResponseRedirect( + '%s?next=%s' % (settings.LOGOUT_URL, request.path)) + add_logout_reason(request, response, msg) + return response diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py index 16dbfb5ec1..3a178648b2 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -23,7 +23,6 @@ import logging import urlparse from django.conf import settings # noqa -from django.contrib.auth import logout # noqa from django.utils.translation import ugettext_lazy as _ # noqa from keystoneclient import exceptions as keystone_exceptions @@ -32,6 +31,7 @@ from openstack_auth import backend from horizon import exceptions from horizon import messages +from horizon.utils import functions as utils from openstack_dashboard.api import base @@ -354,8 +354,11 @@ def user_update(request, user, **data): if password: try: user_update_password(request, user, password) - if user == request.user.id: - logout(request) + if user.id == request.user.id: + return utils.logout_with_message( + request, + _("Password changed. Please log in again to continue.") + ) except Exception: error = exceptions.handle(request, ignore=True) @@ -367,6 +370,11 @@ def user_update(request, user, **data): if not data['password']: data.pop('password') user = manager.update(user, **data) + if data.get('password') and user.id == request.user.id: + return utils.logout_with_message( + request, + _("Password changed. Please log in again to continue.") + ) return VERSIONS.upgrade_v2_user(user) diff --git a/openstack_dashboard/dashboards/admin/users/forms.py b/openstack_dashboard/dashboards/admin/users/forms.py index 6edeabb220..803b1c008a 100644 --- a/openstack_dashboard/dashboards/admin/users/forms.py +++ b/openstack_dashboard/dashboards/admin/users/forms.py @@ -21,6 +21,7 @@ import logging from django.forms import ValidationError # noqa +from django import http from django.utils.translation import ugettext_lazy as _ # noqa from django.views.decorators.debug import sensitive_variables # noqa @@ -185,10 +186,14 @@ class UpdateUserForm(BaseUserForm): data.pop('domain_name') try: - api.keystone.user_update(request, user, **data) + response = api.keystone.user_update(request, user, **data) messages.success(request, _('User has been updated successfully.')) except Exception: - exceptions.handle(request, ignore=True) + response = exceptions.handle(request, ignore=True) messages.error(request, _('Unable to update the user.')) - return True + + if isinstance(response, http.HttpResponse): + return response + else: + return True