Repository: wagtail/wagtail

Issue:
Wagtail doesn't gracefully support session invalidation on password change
According to [Django's documentation](https://docs.djangoproject.com/en/1.7/topics/auth/default/#session-invalidation-on-password-change), SessionAuthenticationMiddleware is new in Django 1.7, enabled by default, and will be mandatory in Django 2.0.

Currently, when the middleware is loaded and the user changes their password, they are immediately kicked out to the sign in screen. The user's session is most likely invalidated. This is very obtrusive and the user is not informed if their password was successfully updated. I believe the offending code is in
[account.py](https://github.com/torchbox/wagtail/blob/master/wagtail/wagtailadmin/views/account.py#L26) and attempted to modify the code from the example to make it work, but the outcome was the same:

``` python
# ...
from django.contrib.auth import update_session_auth_hash # new code
# ...
def change_password(request):
    can_change_password = request.user.has_usable_password()

    if can_change_password:
        if request.POST:
            form = SetPasswordForm(request.user, request.POST)

            if form.is_valid():
                form.save()
                update_session_auth_hash(request, form.user) # new code

                messages.success(request, _("Your password has been changed successfully!"))
                return redirect('wagtailadmin_account')
        else:
            form = SetPasswordForm(request.user)
    else:
        form = None

    return render(request, 'wagtailadmin/account/change_password.html', {
        'form': form,
        'can_change_password': can_change_password,
    })
```

I am, currently, a Django novice, so that's as far as I was able to get. Hope this is an easy fix!



Discussion:

Resolving patch:
diff --git a/wagtail/wagtailadmin/views/account.py b/wagtail/wagtailadmin/views/account.py
--- a/wagtail/wagtailadmin/views/account.py
+++ b/wagtail/wagtailadmin/views/account.py
@@ -3,6 +3,7 @@
 from django.contrib import messages
 from django.contrib.auth.forms import SetPasswordForm
 from django.contrib.auth.views import logout as auth_logout, login as auth_login
+from django.contrib.auth import update_session_auth_hash
 from django.utils.translation import ugettext as _ 
 from django.views.decorators.debug import sensitive_post_parameters
 from django.views.decorators.cache import never_cache
@@ -32,6 +33,7 @@ def change_password(request):
 
             if form.is_valid():
                 form.save()
+                update_session_auth_hash(request, form.user)
 
                 messages.success(request, _("Your password has been changed successfully!"))
                 return redirect('wagtailadmin_account')


Test patch:
diff --git a/wagtail/tests/settings.py b/wagtail/tests/settings.py
--- a/wagtail/tests/settings.py
+++ b/wagtail/tests/settings.py
@@ -43,6 +43,7 @@
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',