From 8a83aa408e74e2554f2e1c5fea12be8f594bc8a6 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sun, 11 Feb 2018 22:42:43 +0100 Subject: [PATCH] views: show warning to users with a mail linked to another FC account (fixes #21292) The warning will help them connect their FC account to normally registered account. --- src/authentic2_auth_fc/views.py | 10 ++++---- tests/test_auth_fc.py | 52 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/authentic2_auth_fc/views.py b/src/authentic2_auth_fc/views.py index 80e1afa..1562f3d 100644 --- a/src/authentic2_auth_fc/views.py +++ b/src/authentic2_auth_fc/views.py @@ -403,11 +403,11 @@ class LoginOrLinkView(PopupViewMixin, FcOAuthSessionViewMixin, View): user = authenticate(sub=self.sub, user_info=self.user_info, token=self.token) else: - self.logger.warning(u'account with email %s already linked to another sub ' - u'%s, logging anyway', - email, user.fc_accounts.values_list('sub', flat=True)) - # login the user anyway, but do not update its user_info, it's not ideal - a2_utils.simulate_login(user, 'france-connect', service_slug=self.service_slug) + messages.warning( + request, + _('Your FranceConnect email \'%s\' is already used by another account, ' + 'so we cannot create an account for you, please create an account ' + 'with another email then link your FranceConnect.') % email) return self.redirect(request) if user: a2_utils.login(request, user, 'france-connect', service_slug=self.service_slug) diff --git a/tests/test_auth_fc.py b/tests/test_auth_fc.py index c3b5b0b..77461ef 100644 --- a/tests/test_auth_fc.py +++ b/tests/test_auth_fc.py @@ -162,3 +162,55 @@ def test_login_email_is_unique(app, fc_settings, caplog): with httmock.HTTMock(access_token_response, user_info_response): response = app.get(callback + '?code=zzz&state=%s' % state, status=302) assert User.objects.count() == 1 + assert app.session['_auth_user_id'] + + +def test_login_email_is_unique_and_already_linked(app, fc_settings, caplog): + callback = reverse('fc-login-or-link') + response = app.get(callback, status=302) + location = response['Location'] + state = check_authorization_url(location) + + EMAIL = 'john.doe@example.com' + SUB = '1234' + user = User.objects.create(email=EMAIL, first_name='John', last_name='Doe') + models.FcAccount.objects.create(user=user, sub='4567', token='xxx', user_info='{}') + + @httmock.urlmatch(path=r'.*/token$') + def access_token_response(url, request): + parsed = {x: y[0] for x, y in urlparse.parse_qs(request.body).items()} + assert set(parsed.keys()) == set(['code', 'client_id', 'client_secret', 'redirect_uri', + 'grant_type']) + assert parsed['code'] == 'zzz' + assert parsed['client_id'] == 'xxx' + assert parsed['client_secret'] == 'yyy' + assert parsed['grant_type'] == 'authorization_code' + assert callback in parsed['redirect_uri'] + id_token = { + 'sub': SUB, + 'aud': 'xxx', + 'nonce': state, + 'exp': timestamp_from_datetime(now() + datetime.timedelta(seconds=1000)), + 'iss': 'https://fcp.integ01.dev-franceconnect.fr/', + } + return json.dumps({ + 'access_token': 'uuu', + 'id_token': hmac_jwt(id_token, 'yyy') + }) + + @httmock.urlmatch(path=r'.*userinfo$') + def user_info_response(url, request): + assert request.headers['Authorization'] == 'Bearer uuu' + return json.dumps({ + 'sub': '1234', + 'family_name': u'Frédérique', + 'given_name': u'Ÿuñe', + 'email': EMAIL, + }) + + fc_settings.A2_EMAIL_IS_UNIQUE = True + with httmock.HTTMock(access_token_response, user_info_response): + response = app.get(callback + '?code=zzz&state=%s' % state, status=302) + assert 'is already used' in str(response) + assert User.objects.count() == 1 + assert '_auth_user_id' not in app.session -- 2.14.2