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
, LocalUser
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
.LocalUser
.query
.filter(
196 LocalUser
.username
==u
'chris'
198 Session
.expunge(test_user
)
201 # Could not get it to work by 'POST'ing to /auth/openid/login/
202 template
.clear_test_template_context()
203 res
= openid_plugin_app
.post(
204 '/auth/openid/login/finish/', {
205 'openid': u
'http://real.myopenid.com'})
208 assert urlparse
.urlsplit(res
.location
)[2] == '/'
209 assert 'mediagoblin/root.html' in template
.TEMPLATE_TEST_CONTEXT
211 # Make sure user is in the session
212 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/root.html']
213 session
= context
['request'].session
214 assert session
['user_id'] == six
.text_type(test_user
.id)
218 # Test register with empty form
219 template
.clear_test_template_context()
220 openid_plugin_app
.post(
221 '/auth/openid/register/', {})
222 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
223 register_form
= context
['register_form']
225 assert register_form
.openid
.errors
== [u
'This field is required.']
226 assert register_form
.email
.errors
== [u
'This field is required.']
227 assert register_form
.username
.errors
== [u
'This field is required.']
229 # Try to register with existing username and email
230 template
.clear_test_template_context()
231 openid_plugin_app
.post(
232 '/auth/openid/register/', {
233 'openid': 'http://real.myopenid.com',
234 'email': 'chris@example.com',
235 'username': 'chris'})
236 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/auth/register.html']
237 register_form
= context
['register_form']
239 assert register_form
.username
.errors
== [u
'Sorry, a user with that name already exists.']
240 assert register_form
.email
.errors
== [u
'Sorry, a user with that email address already exists.']
241 assert register_form
.openid
.errors
== [u
'Sorry, an account is already registered to that OpenID.']
243 def test_add_delete(self
, openid_plugin_app
):
244 """Test adding and deleting openids"""
246 test_user
= fixture_add_user(password
='', privileges
=[u
'active'])
247 openid
= OpenIDUserURL()
248 openid
.openid_url
= 'http://real.myopenid.com'
249 openid
.user_id
= test_user
.id
253 template
.clear_test_template_context()
254 self
._setup
(openid_plugin_app
)
256 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
257 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
259 openid_plugin_app
.post(
260 '/auth/openid/login/finish/', {
261 'openid': u
'http://real.myopenid.com'})
265 # Try and delete only OpenID url
266 template
.clear_test_template_context()
267 res
= openid_plugin_app
.post(
268 '/edit/openid/delete/', {
269 'openid': 'http://real.myopenid.com'})
270 assert 'mediagoblin/plugins/openid/delete.html' in template
.TEMPLATE_TEST_CONTEXT
274 template
.clear_test_template_context()
275 res
= openid_plugin_app
.post(
277 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/add.html']
278 form
= context
['form']
279 assert form
.openid
.errors
== [u
'This field is required.']
282 template
.clear_test_template_context()
283 openid_plugin_app
.post(
285 'openid': u
'not_a_url.com'})
286 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/add.html']
287 form
= context
['form']
288 assert form
.openid
.errors
== [u
'Please enter a valid url.']
290 # Try with a url that's already registered
291 template
.clear_test_template_context()
292 openid_plugin_app
.post(
294 'openid': 'http://real.myopenid.com'})
295 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/add.html']
296 form
= context
['form']
297 assert form
.openid
.errors
== [u
'Sorry, an account is already registered to that OpenID.']
299 # Test adding openid to account
300 # Need to clear_test_template_context before calling _setup
301 template
.clear_test_template_context()
302 self
._setup
(openid_plugin_app
, edit
=True)
304 # Need to remove openid_url from db because it was added at setup
305 openid
= OpenIDUserURL
.query
.filter_by(
306 openid_url
=u
'http://add.myopenid.com')
309 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
310 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
313 template
.clear_test_template_context()
314 res
= openid_plugin_app
.post(
316 'openid': u
'http://add.myopenid.com'})
320 assert urlparse
.urlsplit(res
.location
)[2] == '/edit/account/'
321 assert 'mediagoblin/edit/edit_account.html' in template
.TEMPLATE_TEST_CONTEXT
324 new_openid
= mg_globals
.database
.OpenIDUserURL
.query
.filter_by(
325 openid_url
=u
'http://add.myopenid.com').first()
330 # Test deleting openid from account
331 # Need to clear_test_template_context before calling _setup
332 template
.clear_test_template_context()
333 self
._setup
(openid_plugin_app
, delete
=True)
335 # Need to add OpenID back to user because it was deleted during
337 openid
= OpenIDUserURL()
338 openid
.openid_url
= 'http://add.myopenid.com'
339 openid
.user_id
= test_user
.id
342 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self
._finish
_verification
)
343 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self
._start
_verification
)
344 def _test_delete(self
, test_user
):
345 # Delete openid from user
346 # Create another user to test deleting OpenID that doesn't belong to them
347 new_user
= fixture_add_user(username
='newman')
348 openid
= OpenIDUserURL()
349 openid
.openid_url
= 'http://realfake.myopenid.com/'
350 openid
.user_id
= new_user
.id
353 # Try and delete OpenID url that isn't the users
354 template
.clear_test_template_context()
355 res
= openid_plugin_app
.post(
356 '/edit/openid/delete/', {
357 'openid': 'http://realfake.myopenid.com/'})
358 context
= template
.TEMPLATE_TEST_CONTEXT
['mediagoblin/plugins/openid/delete.html']
359 form
= context
['form']
360 assert form
.openid
.errors
== [u
'That OpenID is not registered to this account.']
363 # Kind of weird to POST to delete/finish
364 template
.clear_test_template_context()
365 res
= openid_plugin_app
.post(
366 '/edit/openid/delete/finish/', {
367 'openid': u
'http://add.myopenid.com'})
371 assert urlparse
.urlsplit(res
.location
)[2] == '/edit/account/'
372 assert 'mediagoblin/edit/edit_account.html' in template
.TEMPLATE_TEST_CONTEXT
375 new_openid
= mg_globals
.database
.OpenIDUserURL
.query
.filter_by(
376 openid_url
=u
'http://add.myopenid.com').first()
377 assert not new_openid
379 _test_delete(self
, test_user
)