Projet

Général

Profil

0001-auth_oidc-show-a-warning-message-if-target-user-is-a.patch

Benjamin Dauvergne, 17 octobre 2022 10:10

Télécharger (5,47 ko)

Voir les différences:

Subject: [PATCH] auth_oidc: show a warning message if target user is already
 linked to another provider (#65692)

 src/authentic2_auth_oidc/backends.py | 28 ++++++++++++++++++-----
 src/authentic2_auth_oidc/views.py    |  2 --
 tests/test_auth_oidc.py              | 33 ++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 7 deletions(-)
src/authentic2_auth_oidc/backends.py
19 19

  
20 20
import requests
21 21
from django.conf import settings
22
from django.contrib import messages
22 23
from django.contrib.auth import get_user_model
23 24
from django.contrib.auth.backends import ModelBackend
24
from django.db.transaction import atomic
25
from django.db import IntegrityError
26
from django.db.transaction import atomic, set_rollback
25 27
from django.utils.timezone import now
28
from django.utils.translation import gettext as _
26 29
from jwcrypto.jwk import JWK
27 30
from jwcrypto.jwt import JWT
28 31

  
......
38 41
class OIDCBackend(ModelBackend):
39 42
    # pylint: disable=arguments-renamed
40 43
    def authenticate(self, request, access_token=None, id_token=None, nonce=None, provider=None):
41
        with atomic(savepoint=False):
44
        with atomic():
42 45
            return self._authenticate(
43 46
                request, access_token=access_token, id_token=id_token, nonce=nonce, provider=provider
44 47
            )
......
312 315
                    user = User.objects.create(ou=provider.ou, email=email or '')
313 316
                    user.set_unusable_password()
314 317
                    created_user = True
315
                oidc_account, created = models.OIDCAccount.objects.get_or_create(
316
                    provider=provider, user=user, defaults={'sub': id_token.sub}
317
                )
318
                try:
319
                    oidc_account, created = models.OIDCAccount.objects.get_or_create(
320
                        provider=provider, user=user, defaults={'sub': id_token.sub}
321
                    )
322
                except IntegrityError:
323
                    set_rollback(True)
324
                    logger.warning('auth_oidc: email %s is already linked to another provider.', email)
325
                    if request:
326
                        messages.warning(
327
                            request,
328
                            _(
329
                                'Your email is already linked to another SSO account, please contact an administrator.'
330
                            ),
331
                        )
332
                        return None
333

  
318 334
                if not created and oidc_account.sub != id_token.sub:
319 335
                    logger.info(
320 336
                        'auth_oidc: changed user %s sub from %s to %s (issuer %s)',
......
326 342
                    oidc_account.sub = id_token.sub
327 343
                    oidc_account.save()
328 344
            else:
345
                if request:
346
                    messages.warning(request, _('No user found'))
329 347
                logger.warning(
330 348
                    'auth_oidc: cannot create user for sub %r as issuer %r does not allow it',
331 349
                    id_token.sub,
src/authentic2_auth_oidc/views.py
295 295
                    'provider_pk': provider.pk,
296 296
                }
297 297
            )
298
        else:
299
            messages.warning(request, _('No user found'))
300 298
        return self.continue_to_next_url(request)
301 299

  
302 300
    errors = {
tests/test_auth_oidc.py
1337 1337

  
1338 1338
    user = User.objects.get()
1339 1339
    assert simple_role in user.roles.all()
1340

  
1341

  
1342
def test_double_link(app, caplog, code, simple_user, oidc_provider_jwkset):
1343
    ou = get_default_ou()
1344
    ou.email_is_unique = True
1345
    ou.save()
1346
    provider1 = make_oidc_provider(name='provider1', jwkset=oidc_provider_jwkset)
1347
    provider2 = make_oidc_provider(name='provider2', jwkset=oidc_provider_jwkset)
1348

  
1349
    OIDCAccount.objects.create(provider=provider2, sub='1234', user=simple_user)
1350

  
1351
    response = app.get('/').maybe_follow()
1352
    response = response.click('provider1')
1353
    location = urllib.parse.urlparse(response.location)
1354
    query = QueryDict(location.query)
1355
    state = query['state']
1356
    nonce = query['nonce']
1357

  
1358
    # sub=john.doe
1359
    with utils.check_log(caplog, 'auth_oidc: email user@example.net is already linked'):
1360
        with oidc_provider_mock(
1361
            provider1,
1362
            oidc_provider_jwkset,
1363
            code,
1364
            nonce=nonce,
1365
            extra_id_token={'email': simple_user.email},
1366
            extra_user_info={'email': simple_user.email},
1367
        ):
1368
            response = app.get(login_callback_url(provider1), params={'code': code, 'state': state})
1369
        response = response.maybe_follow()
1370
    warnings = response.pyquery('.warning')
1371
    assert len(warnings) == 1
1372
    assert 'Your email is already linked' in warnings.text()
1340
-