auth_oidc: handle case of multiple users with same email but email should be unique (#48339)

This commit is contained in:
Benjamin Dauvergne 2020-11-06 10:22:12 +01:00
parent 7fdf868b5c
commit b2f926388b
2 changed files with 53 additions and 0 deletions

View File

@ -239,6 +239,11 @@ class OIDCBackend(ModelBackend):
linked = True
except User.DoesNotExist:
pass
except User.MultipleObjectsReturned:
logger.error('auth_oidc: cannot create user with sub "%s", '
'too many users with the same email "%s" in ou "%s"',
id_token.sub, email, provider.ou)
return
if not user:
user = User.objects.create(ou=provider.ou)
user.set_unusable_password()

View File

@ -862,3 +862,51 @@ def test_save_account_on_delete_user(db):
'sub': '1234',
}
]
def test_multiple_users_with_same_email(app, caplog, code, oidc_provider_jwkset, hooks):
oidc_provider = make_oidc_provider(idtoken_algo=OIDCProvider.ALGO_HMAC)
ou = get_default_ou()
ou.email_is_unique = True
ou.save()
user1 = User.objects.create(ou=ou, email='john.doe@example.com')
assert OIDCAccount.objects.count() == 0
response = app.get('/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
location = urlparse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
# sub=john.doe, MUST not work
with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, nonce=nonce):
response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state})
assert app.session['_auth_user_id'] == str(user1.id)
assert OIDCAccount.objects.count() == 1
app.session.flush()
OIDCAccount.objects.all().delete()
User.objects.create(ou=ou, email='john.doe@example.com')
response = app.get('/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
location = urlparse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
assert OIDCAccount.objects.count() == 0
# sub=john.doe, MUST not work
with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, nonce=nonce):
response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state})
assert '_auth_user_id' not in app.session
assert OIDCAccount.objects.count() == 0
assert 'too many users' in caplog.records[-1].message