auth_oidc: add STRATEGY_FIND_USERNAME to match sub with username (#53445)

This commit is contained in:
Benjamin Dauvergne 2021-04-26 21:54:19 +02:00
parent c7418ad4eb
commit 8915d6fc96
4 changed files with 45 additions and 1 deletions

View File

@ -143,7 +143,13 @@ class OIDCBackend(ModelBackend):
pass
else:
logger.info('auth_oidc: found user using UUID (=sub) "%s": %s', id_token.sub, user)
elif provider.strategy == models.OIDCProvider.STRATEGY_FIND_USERNAME:
users = User.objects.filter(username=id_token.sub, is_active=True).order_by('pk')
if not users:
logger.warning('auth_oidc: user with username (=sub) "%s" not found', id_token.sub)
else:
user = users[0]
logger.info('auth_oidc: found user using username (=sub) "%s": %s', id_token.sub, user)
else:
try:
user = User.objects.get(

View File

@ -20,6 +20,7 @@ class Migration(migrations.Migration):
choices=[
('create', 'create'),
('find-uuid', 'use sub to find existing user through UUID'),
('find-username', 'use sub to find existing user through username'),
('none', 'none'),
],
),

View File

@ -40,11 +40,13 @@ def validate_jwkset(data):
class OIDCProvider(models.Model):
STRATEGY_CREATE = 'create'
STRATEGY_FIND_UUID = 'find-uuid'
STRATEGY_FIND_USERNAME = 'find-username'
STRATEGY_NONE = 'none'
STRATEGIES = [
(STRATEGY_CREATE, _('create')),
(STRATEGY_FIND_UUID, _('use sub to find existing user through UUID')),
(STRATEGY_FIND_USERNAME, _('use sub to find existing user through username')),
(STRATEGY_NONE, _('none')),
]
ALGO_NONE = 0

View File

@ -912,3 +912,38 @@ def test_manager_user_sidebar(app, superuser, simple_user, oidc_provider):
assert 'OIDC' in response
assert 'Server' in response
assert '1234' in response
def test_strategy_find_username(app, caplog, code, oidc_provider, oidc_provider_jwkset, simple_user):
# no mapping please
OIDCClaimMapping.objects.all().delete()
oidc_provider.strategy = oidc_provider.STRATEGY_FIND_USERNAME
oidc_provider.save()
assert User.objects.count() == 1
response = app.get('/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
location = urllib.parse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
# sub=simple_user.uuid MUST not work
with utils.check_log(caplog, 'cannot create user'):
with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, sub=simple_user.uuid, nonce=nonce):
response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state})
# sub=john.doe, MUST not work
with utils.check_log(caplog, 'cannot create user'):
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})
simple_user.username = 'john.doe'
simple_user.save()
# sub=john.doe, MUST work
with utils.check_log(caplog, 'found user using username'):
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})