Use urljoin to create proper feed media URLs
[larjonas-mediagoblin.git] / mediagoblin / tests / test_openid.py
blob71767032e892b54c8ef3cef431393f54269452d9
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/>.
17 import pkg_resources
18 import pytest
19 import six
20 import six.moves.urllib.parse as urlparse
21 try:
22 import mock
23 except ImportError:
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
38 @pytest.fixture()
39 def openid_plugin_app(request):
40 return get_app(
41 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):
49 if value:
50 response = openid_consumer.SuccessResponse(mock.Mock(), mock.Mock())
51 if edit or delete:
52 response.identity_url = u'http://add.myopenid.com'
53 else:
54 response.identity_url = u'http://real.myopenid.com'
55 self._finish_verification = mock.Mock(return_value=response)
56 else:
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):
63 if edit:
64 self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
65 '/edit/openid/finish/'))
66 elif delete:
67 self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
68 '/edit/openid/delete/finish/'))
69 else:
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/')
85 res.follow()
87 # Correct redirect?
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/')
92 res.follow()
94 # Correct redirect?
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/')
99 res.follow()
101 # Correct redirect?
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/')
107 # Correct place?
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
130 # Phony OpenID URl
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/'})
151 res.follow()
153 # Correct Place?
154 assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
155 assert 'mediagoblin/plugins/openid/login.html' in template.TEMPLATE_TEST_CONTEXT
156 _test_non_response()
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'})
170 # Right place?
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']
175 # Register User
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'})
181 res.follow()
183 # Correct place?
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
191 # Logout User
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'
197 ).first()
198 Session.expunge(test_user)
200 # Log back in
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'})
206 res.follow()
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)
216 _test_new_user()
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"""
245 # Add user
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
250 openid.save()
252 # Log user in
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)
258 def _login_user():
259 openid_plugin_app.post(
260 '/auth/openid/login/finish/', {
261 'openid': u'http://real.myopenid.com'})
263 _login_user()
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
272 # Add OpenID to user
273 # Empty form
274 template.clear_test_template_context()
275 res = openid_plugin_app.post(
276 '/edit/openid/', {})
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.']
281 # Try with a bad url
282 template.clear_test_template_context()
283 openid_plugin_app.post(
284 '/edit/openid/', {
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(
293 '/edit/openid/', {
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')
307 openid.delete()
309 @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
310 @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
311 def _test_add():
312 # Successful add
313 template.clear_test_template_context()
314 res = openid_plugin_app.post(
315 '/edit/openid/', {
316 'openid': u'http://add.myopenid.com'})
317 res.follow()
319 # Correct place?
320 assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
321 assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
323 # OpenID Added?
324 new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
325 openid_url=u'http://add.myopenid.com').first()
326 assert new_openid
328 _test_add()
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
336 # patch
337 openid = OpenIDUserURL()
338 openid.openid_url = 'http://add.myopenid.com'
339 openid.user_id = test_user.id
340 openid.save()
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
351 openid.save()
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.']
362 # Delete OpenID
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'})
368 res.follow()
370 # Correct place?
371 assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
372 assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
374 # OpenID deleted?
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)