Merge remote-tracking branch 'tilly-q/OPW-Moderation-Update' into merge-tillyq-moderation
[mediagoblin.git] / mediagoblin / tests / test_openid.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
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.
8 #
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.
13 #
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/>.
16
17 import urlparse
18 import pkg_resources
19 import pytest
20 import mock
21
22 openid_consumer = pytest.importorskip(
23 "openid.consumer.consumer")
24
25 from mediagoblin import mg_globals
26 from mediagoblin.db.base import Session
27 from mediagoblin.db.models import User
28 from mediagoblin.plugins.openid.models import OpenIDUserURL
29 from mediagoblin.tests.tools import get_app, fixture_add_user
30 from mediagoblin.tools import template
31
32
33 # App with plugin enabled
34 @pytest.fixture()
35 def openid_plugin_app(request):
36 return get_app(
37 request,
38 mgoblin_config=pkg_resources.resource_filename(
39 'mediagoblin.tests.auth_configs',
40 'openid_appconfig.ini'))
41
42
43 class TestOpenIDPlugin(object):
44 def _setup(self, openid_plugin_app, value=True, edit=False, delete=False):
45 if value:
46 response = openid_consumer.SuccessResponse(mock.Mock(), mock.Mock())
47 if edit or delete:
48 response.identity_url = u'http://add.myopenid.com'
49 else:
50 response.identity_url = u'http://real.myopenid.com'
51 self._finish_verification = mock.Mock(return_value=response)
52 else:
53 self._finish_verification = mock.Mock(return_value=False)
54
55 @mock.patch('mediagoblin.plugins.openid.views._response_email', mock.Mock(return_value=None))
56 @mock.patch('mediagoblin.plugins.openid.views._response_nickname', mock.Mock(return_value=None))
57 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
58 def _setup_start(self, openid_plugin_app, edit, delete):
59 if edit:
60 self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
61 '/edit/openid/finish/'))
62 elif delete:
63 self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
64 '/edit/openid/delete/finish/'))
65 else:
66 self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
67 '/auth/openid/login/finish/'))
68 _setup_start(self, openid_plugin_app, edit, delete)
69
70 def test_bad_login(self, openid_plugin_app):
71 """ Test that attempts to login with invalid paramaters"""
72
73 # Test GET request for auth/register page
74 res = openid_plugin_app.get('/auth/register/').follow()
75
76 # Make sure it redirected to the correct place
77 assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
78
79 # Test GET request for auth/login page
80 res = openid_plugin_app.get('/auth/login/')
81 res.follow()
82
83 # Correct redirect?
84 assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
85
86 # Test GET request for auth/openid/register page
87 res = openid_plugin_app.get('/auth/openid/register/')
88 res.follow()
89
90 # Correct redirect?
91 assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
92
93 # Test GET request for auth/openid/login/finish page
94 res = openid_plugin_app.get('/auth/openid/login/finish/')
95 res.follow()
96
97 # Correct redirect?
98 assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
99
100 # Test GET request for auth/openid/login page
101 res = openid_plugin_app.get('/auth/openid/login/')
102
103 # Correct place?
104 assert 'mediagoblin/plugins/openid/login.html' in template.TEMPLATE_TEST_CONTEXT
105
106 # Try to login with an empty form
107 template.clear_test_template_context()
108 openid_plugin_app.post(
109 '/auth/openid/login/', {})
110 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
111 form = context['login_form']
112 assert form.openid.errors == [u'This field is required.']
113
114 # Try to login with wrong form values
115 template.clear_test_template_context()
116 openid_plugin_app.post(
117 '/auth/openid/login/', {
118 'openid': 'not_a_url.com'})
119 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
120 form = context['login_form']
121 assert form.openid.errors == [u'Please enter a valid url.']
122
123 # Should be no users in the db
124 assert User.query.count() == 0
125
126 # Phony OpenID URl
127 template.clear_test_template_context()
128 openid_plugin_app.post(
129 '/auth/openid/login/', {
130 'openid': 'http://phoney.myopenid.com/'})
131 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
132 form = context['login_form']
133 assert form.openid.errors == [u'Sorry, the OpenID server could not be found']
134
135 def test_login(self, openid_plugin_app):
136 """Tests that test login and registion with openid"""
137 # Test finish_login redirects correctly when response = False
138 self._setup(openid_plugin_app, False)
139
140 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
141 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
142 def _test_non_response():
143 template.clear_test_template_context()
144 res = openid_plugin_app.post(
145 '/auth/openid/login/', {
146 'openid': 'http://phoney.myopenid.com/'})
147 res.follow()
148
149 # Correct Place?
150 assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
151 assert 'mediagoblin/plugins/openid/login.html' in template.TEMPLATE_TEST_CONTEXT
152 _test_non_response()
153
154 # Test login with new openid
155 # Need to clear_test_template_context before calling _setup
156 template.clear_test_template_context()
157 self._setup(openid_plugin_app)
158
159 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
160 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
161 def _test_new_user():
162 openid_plugin_app.post(
163 '/auth/openid/login/', {
164 'openid': u'http://real.myopenid.com'})
165
166 # Right place?
167 assert 'mediagoblin/auth/register.html' in template.TEMPLATE_TEST_CONTEXT
168 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
169 register_form = context['register_form']
170
171 # Register User
172 res = openid_plugin_app.post(
173 '/auth/openid/register/', {
174 'openid': register_form.openid.data,
175 'username': u'chris',
176 'email': u'chris@example.com'})
177 res.follow()
178
179 # Correct place?
180 assert urlparse.urlsplit(res.location)[2] == '/u/chris/'
181 assert 'mediagoblin/user_pages/user_nonactive.html' in template.TEMPLATE_TEST_CONTEXT
182
183 # No need to test if user is in logged in and verification email
184 # awaits, since openid uses the register_user function which is
185 # tested in test_auth
186
187 # Logout User
188 openid_plugin_app.get('/auth/logout')
189
190 # Get user and detach from session
191 test_user = mg_globals.database.User.query.filter_by(
192 username=u'chris').first()
193 Session.expunge(test_user)
194
195 # Log back in
196 # Could not get it to work by 'POST'ing to /auth/openid/login/
197 template.clear_test_template_context()
198 res = openid_plugin_app.post(
199 '/auth/openid/login/finish/', {
200 'openid': u'http://real.myopenid.com'})
201 res.follow()
202
203 assert urlparse.urlsplit(res.location)[2] == '/'
204 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
205
206 # Make sure user is in the session
207 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
208 session = context['request'].session
209 assert session['user_id'] == unicode(test_user.id)
210
211 _test_new_user()
212
213 # Test register with empty form
214 template.clear_test_template_context()
215 openid_plugin_app.post(
216 '/auth/openid/register/', {})
217 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
218 register_form = context['register_form']
219
220 assert register_form.openid.errors == [u'This field is required.']
221 assert register_form.email.errors == [u'This field is required.']
222 assert register_form.username.errors == [u'This field is required.']
223
224 # Try to register with existing username and email
225 template.clear_test_template_context()
226 openid_plugin_app.post(
227 '/auth/openid/register/', {
228 'openid': 'http://real.myopenid.com',
229 'email': 'chris@example.com',
230 'username': 'chris'})
231 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
232 register_form = context['register_form']
233
234 assert register_form.username.errors == [u'Sorry, a user with that name already exists.']
235 assert register_form.email.errors == [u'Sorry, a user with that email address already exists.']
236 assert register_form.openid.errors == [u'Sorry, an account is already registered to that OpenID.']
237
238 def test_add_delete(self, openid_plugin_app):
239 """Test adding and deleting openids"""
240 # Add user
241 test_user = fixture_add_user(password='', privileges=[u'active'])
242 openid = OpenIDUserURL()
243 openid.openid_url = 'http://real.myopenid.com'
244 openid.user_id = test_user.id
245 openid.save()
246
247 # Log user in
248 template.clear_test_template_context()
249 self._setup(openid_plugin_app)
250
251 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
252 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
253 def _login_user():
254 openid_plugin_app.post(
255 '/auth/openid/login/finish/', {
256 'openid': u'http://real.myopenid.com'})
257
258 _login_user()
259
260 # Try and delete only OpenID url
261 template.clear_test_template_context()
262 res = openid_plugin_app.post(
263 '/edit/openid/delete/', {
264 'openid': 'http://real.myopenid.com'})
265 assert 'mediagoblin/plugins/openid/delete.html' in template.TEMPLATE_TEST_CONTEXT
266
267 # Add OpenID to user
268 # Empty form
269 template.clear_test_template_context()
270 res = openid_plugin_app.post(
271 '/edit/openid/', {})
272 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
273 form = context['form']
274 assert form.openid.errors == [u'This field is required.']
275
276 # Try with a bad url
277 template.clear_test_template_context()
278 openid_plugin_app.post(
279 '/edit/openid/', {
280 'openid': u'not_a_url.com'})
281 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
282 form = context['form']
283 assert form.openid.errors == [u'Please enter a valid url.']
284
285 # Try with a url that's already registered
286 template.clear_test_template_context()
287 openid_plugin_app.post(
288 '/edit/openid/', {
289 'openid': 'http://real.myopenid.com'})
290 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
291 form = context['form']
292 assert form.openid.errors == [u'Sorry, an account is already registered to that OpenID.']
293
294 # Test adding openid to account
295 # Need to clear_test_template_context before calling _setup
296 template.clear_test_template_context()
297 self._setup(openid_plugin_app, edit=True)
298
299 # Need to remove openid_url from db because it was added at setup
300 openid = OpenIDUserURL.query.filter_by(
301 openid_url=u'http://add.myopenid.com')
302 openid.delete()
303
304 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
305 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
306 def _test_add():
307 # Successful add
308 template.clear_test_template_context()
309 res = openid_plugin_app.post(
310 '/edit/openid/', {
311 'openid': u'http://add.myopenid.com'})
312 res.follow()
313
314 # Correct place?
315 assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
316 assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
317
318 # OpenID Added?
319 new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
320 openid_url=u'http://add.myopenid.com').first()
321 assert new_openid
322
323 _test_add()
324
325 # Test deleting openid from account
326 # Need to clear_test_template_context before calling _setup
327 template.clear_test_template_context()
328 self._setup(openid_plugin_app, delete=True)
329
330 # Need to add OpenID back to user because it was deleted during
331 # patch
332 openid = OpenIDUserURL()
333 openid.openid_url = 'http://add.myopenid.com'
334 openid.user_id = test_user.id
335 openid.save()
336
337 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
338 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
339 def _test_delete(self, test_user):
340 # Delete openid from user
341 # Create another user to test deleting OpenID that doesn't belong to them
342 new_user = fixture_add_user(username='newman')
343 openid = OpenIDUserURL()
344 openid.openid_url = 'http://realfake.myopenid.com/'
345 openid.user_id = new_user.id
346 openid.save()
347
348 # Try and delete OpenID url that isn't the users
349 template.clear_test_template_context()
350 res = openid_plugin_app.post(
351 '/edit/openid/delete/', {
352 'openid': 'http://realfake.myopenid.com/'})
353 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/delete.html']
354 form = context['form']
355 assert form.openid.errors == [u'That OpenID is not registered to this account.']
356
357 # Delete OpenID
358 # Kind of weird to POST to delete/finish
359 template.clear_test_template_context()
360 res = openid_plugin_app.post(
361 '/edit/openid/delete/finish/', {
362 'openid': u'http://add.myopenid.com'})
363 res.follow()
364
365 # Correct place?
366 assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
367 assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
368
369 # OpenID deleted?
370 new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
371 openid_url=u'http://add.myopenid.com').first()
372 assert not new_openid
373
374 _test_delete(self, test_user)