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/>.
22 import six
.moves
.urllib
.parse
as urlparse
24 from mediagoblin
import mg_globals
25 from mediagoblin
.db
.models
import User
, LocalUser
26 from mediagoblin
.tests
.tools
import get_app
, fixture_add_user
27 from mediagoblin
.tools
import template
, mail
28 from mediagoblin
.auth
import tools
as auth_tools
31 def test_register_views(test_app
):
33 Massive test function that all our registration-related views all work.
35 # Test doing a simple GET on the page
36 # -----------------------------------
38 test_app
.get('/auth/register/')
39 # Make sure it rendered with the appropriate template
40 assert 'mediagoblin/auth/register.html' in template
.TEMPLATE_TEST_CONTEXT
42 # Try to register without providing anything, should error
43 # --------------------------------------------------------
45 template
.clear_test_template_context()
47 '/auth/register/', {})
48 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
49 form
= context
['register_form']
50 assert form
.username
.errors
== [u
'This field is required.']
51 assert form
.password
.errors
== [u
'This field is required.']
52 assert form
.email
.errors
== [u
'This field is required.']
54 # Try to register with fields that are known to be invalid
55 # --------------------------------------------------------
58 template
.clear_test_template_context()
64 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
65 form
= context
['register_form']
67 assert form
.username
.errors
== [u
'Field must be between 3 and 30 characters long.']
68 assert form
.password
.errors
== [u
'Field must be between 5 and 1024 characters long.']
71 template
.clear_test_template_context()
75 'email': 'lollerskates'})
76 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
77 form
= context
['register_form']
79 assert form
.username
.errors
== [u
'This field does not take email addresses.']
80 assert form
.email
.errors
== [u
'This field requires an email address.']
83 template
.clear_test_template_context()
86 'username': 'ampersand&invalid',
87 'email': 'easter@egg.com'})
88 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
89 form
= context
['register_form']
91 assert form
.username
.errors
== [u
'Invalid input.']
93 ## At this point there should be no users in the database ;)
94 assert User
.query
.count() == 0
96 ## mixture of characters from all valid ranges
97 template
.clear_test_template_context()
100 'username': 'Jean-Louis1_Le-Chat',
101 'password': 'iamsohappy',
102 'email': 'easter@egg.com'})
104 ## At this point there should on user in the database
105 assert User
.query
.count() == 1
107 # Successful register
108 # -------------------
109 template
.clear_test_template_context()
110 response
= test_app
.post(
112 'username': u
'angrygirl',
113 'password': 'iamsoangry',
114 'email': 'angrygrrl@example.org'})
117 ## Did we redirect to the proper page? Use the right template?
118 assert urlparse
.urlsplit(response
.location
)[2] == '/u/angrygirl/'
119 assert 'mediagoblin/user_pages/user_nonactive.html' in template
.TEMPLATE_TEST_CONTEXT
121 ## Make sure user is in place
122 new_user
= mg_globals
.database
.LocalUser
.query
.filter(
123 LocalUser
.username
==u
'angrygirl'
127 ## Make sure that the proper privileges are granted on registration
129 assert new_user
.has_privilege(u
'commenter')
130 assert new_user
.has_privilege(u
'uploader')
131 assert new_user
.has_privilege(u
'reporter')
132 assert not new_user
.has_privilege(u
'active')
133 ## Make sure user is logged in
134 request
= template
.TEMPLATE_TEST_CONTEXT
[
135 'mediagoblin/user_pages/user_nonactive.html']['request']
136 assert request
.session
['user_id'] == six
.text_type(new_user
.id)
138 ## Make sure we get email confirmation, and try verifying
139 assert len(mail
.EMAIL_TEST_INBOX
) == 2
140 message
= mail
.EMAIL_TEST_INBOX
.pop()
141 assert message
['To'] == 'angrygrrl@example.org'
142 email_context
= template
.TEMPLATE_TEST_CONTEXT
[
143 'mediagoblin/auth/verification_email.txt']
144 assert email_context
['verification_url'].encode('ascii') in message
.get_payload(decode
=True)
146 path
= urlparse
.urlsplit(email_context
['verification_url'])[2]
147 get_params
= urlparse
.urlsplit(email_context
['verification_url'])[3]
148 assert path
== u
'/auth/verify_email/'
149 parsed_get_params
= urlparse
.parse_qs(get_params
)
151 ## Try verifying with bs verification key, shouldn't work
152 template
.clear_test_template_context()
153 response
= test_app
.get(
154 "/auth/verify_email/?token=total_bs")
158 assert urlparse
.urlsplit(response
.location
)[2] == '/'
160 # assert context['verification_successful'] == True
161 # TODO: Would be good to test messages here when we can do so...
162 new_user
= mg_globals
.database
.LocalUser
.query
.filter(
163 LocalUser
.username
==u
'angrygirl'
167 ## Verify the email activation works
168 template
.clear_test_template_context()
169 response
= test_app
.get("%s?%s" % (path
, get_params
))
171 context
= template
.TEMPLATE_TEST_CONTEXT
[
172 'mediagoblin/user_pages/user.html']
173 # assert context['verification_successful'] == True
174 # TODO: Would be good to test messages here when we can do so...
175 new_user
= mg_globals
.database
.LocalUser
.query
.filter(
176 LocalUser
.username
==u
'angrygirl'
182 ## We shouldn't be able to register with that user twice
183 template
.clear_test_template_context()
184 response
= test_app
.post(
186 'username': u
'angrygirl',
187 'password': 'iamsoangry2',
188 'email': 'angrygrrl2@example.org'})
190 context
= template
.TEMPLATE_TEST_CONTEXT
[
191 'mediagoblin/auth/register.html']
192 form
= context
['register_form']
193 assert form
.username
.errors
== [
194 u
'Sorry, a user with that name already exists.']
196 ## TODO: Also check for double instances of an email address?
198 ### Oops, forgot the password
199 # -------------------
200 template
.clear_test_template_context()
201 response
= test_app
.post(
202 '/auth/forgot_password/',
203 {'username': u
'angrygirl'})
206 ## Did we redirect to the proper page? Use the right template?
207 assert urlparse
.urlsplit(response
.location
)[2] == '/auth/login/'
208 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
210 ## Make sure link to change password is sent by email
211 assert len(mail
.EMAIL_TEST_INBOX
) == 2
212 message
= mail
.EMAIL_TEST_INBOX
.pop()
213 assert message
['To'] == 'angrygrrl@example.org'
214 email_context
= template
.TEMPLATE_TEST_CONTEXT
[
215 'mediagoblin/plugins/basic_auth/fp_verification_email.txt']
216 #TODO - change the name of verification_url to something forgot-password-ish
217 assert email_context
['verification_url'].encode('ascii') in message
.get_payload(decode
=True)
219 path
= urlparse
.urlsplit(email_context
['verification_url'])[2]
220 get_params
= urlparse
.urlsplit(email_context
['verification_url'])[3]
221 parsed_get_params
= urlparse
.parse_qs(get_params
)
222 assert path
== u
'/auth/forgot_password/verify/'
224 ## Try using a bs password-changing verification key, shouldn't work
225 template
.clear_test_template_context()
226 response
= test_app
.get(
227 "/auth/forgot_password/verify/?token=total_bs")
231 assert urlparse
.urlsplit(response
.location
)[2] == '/'
233 ## Verify step 1 of password-change works -- can see form to change password
234 template
.clear_test_template_context()
235 response
= test_app
.get("%s?%s" % (path
, get_params
))
236 assert 'mediagoblin/plugins/basic_auth/change_fp.html' in \
237 template
.TEMPLATE_TEST_CONTEXT
239 ## Verify step 2.1 of password-change works -- report success to user
240 template
.clear_test_template_context()
241 response
= test_app
.post(
242 '/auth/forgot_password/verify/', {
243 'password': 'iamveryveryangry',
244 'token': parsed_get_params
['token']})
246 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
248 ## Verify step 2.2 of password-change works -- login w/ new password success
249 template
.clear_test_template_context()
250 response
= test_app
.post(
252 'username': u
'angrygirl',
253 'password': 'iamveryveryangry'})
255 # User should be redirected
257 assert urlparse
.urlsplit(response
.location
)[2] == '/'
258 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
260 def test_authentication_views(test_app
):
262 Test logging in and logging out
265 test_user
= fixture_add_user()
270 test_app
.get('/auth/login/')
271 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
273 # Failed login - blank form
274 # -------------------------
275 template
.clear_test_template_context()
276 response
= test_app
.post('/auth/login/')
277 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
278 form
= context
['login_form']
279 assert form
.username
.errors
== [u
'This field is required.']
281 # Failed login - blank user
282 # -------------------------
283 template
.clear_test_template_context()
284 response
= test_app
.post(
286 'password': u
'toast'})
287 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
288 form
= context
['login_form']
289 assert form
.username
.errors
== [u
'This field is required.']
291 # Failed login - blank password
292 # -----------------------------
293 template
.clear_test_template_context()
294 response
= test_app
.post(
296 'username': u
'chris'})
297 assert 'mediagoblin/auth/login.html' in template
.TEMPLATE_TEST_CONTEXT
299 # Failed login - bad user
300 # -----------------------
301 template
.clear_test_template_context()
302 response
= test_app
.post(
304 'username': u
'steve',
305 'password': 'toast'})
306 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
307 assert context
['login_failed']
309 # Failed login - bad password
310 # ---------------------------
311 template
.clear_test_template_context()
312 response
= test_app
.post(
314 'username': u
'chris',
315 'password': 'jam_and_ham'})
316 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
317 assert context
['login_failed']
321 template
.clear_test_template_context()
322 response
= test_app
.post(
324 'username': u
'chris',
325 'password': 'toast'})
327 # User should be redirected
329 assert urlparse
.urlsplit(response
.location
)[2] == '/'
330 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
332 # Make sure user is in the session
333 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
334 session
= context
['request'].session
335 assert session
['user_id'] == six
.text_type(test_user
.id)
339 template
.clear_test_template_context()
340 response
= test_app
.get('/auth/logout/')
342 # Should be redirected to index page
344 assert urlparse
.urlsplit(response
.location
)[2] == '/'
345 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
347 # Make sure the user is not in the session
348 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
349 session
= context
['request'].session
350 assert 'user_id' not in session
352 # User is redirected to custom URL if POST['next'] is set
353 # -------------------------------------------------------
354 template
.clear_test_template_context()
355 response
= test_app
.post(
357 'username': u
'chris',
359 'next' : '/u/chris/'})
360 assert urlparse
.urlsplit(response
.location
)[2] == '/u/chris/'
362 ## Verify that username is lowercased on login attempt
363 template
.clear_test_template_context()
364 response
= test_app
.post(
366 'username': u
'ANDREW',
367 'password': 'fuselage'})
368 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/login.html']
369 form
= context
['login_form']
371 # Username should no longer be uppercased; it should be lowercased
372 assert not form
.username
.data
== u
'ANDREW'
373 assert form
.username
.data
== u
'andrew'
375 # Successful login with short user
376 # --------------------------------
377 short_user
= fixture_add_user(username
=u
'me', password
=u
'sho')
378 template
.clear_test_template_context()
379 response
= test_app
.post(
384 # User should be redirected
387 assert urlparse
.urlsplit(response
.location
)[2] == '/'
388 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
390 # Make sure user is in the session
391 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
392 session
= context
['request'].session
393 assert session
['user_id'] == six
.text_type(short_user
.id)
396 template
.clear_test_template_context()
397 response
= test_app
.get('/auth/logout/')
399 # Successful login with long user
401 long_user
= fixture_add_user(
402 username
=u
'realllylonguser@reallylongdomain.com.co', password
=u
'sho')
403 template
.clear_test_template_context()
404 response
= test_app
.post(
406 'username': u
'realllylonguser@reallylongdomain.com.co',
409 # User should be redirected
411 assert urlparse
.urlsplit(response
.location
)[2] == '/'
412 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
414 # Make sure user is in the session
415 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
416 session
= context
['request'].session
417 assert session
['user_id'] == six
.text_type(long_user
.id)
419 template
.clear_test_template_context()
420 response
= test_app
.get('/auth/logout/')
423 def authentication_disabled_app(request
):
426 mgoblin_config
=pkg_resources
.resource_filename(
427 'mediagoblin.tests.auth_configs',
428 'authentication_disabled_appconfig.ini'))
431 def test_authentication_disabled_app(authentication_disabled_app
):
432 # app.auth should = false
434 assert mg_globals
.app
.auth
is False
436 # Try to visit register page
437 template
.clear_test_template_context()
438 response
= authentication_disabled_app
.get('/auth/register/')
442 assert urlparse
.urlsplit(response
.location
)[2] == '/'
443 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
445 # Try to vist login page
446 template
.clear_test_template_context()
447 response
= authentication_disabled_app
.get('/auth/login/')
451 assert urlparse
.urlsplit(response
.location
)[2] == '/'
452 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
454 ## Test check_login_simple should return None
455 assert auth_tools
.check_login_simple('test', 'simple') is None
457 # Try to visit the forgot password page
458 template
.clear_test_template_context()
459 response
= authentication_disabled_app
.get('/auth/register/')
463 assert urlparse
.urlsplit(response
.location
)[2] == '/'
464 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT