0001-authentic2_auth_oidc-show-a-warning-message-if-targe.patch
src/authentic2_auth_oidc/backends.py | ||
---|---|---|
18 | 18 |
import logging |
19 | 19 | |
20 | 20 |
import requests |
21 |
from django.contrib import messages |
|
21 | 22 |
from django.contrib.auth import get_user_model |
22 | 23 |
from django.contrib.auth.backends import ModelBackend |
23 |
from django.db.transaction import atomic |
|
24 |
from django.db import IntegrityError |
|
25 |
from django.db.transaction import atomic, set_rollback |
|
24 | 26 |
from django.utils.timezone import now |
27 |
from django.utils.translation import gettext as _ |
|
25 | 28 |
from jwcrypto.jwk import JWK |
26 | 29 |
from jwcrypto.jwt import JWT |
27 | 30 | |
... | ... | |
37 | 40 |
class OIDCBackend(ModelBackend): |
38 | 41 |
# pylint: disable=arguments-renamed |
39 | 42 |
def authenticate(self, request, access_token=None, id_token=None, nonce=None, provider=None): |
40 |
with atomic(savepoint=False):
|
|
43 |
with atomic(): |
|
41 | 44 |
return self._authenticate( |
42 | 45 |
request, access_token=access_token, id_token=id_token, nonce=nonce, provider=provider |
43 | 46 |
) |
... | ... | |
285 | 288 |
user = User.objects.create(ou=provider.ou, email=email or '') |
286 | 289 |
user.set_unusable_password() |
287 | 290 |
created_user = True |
288 |
oidc_account, created = models.OIDCAccount.objects.get_or_create( |
|
289 |
provider=provider, user=user, defaults={'sub': id_token.sub} |
|
290 |
) |
|
291 |
try: |
|
292 |
oidc_account, created = models.OIDCAccount.objects.get_or_create( |
|
293 |
provider=provider, user=user, defaults={'sub': id_token.sub} |
|
294 |
) |
|
295 |
except IntegrityError: |
|
296 |
set_rollback(True) |
|
297 |
if request: |
|
298 |
logger.warning('auth_oidc: email %s is already linked to another provider.', email) |
|
299 |
messages.warning( |
|
300 |
request, |
|
301 |
_( |
|
302 |
'Your email is already linked to another SSO account, please contact an administrator' |
|
303 |
), |
|
304 |
) |
|
305 |
return None |
|
306 | ||
291 | 307 |
if not created and oidc_account.sub != id_token.sub: |
292 | 308 |
logger.info( |
293 | 309 |
'auth_oidc: changed user %s sub from %s to %s (issuer %s)', |
... | ... | |
299 | 315 |
oidc_account.sub = id_token.sub |
300 | 316 |
oidc_account.save() |
301 | 317 |
else: |
318 |
if request: |
|
319 |
messages.warning(request, _('No user found')) |
|
302 | 320 |
logger.warning( |
303 | 321 |
'auth_oidc: cannot create user for sub %r as issuer %r does not allow it', |
304 | 322 |
id_token.sub, |
src/authentic2_auth_oidc/views.py | ||
---|---|---|
298 | 298 |
'provider_pk': provider.pk, |
299 | 299 |
} |
300 | 300 |
) |
301 |
else: |
|
302 |
messages.warning(request, _('No user found')) |
|
303 | 301 |
return self.continue_to_next_url(request) |
304 | 302 | |
305 | 303 |
errors = { |
tests/test_auth_oidc.py | ||
---|---|---|
1141 | 1141 |
assert second_authenticator.claim_mappings.get().pk == second_provider_claim_mapping.pk |
1142 | 1142 |
assert second_authenticator.accounts.count() == 1 |
1143 | 1143 |
assert second_authenticator.accounts.get().pk == second_provider_account.pk |
1144 | ||
1145 | ||
1146 |
def test_double_link(app, caplog, code, simple_user, oidc_provider_jwkset): |
|
1147 |
ou = get_default_ou() |
|
1148 |
ou.email_is_unique = True |
|
1149 |
ou.save() |
|
1150 |
provider1 = make_oidc_provider(name='provider1', jwkset=oidc_provider_jwkset) |
|
1151 |
provider2 = make_oidc_provider(name='provider2', jwkset=oidc_provider_jwkset) |
|
1152 | ||
1153 |
OIDCAccount.objects.create(provider=provider2, sub='1234', user=simple_user) |
|
1154 | ||
1155 |
response = app.get('/').maybe_follow() |
|
1156 |
response = response.click('provider1') |
|
1157 |
location = urllib.parse.urlparse(response.location) |
|
1158 |
query = QueryDict(location.query) |
|
1159 |
state = query['state'] |
|
1160 |
nonce = query['nonce'] |
|
1161 | ||
1162 |
# sub=john.doe |
|
1163 |
with utils.check_log(caplog, 'auth_oidc: email user@example.net is already linked'): |
|
1164 |
with oidc_provider_mock( |
|
1165 |
provider1, |
|
1166 |
oidc_provider_jwkset, |
|
1167 |
code, |
|
1168 |
nonce=nonce, |
|
1169 |
extra_id_token={'email': simple_user.email}, |
|
1170 |
extra_user_info={'email': simple_user.email}, |
|
1171 |
): |
|
1172 |
response = app.get(login_callback_url(provider1), params={'code': code, 'state': state}) |
|
1173 |
response = response.maybe_follow() |
|
1174 |
warnings = response.pyquery('.warning') |
|
1175 |
assert len(warnings) == 1 |
|
1176 |
assert 'Your email is already linked' in warnings.text() |
|
1144 |
- |