Merge lp:~rvb/maas/1.5-bug-1298790 into lp:maas/1.5

Proposed by Raphaël Badin on 2014-04-02
Status: Merged
Approved by: Raphaël Badin on 2014-04-02
Approved revision: 2219
Merged at revision: 2219
Proposed branch: lp:~rvb/maas/1.5-bug-1298790
Merge into: lp:maas/1.5
Diff against target: 116 lines (+70/-3)
3 files modified
src/maasserver/templates/maasserver/logout_confirm.html (+21/-0)
src/maasserver/views/account.py (+24/-2)
src/maasserver/views/tests/test_account.py (+25/-1)
To merge this branch: bzr merge lp:~rvb/maas/1.5-bug-1298790
Reviewer Review Type Date Requested Status
MAAS Maintainers 2014-04-02 Pending
Review via email: mp+213794@code.launchpad.net

Commit message

Backport revision 2219: Add a "logout confirmation" page. Using this, the logout action is protected against CSRF attacks because it uses a POST request, in conjunction with Django's CSRF protection feature.

To post a comment you must log in.
Raphaël Badin (rvb) wrote :

Simple backport: self-approving.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'src/maasserver/templates/maasserver/logout_confirm.html'
2--- src/maasserver/templates/maasserver/logout_confirm.html 1970-01-01 00:00:00 +0000
3+++ src/maasserver/templates/maasserver/logout_confirm.html 2014-04-02 09:48:49 +0000
4@@ -0,0 +1,21 @@
5+{% extends "maasserver/base.html" %}
6+
7+{% block nav-active-settings %}active{% endblock %}
8+{% block title %}Logout{% endblock %}
9+{% block page-title %}Logout{% endblock %}
10+
11+{% block content %}
12+ <div class="block auto-width">
13+ <h2>
14+ Are you sure you want to log out?
15+ </h2>
16+ <p>
17+ <form action="." method="post">{% csrf_token %}
18+ <input type="hidden" name="post" value="yes" />
19+ <input type="submit" value="Log out" class="right" />
20+ <a href="{% url 'index' %}">Cancel</a>
21+ </form>
22+ </p>
23+ </div>
24+{% endblock %}
25+
26
27=== modified file 'src/maasserver/views/account.py'
28--- src/maasserver/views/account.py 2013-10-07 09:12:40 +0000
29+++ src/maasserver/views/account.py 2014-04-02 09:48:49 +0000
30@@ -17,6 +17,7 @@
31 "logout",
32 ]
33
34+from django import forms
35 from django.conf import settings as django_settings
36 from django.contrib import messages
37 from django.contrib.auth.views import (
38@@ -25,6 +26,8 @@
39 )
40 from django.core.urlresolvers import reverse
41 from django.http import HttpResponseRedirect
42+from django.shortcuts import render_to_response
43+from django.template import RequestContext
44 from maasserver.models import UserProfile
45
46
47@@ -39,6 +42,25 @@
48 return dj_login(request, extra_context=extra_context)
49
50
51+class LogoutForm(forms.Form):
52+ """Log-out confirmation form.
53+
54+ There is nothing interesting in this form, but it's needed in order
55+ to get Django's CSRF protection during logout.
56+ """
57+
58+
59 def logout(request):
60- messages.info(request, "You have been logged out.")
61- return dj_logout(request, next_page=reverse('login'))
62+ if request.method == 'POST':
63+ form = LogoutForm(request.POST)
64+ if form.is_valid():
65+ messages.info(request, "You have been logged out.")
66+ return dj_logout(request, next_page=reverse('login'))
67+ else:
68+ form = LogoutForm()
69+
70+ return render_to_response(
71+ 'maasserver/logout_confirm.html',
72+ {'form': form},
73+ context_instance=RequestContext(request),
74+ )
75
76=== modified file 'src/maasserver/views/tests/test_account.py'
77--- src/maasserver/views/tests/test_account.py 2014-02-11 22:00:31 +0000
78+++ src/maasserver/views/tests/test_account.py 2014-04-02 09:48:49 +0000
79@@ -15,8 +15,13 @@
80 __all__ = []
81
82 from django.conf import settings
83+from django.contrib.auth import SESSION_KEY
84+from django.core.urlresolvers import reverse
85 from lxml.html import fromstring
86-from maasserver.testing import extract_redirect
87+from maasserver.testing import (
88+ extract_redirect,
89+ get_content_links,
90+ )
91 from maasserver.testing.factory import factory
92 from maasserver.testing.testcase import MAASServerTestCase
93
94@@ -44,3 +49,22 @@
95 self.client.login(username=user.username, password=password)
96 response = self.client.get('/accounts/login/')
97 self.assertEqual('/', extract_redirect(response))
98+
99+
100+class TestLogout(MAASServerTestCase):
101+
102+ def test_logout_link_present_on_homepage(self):
103+ self.client_log_in()
104+ response = self.client.get(reverse('index'))
105+ logout_link = reverse('logout')
106+ self.assertIn(
107+ logout_link,
108+ get_content_links(response, element='#user-options'))
109+
110+ def test_loggout_uses_POST(self):
111+ # Using POST for logging out, along with Django's csrf_token
112+ # tag, guarantees that we're protected against CSRF attacks on
113+ # the loggout page.
114+ self.client_log_in()
115+ self.client.post(reverse('logout'))
116+ self.assertNotIn(SESSION_KEY, self.client.session.keys())

Subscribers

People subscribed via source and target branches

to all changes: