From 460def09da3c3838d467fce885ec113da581655c Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Mon, 8 Oct 2018 12:07:04 +0200 Subject: [PATCH] launch tests with Django 1.11 (fixes #27095) --- Jenkinsfile | 8 ++++++-- src/authentic2_auth_fc/views.py | 12 +++++++++++- tests/test_auth_fc.py | 25 +++++++++++++++++-------- tox.ini | 6 ++++-- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d7dfe26..05f8aab 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -25,9 +25,13 @@ pipeline { utils.mail_notify(currentBuild, env, 'admin+jenkins-authentic2-auth-fc@entrouvert.com') utils.publish_coverage('coverage-*.xml') utils.publish_coverage_native( - 'index.html', 'htmlcov-coverage-dj18-pg', 'Coverage a2-auth-fc PG') + 'index.html', 'htmlcov-coverage-dj18-pg', 'Coverage a2-auth-fc dj18 PG') utils.publish_coverage_native( - 'index.html', 'htmlcov-coverage-dj18-sqlite', 'Coverage a2-auth-fc SQLITE') + 'index.html', 'htmlcov-coverage-dj18-sqlite', 'Coverage a2-auth-fc dj18 SQLITE') + utils.publish_coverage_native( + 'index.html', 'htmlcov-coverage-dj111-pg', 'Coverage a2-auth-fc dj111 PG') + utils.publish_coverage_native( + 'index.html', 'htmlcov-coverage-dj111-sqlite', 'Coverage a2-auth-fc dj111 SQLITE') utils.publish_pylint('pylint.out') } junit 'junit-*.xml' diff --git a/src/authentic2_auth_fc/views.py b/src/authentic2_auth_fc/views.py index eb2d8e4..5790977 100644 --- a/src/authentic2_auth_fc/views.py +++ b/src/authentic2_auth_fc/views.py @@ -8,6 +8,7 @@ import requests from requests_oauthlib import OAuth2Session +import django from django.views.generic import View, FormView from django.views.generic.detail import SingleObjectMixin from django.http import HttpResponseRedirect, Http404 @@ -22,6 +23,10 @@ from django.core.cache import InvalidCacheBackendError, caches from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from django.forms import Form +try: + from django.contrib.auth.views import update_session_auth_hash +except ImportError: + update_session_auth_hash = None from authentic2 import app_settings as a2_app_settings from authentic2 import utils as a2_utils, hooks, constants @@ -150,7 +155,11 @@ class FcOAuthSessionViewMixin(LoggerMixin): else: redirect_to = request.GET.get(self.redirect_field_name, '') - if not is_safe_url(url=redirect_to, host=request.get_host()): + if django.VERSION < (1, 11): + safe = is_safe_url(url=redirect_to, host=request.get_host()) + else: + safe = is_safe_url(url=redirect_to, allowed_hosts=[request.get_host()]) + if not safe: redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL) return redirect_to @@ -523,6 +532,7 @@ class UnlinkView(LoggerMixin, FormView): def form_valid(self, form): if self.must_set_password(): form.save() + update_session_auth_hash(self.request, self.request.user) self.logger.info(u'user %s has set a password', self.request.user) links = models.FcAccount.objects.filter(user=self.request.user) for link in links: diff --git a/tests/test_auth_fc.py b/tests/test_auth_fc.py index 38e55d4..09ed579 100644 --- a/tests/test_auth_fc.py +++ b/tests/test_auth_fc.py @@ -24,6 +24,15 @@ from authentic2_auth_fc.utils import requests_retry_session User = get_user_model() +def path(url): + return urlparse.urlparse(url).path + + +def path_and_query(url): + parsed = urlparse.urlparse(url) + return parsed.path + '?' + parsed.query + + def get_links_from_mail(mail): '''Extract links from mail sent by Django''' return re.findall('https?://[^ \n]*', mail.body) @@ -113,7 +122,7 @@ def test_login_simple(app, fc_settings, caplog, hooks, exp): else: assert User.objects.count() == 1 if User.objects.count(): - assert response['Location'] == 'http://testserver/idp/' + assert path(response['Location']) == '/idp/' assert hooks.event[1]['kwargs']['name'] == 'login' assert hooks.event[1]['kwargs']['service'] == 'portail' # we must be connected @@ -130,7 +139,7 @@ def test_login_simple(app, fc_settings, caplog, hooks, exp): state = urlparse.parse_qs(urlparse.urlparse(continue_url).query)['state'][0] assert app.session['fc_states'][state]['next'] == '/accounts/' response = app.get(reverse('fc-logout') + '?state=' + state) - assert response['Location'] == 'http://testserver/accounts/' + assert path(response['Location']) == '/accounts/' def test_login_email_is_unique(app, fc_settings, caplog): @@ -327,7 +336,7 @@ def test_registration1(app, fc_settings, caplog, hooks): with httmock.HTTMock(access_token_response, user_info_response): response = app.get(callback + '&code=zzz&state=%s' % state, status=302) assert User.objects.count() == 0 - assert response['Location'].startswith('http://testserver/login/') + assert path(response['Location']) == '/login/' response = response.follow() response = response.click('Create your account with FranceConnect') location = response['Location'] @@ -336,7 +345,7 @@ def test_registration1(app, fc_settings, caplog, hooks): assert hooks.calls['event'][0]['kwargs']['service'] == 'portail' # we must be connected assert app.session['_auth_user_id'] - assert response['Location'].startswith(callback) + assert path_and_query(response['Location']) == path_and_query(callback) response = response.follow() location = response['Location'] state = check_authorization_url(location) @@ -354,7 +363,7 @@ def test_registration1(app, fc_settings, caplog, hooks): state = urlparse.parse_qs(urlparse.urlparse(continue_url).query)['state'][0] assert app.session['fc_states'][state]['next'] == '/accounts/' response = app.get(reverse('fc-logout') + '?state=' + state) - assert response['Location'] == 'http://testserver/accounts/' + assert path(response['Location']) == '/accounts/' def test_registration2(app, fc_settings, caplog, hooks): @@ -406,7 +415,7 @@ def test_registration2(app, fc_settings, caplog, hooks): with httmock.HTTMock(access_token_response, user_info_response): response = app.get(callback + '&code=zzz&state=%s' % state, status=302) assert User.objects.count() == 0 - assert response['Location'].startswith('http://testserver/accounts/fc/register/') + assert path(response['Location']) == '/accounts/fc/register/' response = response.follow() location = response['Location'] location.startswith('http://testserver/accounts/activate/') @@ -419,7 +428,7 @@ def test_registration2(app, fc_settings, caplog, hooks): callback = callback.replace('®istration=', '') callback = callback.replace('?registration=', '?') callback = callback.replace('?&', '?') - assert response['Location'].startswith(callback) + assert path_and_query(response['Location']) == path_and_query(callback) response = response.follow() location = response['Location'] state = check_authorization_url(location) @@ -437,4 +446,4 @@ def test_registration2(app, fc_settings, caplog, hooks): state = urlparse.parse_qs(urlparse.urlparse(continue_url).query)['state'][0] assert app.session['fc_states'][state]['next'] == '/accounts/' response = app.get(reverse('fc-logout') + '?state=' + state) - assert response['Location'] == 'http://testserver/accounts/' + assert path(response['Location']) == '/accounts/' diff --git a/tox.ini b/tox.ini index 066ebd7..0d73357 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ [tox] toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/authentic2-auth-fc/ -envlist = coverage-dj18-{pg,sqlite} +envlist = coverage-{dj18,dj111}-{pg,sqlite} [testenv] whitelist_externals = @@ -24,6 +24,8 @@ usedevelop = deps = dj18: django>1.8,<1.9 dj18: django-tables2<1.1 + dj111: django<2.0 + dj111: django-tables<2.0 pg: psycopg2 coverage pytest-cov @@ -34,7 +36,7 @@ deps = cssselect pylint pylint-django - django-webtest + django-webtest<1.9.3 WebTest pyquery httmock