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/>.
20 import six
.moves
.urllib
.parse
as urlparse
24 import unittest
.mock
as mock
26 openid_consumer
= pytest
.importorskip(
27 "openid.consumer.consumer")
29 from mediagoblin
import mg_globals
30 from mediagoblin
.db
.base
import Session
31 from mediagoblin
.db
.models
import User
32 from mediagoblin
.plugins
.openid
.models
import OpenIDUserURL
33 from mediagoblin
.tests
.tools
import get_app
, fixture_add_user
34 from mediagoblin
.tools
import template
37 # App with plugin enabled
39 def openid_plugin_app(request
):
42 mgoblin_config
=pkg_resources
.resource_filename(
43 'mediagoblin.tests.auth_configs',
44 'openid_appconfig.ini'))
47 class TestOpenIDPlugin(object):
48 def _setup(self
, openid_plugin_app
, value
=True, edit
=False, delete
=False):
50 response
= openid_consumer
.SuccessResponse(mock
.Mock(), mock
.Mock())
52 response
.identity_url
= u
'http://add.myopenid.com'
54 response
.identity_url
= u
'http://real.myopenid.com'
55 self
._finish
_verification
= mock
.Mock(return_value
=response
)
57 self
._finish
_verification
= mock
.Mock(return_value
=False)
59 @mock.patch('mediagoblin.plugins.openid.views._response_email', mock
.Mock(return_value
=None))
60 @mock.patch('mediagoblin.plugins.openid.views._response_nickname', mock
.Mock(return_value
=None))
61 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
62 def _setup_start(self
, openid_plugin_app
, edit
, delete
):
64 self
._start
_verification
= mock
.Mock(return_value
=openid_plugin_app
.post(
65 '/edit/openid/finish/'))
67 self
._start
_verification
= mock
.Mock(return_value
=openid_plugin_app
.post(
68 '/edit/openid/delete/finish/'))
70 self
._start
_verification
= mock
.Mock(return_value
=openid_plugin_app
.post(
71 '/auth/openid/login/finish/'))
72 _setup_start(self
, openid_plugin_app
, edit
, delete
)
74 def test_bad_login(self
, openid_plugin_app
):
75 """ Test that attempts to login with invalid paramaters"""
77 # Test GET request for auth/register page
78 res
= openid_plugin_app
.get('/auth/register/').follow()
80 # Make sure it redirected to the correct place
81 assert urlparse
.urlsplit(res
.location
)[2] == '/auth/openid/login/'
83 # Test GET request for auth/login page
84 res
= openid_plugin_app
.get('/auth/login/')
88 assert urlparse
.urlsplit(res
.location
)[2] == '/auth/openid/login/'
90 # Test GET request for auth/openid/register page
91 res
= openid_plugin_app
.get('/auth/openid/register/')
95 assert urlparse
.urlsplit(res
.location
)[2] == '/auth/openid/login/'
97 # Test GET request for auth/openid/login/finish page
98 res
= openid_plugin_app
.get('/auth/openid/login/finish/')
102 assert urlparse
.urlsplit(res
.location
)[2] == '/auth/openid/login/'
104 # Test GET request for auth/openid/login page
105 res
= openid_plugin_app
.get('/auth/openid/login/')
108 assert 'mediagoblin/plugins/openid/login.html' in template
.TEMPLATE_TEST_CONTEXT
110 # Try to login with an empty form
111 template
.clear_test_template_context()
112 openid_plugin_app
.post(
113 '/auth/openid/login/', {})
114 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/login.html']
115 form
= context
['login_form']
116 assert form
.openid
.errors
== [u
'This field is required.']
118 # Try to login with wrong form values
119 template
.clear_test_template_context()
120 openid_plugin_app
.post(
121 '/auth/openid/login/', {
122 'openid': 'not_a_url.com'})
123 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/login.html']
124 form
= context
['login_form']
125 assert form
.openid
.errors
== [u
'Please enter a valid url.']
127 # Should be no users in the db
128 assert User
.query
.count() == 0
131 template
.clear_test_template_context()
132 openid_plugin_app
.post(
133 '/auth/openid/login/', {
134 'openid': 'http://phoney.myopenid.com/'})
135 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/login.html']
136 form
= context
['login_form']
137 assert form
.openid
.errors
== [u
'Sorry, the OpenID server could not be found']
139 def test_login(self
, openid_plugin_app
):
140 """Tests that test login and registion with openid"""
141 # Test finish_login redirects correctly when response = False
142 self
._setup
(openid_plugin_app
, False)
144 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
145 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
146 def _test_non_response():
147 template
.clear_test_template_context()
148 res
= openid_plugin_app
.post(
149 '/auth/openid/login/', {
150 'openid': 'http://phoney.myopenid.com/'})
154 assert urlparse
.urlsplit(res
.location
)[2] == '/auth/openid/login/'
155 assert 'mediagoblin/plugins/openid/login.html' in template
.TEMPLATE_TEST_CONTEXT
158 # Test login with new openid
159 # Need to clear_test_template_context before calling _setup
160 template
.clear_test_template_context()
161 self
._setup
(openid_plugin_app
)
163 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
164 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
165 def _test_new_user():
166 openid_plugin_app
.post(
167 '/auth/openid/login/', {
168 'openid': u
'http://real.myopenid.com'})
171 assert 'mediagoblin/auth/register.html' in template
.TEMPLATE_TEST_CONTEXT
172 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
173 register_form
= context
['register_form']
176 res
= openid_plugin_app
.post(
177 '/auth/openid/register/', {
178 'openid': register_form
.openid
.data
,
179 'username': u
'chris',
180 'email': u
'chris@example.com'})
184 assert urlparse
.urlsplit(res
.location
)[2] == '/u/chris/'
185 assert 'mediagoblin/user_pages/user_nonactive.html' in template
.TEMPLATE_TEST_CONTEXT
187 # No need to test if user is in logged in and verification email
188 # awaits, since openid uses the register_user function which is
189 # tested in test_auth
192 openid_plugin_app
.get('/auth/logout')
194 # Get user and detach from session
195 test_user
= mg_globals
.database
.User
.query
.filter_by(
196 username
=u
'chris').first()
197 Session
.expunge(test_user
)
200 # Could not get it to work by 'POST'ing to /auth/openid/login/
201 template
.clear_test_template_context()
202 res
= openid_plugin_app
.post(
203 '/auth/openid/login/finish/', {
204 'openid': u
'http://real.myopenid.com'})
207 assert urlparse
.urlsplit(res
.location
)[2] == '/'
208 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
210 # Make sure user is in the session
211 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
212 session
= context
['request'].session
213 assert session
['user_id'] == six
.text_type(test_user
.id)
217 # Test register with empty form
218 template
.clear_test_template_context()
219 openid_plugin_app
.post(
220 '/auth/openid/register/', {})
221 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
222 register_form
= context
['register_form']
224 assert register_form
.openid
.errors
== [u
'This field is required.']
225 assert register_form
.email
.errors
== [u
'This field is required.']
226 assert register_form
.username
.errors
== [u
'This field is required.']
228 # Try to register with existing username and email
229 template
.clear_test_template_context()
230 openid_plugin_app
.post(
231 '/auth/openid/register/', {
232 'openid': 'http://real.myopenid.com',
233 'email': 'chris@example.com',
234 'username': 'chris'})
235 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
236 register_form
= context
['register_form']
238 assert register_form
.username
.errors
== [u
'Sorry, a user with that name already exists.']
239 assert register_form
.email
.errors
== [u
'Sorry, a user with that email address already exists.']
240 assert register_form
.openid
.errors
== [u
'Sorry, an account is already registered to that OpenID.']
242 def test_add_delete(self
, openid_plugin_app
):
243 """Test adding and deleting openids"""
245 test_user
= fixture_add_user(password
='', privileges
=[u
'active'])
246 openid
= OpenIDUserURL()
247 openid
.openid_url
= 'http://real.myopenid.com'
248 openid
.user_id
= test_user
.id
252 template
.clear_test_template_context()
253 self
._setup
(openid_plugin_app
)
255 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
256 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
258 openid_plugin_app
.post(
259 '/auth/openid/login/finish/', {
260 'openid': u
'http://real.myopenid.com'})
264 # Try and delete only OpenID url
265 template
.clear_test_template_context()
266 res
= openid_plugin_app
.post(
267 '/edit/openid/delete/', {
268 'openid': 'http://real.myopenid.com'})
269 assert 'mediagoblin/plugins/openid/delete.html' in template
.TEMPLATE_TEST_CONTEXT
273 template
.clear_test_template_context()
274 res
= openid_plugin_app
.post(
276 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/add.html']
277 form
= context
['form']
278 assert form
.openid
.errors
== [u
'This field is required.']
281 template
.clear_test_template_context()
282 openid_plugin_app
.post(
284 'openid': u
'not_a_url.com'})
285 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/add.html']
286 form
= context
['form']
287 assert form
.openid
.errors
== [u
'Please enter a valid url.']
289 # Try with a url that's already registered
290 template
.clear_test_template_context()
291 openid_plugin_app
.post(
293 'openid': 'http://real.myopenid.com'})
294 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/add.html']
295 form
= context
['form']
296 assert form
.openid
.errors
== [u
'Sorry, an account is already registered to that OpenID.']
298 # Test adding openid to account
299 # Need to clear_test_template_context before calling _setup
300 template
.clear_test_template_context()
301 self
._setup
(openid_plugin_app
, edit
=True)
303 # Need to remove openid_url from db because it was added at setup
304 openid
= OpenIDUserURL
.query
.filter_by(
305 openid_url
=u
'http://add.myopenid.com')
308 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
309 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
312 template
.clear_test_template_context()
313 res
= openid_plugin_app
.post(
315 'openid': u
'http://add.myopenid.com'})
319 assert urlparse
.urlsplit(res
.location
)[2] == '/edit/account/'
320 assert 'mediagoblin/edit/edit_account.html' in template
.TEMPLATE_TEST_CONTEXT
323 new_openid
= mg_globals
.database
.OpenIDUserURL
.query
.filter_by(
324 openid_url
=u
'http://add.myopenid.com').first()
329 # Test deleting openid from account
330 # Need to clear_test_template_context before calling _setup
331 template
.clear_test_template_context()
332 self
._setup
(openid_plugin_app
, delete
=True)
334 # Need to add OpenID back to user because it was deleted during
336 openid
= OpenIDUserURL()
337 openid
.openid_url
= 'http://add.myopenid.com'
338 openid
.user_id
= test_user
.id
341 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
342 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
343 def _test_delete(self
, test_user
):
344 # Delete openid from user
345 # Create another user to test deleting OpenID that doesn't belong to them
346 new_user
= fixture_add_user(username
='newman')
347 openid
= OpenIDUserURL()
348 openid
.openid_url
= 'http://realfake.myopenid.com/'
349 openid
.user_id
= new_user
.id
352 # Try and delete OpenID url that isn't the users
353 template
.clear_test_template_context()
354 res
= openid_plugin_app
.post(
355 '/edit/openid/delete/', {
356 'openid': 'http://realfake.myopenid.com/'})
357 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/delete.html']
358 form
= context
['form']
359 assert form
.openid
.errors
== [u
'That OpenID is not registered to this account.']
362 # Kind of weird to POST to delete/finish
363 template
.clear_test_template_context()
364 res
= openid_plugin_app
.post(
365 '/edit/openid/delete/finish/', {
366 'openid': u
'http://add.myopenid.com'})
370 assert urlparse
.urlsplit(res
.location
)[2] == '/edit/account/'
371 assert 'mediagoblin/edit/edit_account.html' in template
.TEMPLATE_TEST_CONTEXT
374 new_openid
= mg_globals
.database
.OpenIDUserURL
.query
.filter_by(
375 openid_url
=u
'http://add.myopenid.com').first()
376 assert not new_openid
378 _test_delete(self
, test_user
)