1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 from mediagoblin
import mg_globals
22 from mediagoblin
.db
.models
import User
23 from mediagoblin
.tests
.tools
import get_app
, fixture_add_user
24 from mediagoblin
.tools
import template
, mail
25 from mediagoblin
.auth
import tools
as auth_tools
28 def test_register_views(test_app
):
30 Massive test function that all our registration-related views all work.
32 # Test doing a simple GET on the page
33 # -----------------------------------
35 test_app
.get('/auth/register/')
36 # Make sure it rendered with the appropriate template
37 assert 'mediagoblin/auth/register.html' in template
.TEMPLATE_TEST_CONTEXT
39 # Try to register without providing anything, should error
40 # --------------------------------------------------------
42 template
.clear_test_template_context()
44 '/auth/register/', {})
45 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
46 form
= context
['register_form']
47 assert form
.username
.errors
== [u
'This field is required.']
48 assert form
.password
.errors
== [u
'This field is required.']
49 assert form
.email
.errors
== [u
'This field is required.']
51 # Try to register with fields that are known to be invalid
52 # --------------------------------------------------------
55 template
.clear_test_template_context()
61 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
62 form
= context
['register_form']
64 assert form
.username
.errors
== [u
'Field must be between 3 and 30 characters long.']
65 assert form
.password
.errors
== [u
'Field must be between 5 and 1024 characters long.']
68 template
.clear_test_template_context()
72 'email': 'lollerskates'})
73 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
74 form
= context
['register_form']
76 assert form
.username
.errors
== [u
'This field does not take email addresses.']
77 assert form
.email
.errors
== [u
'This field requires an email address.']
79 ## At this point there should be no users in the database ;)
80 assert User
.query
.count() == 0
84 template
.clear_test_template_context()
85 response
= test_app
.post(
87 'username': u
'happygirl',
88 'password': 'iamsohappy',
89 'email': 'happygrrl@example.org'})
92 ## Did we redirect to the proper page? Use the right template?
93 assert urlparse
.urlsplit(response
.location
)[2] == '/u/happygirl/'
94 assert 'mediagoblin/user_pages/user.html' in template
.TEMPLATE_TEST_CONTEXT
96 ## Make sure user is in place
97 new_user
= mg_globals
.database
.User
.find_one(
98 {'username': u
'happygirl'})
100 assert new_user
.status
== u
'needs_email_verification'
101 assert new_user
.email_verified
== False
103 ## Make sure user is logged in
104 request
= template
.TEMPLATE_TEST_CONTEXT
[
105 'mediagoblin/user_pages/user.html']['request']
106 assert request
.session
['user_id'] == unicode(new_user
.id)
108 ## Make sure we get email confirmation, and try verifying
109 assert len(mail
.EMAIL_TEST_INBOX
) == 1
110 message
= mail
.EMAIL_TEST_INBOX
.pop()
111 assert message
['To'] == 'happygrrl@example.org'
112 email_context
= template
.TEMPLATE_TEST_CONTEXT
[
113 'mediagoblin/auth/verification_email.txt']
114 assert email_context
['verification_url'] in message
.get_payload(decode
=True)
116 path
= urlparse
.urlsplit(email_context
['verification_url'])[2]
117 get_params
= urlparse
.urlsplit(email_context
['verification_url'])[3]
118 assert path
== u
'/auth/verify_email/'
119 parsed_get_params
= urlparse
.parse_qs(get_params
)
121 ### user should have these same parameters
122 assert parsed_get_params
['userid'] == [
123 unicode(new_user
.id)]
124 assert parsed_get_params
['token'] == [
125 new_user
.verification_key
]
127 ## Try verifying with bs verification key, shouldn't work
128 template
.clear_test_template_context()
129 response
= test_app
.get(
130 "/auth/verify_email/?userid=%s&token=total_bs" % unicode(
133 context
= template
.TEMPLATE_TEST_CONTEXT
[
134 'mediagoblin/user_pages/user.html']
135 # assert context['verification_successful'] == True
136 # TODO: Would be good to test messages here when we can do so...
137 new_user
= mg_globals
.database
.User
.find_one(
138 {'username': u
'happygirl'})
140 assert new_user
.status
== u
'needs_email_verification'
141 assert new_user
.email_verified
== False
143 ## Verify the email activation works
144 template
.clear_test_template_context()
145 response
= test_app
.get("%s?%s" % (path
, get_params
))
147 context
= template
.TEMPLATE_TEST_CONTEXT
[
148 'mediagoblin/user_pages/user.html']
149 # assert context['verification_successful'] == True
150 # TODO: Would be good to test messages here when we can do so...
151 new_user
= mg_globals
.database
.User
.find_one(
152 {'username': u
'happygirl'})
154 assert new_user
.status
== u
'active'
155 assert new_user
.email_verified
== True
159 ## We shouldn't be able to register with that user twice
160 template
.clear_test_template_context()
161 response
= test_app
.post(
163 'username': u
'happygirl',
164 'password': 'iamsohappy2',
165 'email': 'happygrrl2@example.org'})
167 context
= template
.TEMPLATE_TEST_CONTEXT
[
168 'mediagoblin/auth/register.html']
169 form
= context
['register_form']
170 assert form
.username
.errors
== [
171 u
'Sorry, a user with that name already exists.']
173 ## TODO: Also check for double instances of an email address?
175 ### Oops, forgot the password
176 # -------------------
177 template
.clear_test_template_context()
178 response
= test_app
.post(
179 '/auth/forgot_password/',
180 {'username': u
'happygirl'})
183 ## Did we redirect to the proper page? Use the right template?
184 assert urlparse
.urlsplit(response
.location
)[2] == '/auth/login/'
185 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
187 ## Make sure link to change password is sent by email
188 assert len(mail
.EMAIL_TEST_INBOX
) == 1
189 message
= mail
.EMAIL_TEST_INBOX
.pop()
190 assert message
['To'] == 'happygrrl@example.org'
191 email_context
= template
.TEMPLATE_TEST_CONTEXT
[
192 'mediagoblin/auth/fp_verification_email.txt']
193 #TODO - change the name of verification_url to something forgot-password-ish
194 assert email_context
['verification_url'] in message
.get_payload(decode
=True)
196 path
= urlparse
.urlsplit(email_context
['verification_url'])[2]
197 get_params
= urlparse
.urlsplit(email_context
['verification_url'])[3]
198 assert path
== u
'/auth/forgot_password/verify/'
199 parsed_get_params
= urlparse
.parse_qs(get_params
)
201 # user should have matching parameters
202 new_user
= mg_globals
.database
.User
.find_one({'username': u
'happygirl'})
203 assert parsed_get_params
['userid'] == [unicode(new_user
.id)]
204 assert parsed_get_params
['token'] == [new_user
.fp_verification_key
]
206 ### The forgotten password token should be set to expire in ~ 10 days
207 # A few ticks have expired so there are only 9 full days left...
208 assert (new_user
.fp_token_expire
- datetime
.datetime
.now()).days
== 9
210 ## Try using a bs password-changing verification key, shouldn't work
211 template
.clear_test_template_context()
212 response
= test_app
.get(
213 "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode(
214 new_user
.id), status
=404)
215 assert response
.status
.split()[0] == u
'404' # status="404 NOT FOUND"
217 ## Try using an expired token to change password, shouldn't work
218 template
.clear_test_template_context()
219 new_user
= mg_globals
.database
.User
.find_one({'username': u
'happygirl'})
220 real_token_expiration
= new_user
.fp_token_expire
221 new_user
.fp_token_expire
= datetime
.datetime
.now()
223 response
= test_app
.get("%s?%s" % (path
, get_params
), status
=404)
224 assert response
.status
.split()[0] == u
'404' # status="404 NOT FOUND"
225 new_user
.fp_token_expire
= real_token_expiration
228 ## Verify step 1 of password-change works -- can see form to change password
229 template
.clear_test_template_context()
230 response
= test_app
.get("%s?%s" % (path
, get_params
))
231 assert 'mediagoblin/auth/change_fp.html' in template
.TEMPLATE_TEST_CONTEXT
233 ## Verify step 2.1 of password-change works -- report success to user
234 template
.clear_test_template_context()
235 response
= test_app
.post(
236 '/auth/forgot_password/verify/', {
237 'userid': parsed_get_params
['userid'],
238 'password': 'iamveryveryhappy',
239 'token': parsed_get_params
['token']})
241 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
243 ## Verify step 2.2 of password-change works -- login w/ new password success
244 template
.clear_test_template_context()
245 response
= test_app
.post(
247 'username': u
'happygirl',
248 'password': 'iamveryveryhappy'})
250 # User should be redirected
252 assert urlparse
.urlsplit(response
.location
)[2] == '/'
253 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
256 def test_authentication_views(test_app
):
258 Test logging in and logging out
261 test_user
= fixture_add_user(active_user
=False)
265 test_app
.get('/auth/login/')
266 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
268 # Failed login - blank form
269 # -------------------------
270 template
.clear_test_template_context()
271 response
= test_app
.post('/auth/login/')
272 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
273 form
= context
['login_form']
274 assert form
.username
.errors
== [u
'This field is required.']
276 # Failed login - blank user
277 # -------------------------
278 template
.clear_test_template_context()
279 response
= test_app
.post(
281 'password': u
'toast'})
282 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
283 form
= context
['login_form']
284 assert form
.username
.errors
== [u
'This field is required.']
286 # Failed login - blank password
287 # -----------------------------
288 template
.clear_test_template_context()
289 response
= test_app
.post(
291 'username': u
'chris'})
292 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
294 # Failed login - bad user
295 # -----------------------
296 template
.clear_test_template_context()
297 response
= test_app
.post(
299 'username': u
'steve',
300 'password': 'toast'})
301 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
302 assert context
['login_failed']
304 # Failed login - bad password
305 # ---------------------------
306 template
.clear_test_template_context()
307 response
= test_app
.post(
309 'username': u
'chris',
310 'password': 'jam_and_ham'})
311 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
312 assert context
['login_failed']
316 template
.clear_test_template_context()
317 response
= test_app
.post(
319 'username': u
'chris',
320 'password': 'toast'})
322 # User should be redirected
324 assert urlparse
.urlsplit(response
.location
)[2] == '/'
325 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
327 # Make sure user is in the session
328 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
329 session
= context
['request'].session
330 assert session
['user_id'] == unicode(test_user
.id)
334 template
.clear_test_template_context()
335 response
= test_app
.get('/auth/logout/')
337 # Should be redirected to index page
339 assert urlparse
.urlsplit(response
.location
)[2] == '/'
340 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
342 # Make sure the user is not in the session
343 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
344 session
= context
['request'].session
345 assert 'user_id' not in session
347 # User is redirected to custom URL if POST['next'] is set
348 # -------------------------------------------------------
349 template
.clear_test_template_context()
350 response
= test_app
.post(
352 'username': u
'chris',
354 'next' : '/u/chris/'})
355 assert urlparse
.urlsplit(response
.location
)[2] == '/u/chris/'
359 def authentication_disabled_app(request
):
362 mgoblin_config
=pkg_resources
.resource_filename(
363 'mediagoblin.tests.auth_configs',
364 'authentication_disabled_appconfig.ini'))
367 def test_authentication_disabled_app(authentication_disabled_app
):
368 # app.auth should = false
369 assert mg_globals
.app
.auth
is False
371 # Try to visit register page
372 template
.clear_test_template_context()
373 response
= authentication_disabled_app
.get('/auth/register/')
377 assert urlparse
.urlsplit(response
.location
)[2] == '/'
378 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
380 # Try to vist login page
381 template
.clear_test_template_context()
382 response
= authentication_disabled_app
.get('/auth/login/')
386 assert urlparse
.urlsplit(response
.location
)[2] == '/'
387 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
389 ## Test check_login_simple should return None
390 assert auth_tools
.check_login_simple('test', 'simple') is None
392 # Try to visit the forgot password page
393 template
.clear_test_template_context()
394 response
= authentication_disabled_app
.get('/auth/register/')
398 assert urlparse
.urlsplit(response
.location
)[2] == '/'
399 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT