blob: 335941e530390d0a7ec6a54bd9fd47ad7f7a23b5 [file] [log] [blame]
srikanth116e6e82014-08-19 07:22:37 -07001#
2# Copyright (c) 2013 Big Switch Networks, Inc.
3#
4# Licensed under the Eclipse Public License, Version 1.0 (the
5# "License"); you may not use this file except in compliance with the
6# License. You may obtain a copy of the License at
7#
8# http://www.eclipse.org/legal/epl-v10.html
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied. See the License for the specific language governing
14# permissions and limitations under the License.
15#
16
17import os
18import re
19import urllib
20
21from django.conf import settings
22from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
23from django.contrib.auth.forms import AuthenticationForm
24from django.contrib.sites.models import Site, RequestSite
25from django.contrib.auth.models import User
26from django.test import TestCase
27from django.core import mail
28from django.core.urlresolvers import reverse
29from django.utils.unittest import skipIf
30
31class AuthViewsTestCase(TestCase):
32 """
33 Helper base class for all the follow test cases.
34 """
35 fixtures = ['authtestdata.json']
36 urls = 'django.contrib.auth.tests.urls'
37
38 def setUp(self):
39 self.old_LANGUAGES = settings.LANGUAGES
40 self.old_LANGUAGE_CODE = settings.LANGUAGE_CODE
41 settings.LANGUAGES = (('en', 'English'),)
42 settings.LANGUAGE_CODE = 'en'
43 self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
44 settings.TEMPLATE_DIRS = (
45 os.path.join(
46 os.path.dirname(__file__),
47 'templates'
48 )
49 ,)
50
51 def tearDown(self):
52 settings.LANGUAGES = self.old_LANGUAGES
53 settings.LANGUAGE_CODE = self.old_LANGUAGE_CODE
54 settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
55
56 def login(self, password='password'):
57 response = self.client.post('/login/', {
58 'username': 'testclient',
59 'password': password
60 }
61 )
62 self.assertEquals(response.status_code, 302)
63 self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL))
64 self.assert_(SESSION_KEY in self.client.session)
65
66class PasswordResetTest(AuthViewsTestCase):
67
68 def test_email_not_found(self):
69 "Error is raised if the provided email address isn't currently registered"
70 response = self.client.get('/password_reset/')
71 self.assertEquals(response.status_code, 200)
72 response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
73 self.assertContains(response, "That e-mail address doesn't have an associated user account")
74 self.assertEquals(len(mail.outbox), 0)
75
76 @skipIf(True, "Do not support")
77 def test_email_found(self):
78 "Email is sent if a valid email address is provided for password reset"
79 response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
80 self.assertEquals(response.status_code, 302)
81 self.assertEquals(len(mail.outbox), 1)
82 self.assert_("http://" in mail.outbox[0].body)
83 self.assertEquals(settings.DEFAULT_FROM_EMAIL, mail.outbox[0].from_email)
84
85 @skipIf(True, "Do not support")
86 def test_email_found_custom_from(self):
87 "Email is sent if a valid email address is provided for password reset when a custom from_email is provided."
88 response = self.client.post('/password_reset_from_email/', {'email': 'staffmember@example.com'})
89 self.assertEquals(response.status_code, 302)
90 self.assertEquals(len(mail.outbox), 1)
91 self.assertEquals("staffmember@example.com", mail.outbox[0].from_email)
92
93 def _test_confirm_start(self):
94 # Start by creating the email
95 response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
96 self.assertEquals(response.status_code, 302)
97 self.assertEquals(len(mail.outbox), 1)
98 return self._read_signup_email(mail.outbox[0])
99
100 def _read_signup_email(self, email):
101 urlmatch = re.search(r"https?://[^/]*(/.*reset/\S*)", email.body)
102 self.assert_(urlmatch is not None, "No URL found in sent email")
103 return urlmatch.group(), urlmatch.groups()[0]
104
105 @skipIf(True, "Do not support")
106 def test_confirm_valid(self):
107 url, path = self._test_confirm_start()
108 response = self.client.get(path)
109 # redirect to a 'complete' page:
110 self.assertEquals(response.status_code, 200)
111 self.assert_("Please enter your new password" in response.content)
112
113 @skipIf(True, "Do not support")
114 def test_confirm_invalid(self):
115 url, path = self._test_confirm_start()
116 # Let's munge the token in the path, but keep the same length,
117 # in case the URLconf will reject a different length.
118 path = path[:-5] + ("0"*4) + path[-1]
119
120 response = self.client.get(path)
121 self.assertEquals(response.status_code, 200)
122 self.assert_("The password reset link was invalid" in response.content)
123
124 @skipIf(True, "Do not support")
125 def test_confirm_invalid_user(self):
126 # Ensure that we get a 200 response for a non-existant user, not a 404
127 response = self.client.get('/reset/123456-1-1/')
128 self.assertEquals(response.status_code, 200)
129 self.assert_("The password reset link was invalid" in response.content)
130
131 @skipIf(True, "Do not support")
132 def test_confirm_invalid_post(self):
133 # Same as test_confirm_invalid, but trying
134 # to do a POST instead.
135 url, path = self._test_confirm_start()
136 path = path[:-5] + ("0"*4) + path[-1]
137
138 response = self.client.post(path, {'new_password1': 'anewpassword',
139 'new_password2':' anewpassword'})
140 # Check the password has not been changed
141 u = User.objects.get(email='staffmember@example.com')
142 self.assert_(not u.check_password("anewpassword"))
143
144 @skipIf(True, "Do not support")
145 def test_confirm_complete(self):
146 url, path = self._test_confirm_start()
147 response = self.client.post(path, {'new_password1': 'anewpassword',
148 'new_password2': 'anewpassword'})
149 # It redirects us to a 'complete' page:
150 self.assertEquals(response.status_code, 302)
151 # Check the password has been changed
152 u = User.objects.get(email='staffmember@example.com')
153 self.assert_(u.check_password("anewpassword"))
154
155 # Check we can't use the link again
156 response = self.client.get(path)
157 self.assertEquals(response.status_code, 200)
158 self.assert_("The password reset link was invalid" in response.content)
159
160 @skipIf(True, "Do not support")
161 def test_confirm_different_passwords(self):
162 url, path = self._test_confirm_start()
163 response = self.client.post(path, {'new_password1': 'anewpassword',
164 'new_password2':' x'})
165 self.assertEquals(response.status_code, 200)
166 self.assert_("The two password fields didn't match" in response.content)
167
168class ChangePasswordTest(AuthViewsTestCase):
169
170 def fail_login(self, password='password'):
171 response = self.client.post('/login/', {
172 'username': 'testclient',
173 'password': password
174 }
175 )
176 self.assertEquals(response.status_code, 200)
177 self.assert_("Please enter a correct username and password. Note that both fields are case-sensitive." in response.content)
178
179 def logout(self):
180 response = self.client.get('/logout/')
181
182 def test_password_change_fails_with_invalid_old_password(self):
183 self.login()
184 response = self.client.post('/password_change/', {
185 'old_password': 'donuts',
186 'new_password1': 'password1',
187 'new_password2': 'password1',
188 }
189 )
190 self.assertEquals(response.status_code, 200)
191 self.assert_("Your old password was entered incorrectly. Please enter it again." in response.content)
192
193 def test_password_change_fails_with_mismatched_passwords(self):
194 self.login()
195 response = self.client.post('/password_change/', {
196 'old_password': 'password',
197 'new_password1': 'password1',
198 'new_password2': 'donuts',
199 }
200 )
201 self.assertEquals(response.status_code, 200)
202 self.assert_("The two password fields didn't match." in response.content)
203
204 def test_password_change_succeeds(self):
205 self.login()
206 response = self.client.post('/password_change/', {
207 'old_password': 'password',
208 'new_password1': 'password1',
209 'new_password2': 'password1',
210 }
211 )
212 self.assertEquals(response.status_code, 302)
213 self.assert_(response['Location'].endswith('/password_change/done/'))
214 self.fail_login()
215 self.login(password='password1')
216
217class LoginTest(AuthViewsTestCase):
218
219 @skipIf(True, "Do not support")
220 def test_current_site_in_context_after_login(self):
221 response = self.client.get(reverse('django.contrib.auth.views.login'))
222 self.assertEquals(response.status_code, 200)
223 site = Site.objects.get_current()
224 self.assertEquals(response.context['site'], site)
225 self.assertEquals(response.context['site_name'], site.name)
226 self.assert_(isinstance(response.context['form'], AuthenticationForm),
227 'Login form is not an AuthenticationForm')
228
229 def test_security_check(self, password='password'):
230 login_url = reverse('django.contrib.auth.views.login')
231
232 # Those URLs should not pass the security check
233 for bad_url in ('http://example.com',
234 'https://example.com',
235 'ftp://exampel.com',
236 '//example.com'):
237
238 nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
239 'url': login_url,
240 'next': REDIRECT_FIELD_NAME,
241 'bad_url': urllib.quote(bad_url)
242 }
243 response = self.client.post(nasty_url, {
244 'username': 'testclient',
245 'password': password,
246 }
247 )
248 self.assertEquals(response.status_code, 302)
249 self.assertFalse(bad_url in response['Location'], "%s should be blocked" % bad_url)
250
251 # Now, these URLs have an other URL as a GET parameter and therefore
252 # should be allowed
253 for url_ in ('http://example.com', 'https://example.com',
254 'ftp://exampel.com', '//example.com'):
255 safe_url = '%(url)s?%(next)s=/view/?param=%(safe_param)s' % {
256 'url': login_url,
257 'next': REDIRECT_FIELD_NAME,
258 'safe_param': urllib.quote(url_)
259 }
260 response = self.client.post(safe_url, {
261 'username': 'testclient',
262 'password': password,
263 }
264 )
265 self.assertEquals(response.status_code, 302)
266 self.assertTrue('/view/?param=%s' % url_ in response['Location'], "/view/?param=%s should be allowed" % url_)
267
268
269class LogoutTest(AuthViewsTestCase):
270 urls = 'django.contrib.auth.tests.urls'
271
272 def confirm_logged_out(self):
273 self.assert_(SESSION_KEY not in self.client.session)
274
275 def test_logout_default(self):
276 "Logout without next_page option renders the default template"
277 self.login()
278 response = self.client.get('/logout/')
279 self.assertEquals(200, response.status_code)
280 self.assert_('Logged out' in response.content)
281 self.confirm_logged_out()
282
283 def test_14377(self):
284 # Bug 14377
285 self.login()
286 response = self.client.get('/logout/')
287 self.assertTrue('site' in response.context)
288
289 def test_logout_with_next_page_specified(self):
290 "Logout with next_page option given redirects to specified resource"
291 self.login()
292 response = self.client.get('/logout/next_page/')
293 self.assertEqual(response.status_code, 302)
294 self.assert_(response['Location'].endswith('/somewhere/'))
295 self.confirm_logged_out()
296
297 def test_logout_with_redirect_argument(self):
298 "Logout with query string redirects to specified resource"
299 self.login()
300 response = self.client.get('/logout/?next=/login/')
301 self.assertEqual(response.status_code, 302)
302 self.assert_(response['Location'].endswith('/login/'))
303 self.confirm_logged_out()
304
305 def test_logout_with_custom_redirect_argument(self):
306 "Logout with custom query string redirects to specified resource"
307 self.login()
308 response = self.client.get('/logout/custom_query/?follow=/somewhere/')
309 self.assertEqual(response.status_code, 302)
310 self.assert_(response['Location'].endswith('/somewhere/'))
311 self.confirm_logged_out()