idp_oidc: add a client and global setting for the idtoken duration (fixes #21232)

The default expire duration is still 30 seconds and can be changed
with the IDTOKEN_DURATION app setting.
The duration can be customized for each client with the new 'idtoken_duration'
field.

License: MIT
This commit is contained in:
Christophe de Vienne 2018-01-10 23:51:52 +01:00 committed by Benjamin Dauvergne
parent c2e2293d4f
commit d639f7755b
5 changed files with 56 additions and 6 deletions

View File

@ -26,6 +26,11 @@ class AppSettings(object):
def SCOPES(self):
return self._setting('SCOPES', [])
@property
def IDTOKEN_DURATION(self):
return self._setting('IDTOKEN_DURATION', 30)
import sys
app_settings = AppSettings('A2_IDP_OIDC_')

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentic2_idp_oidc', '0007_oidcclient_has_api_access'),
]
operations = [
migrations.AddField(
model_name='oidcclient',
name='idtoken_duration',
field=models.DurationField(
verbose_name='time during which the token is valid',
blank=True,
null=True,
default=None),
),
]

View File

@ -80,6 +80,11 @@ class OIDCClient(Service):
max_length=255,
verbose_name=_('client secret'),
default=generate_uuid)
idtoken_duration = models.DurationField(
verbose_name=_('time during which the token is valid'),
blank=True,
null=True,
default=None)
authorization_mode = models.PositiveIntegerField(
default=AUTHORIZATION_MODE_BY_SERVICE,
choices=AUTHORIZATION_MODES,

View File

@ -68,6 +68,12 @@ def authorization_error(request, redirect_uri, error, error_description=None, er
return redirect(request, redirect_uri, params=params, resolve=False)
def idtoken_duration(client):
if client.idtoken_duration:
return client.idtoken_duration
return datetime.timedelta(seconds=app_settings.IDTOKEN_DURATION)
@setting_enabled('ENABLE', settings=app_settings)
def authorize(request, *args, **kwargs):
logger = logging.getLogger(__name__)
@ -272,8 +278,7 @@ def authorize(request, *args, **kwargs):
id_token.update({
'iss': request.build_absolute_uri('/'),
'aud': client.client_id,
'exp': timestamp_from_datetime(
start + datetime.timedelta(seconds=30)),
'exp': timestamp_from_datetime(start + idtoken_duration(client)),
'iat': timestamp_from_datetime(start),
'auth_time': last_auth['when'],
'acr': acr,
@ -379,8 +384,7 @@ def token(request, *args, **kwargs):
'iss': request.build_absolute_uri('/'),
'sub': utils.make_sub(client, oidc_code.user),
'aud': client.client_id,
'exp': timestamp_from_datetime(
start + datetime.timedelta(seconds=30)),
'exp': timestamp_from_datetime(start + idtoken_duration(client)),
'iat': timestamp_from_datetime(start),
'auth_time': timestamp_from_datetime(oidc_code.auth_time),
'acr': acr,

View File

@ -64,7 +64,14 @@ OIDC_CLIENT_PARAMS = [
},
{
'authorization_mode': OIDCClient.AUTHORIZATION_MODE_NONE,
}
},
{
'idtoken_duration': datetime.timedelta(hours=1),
},
{
'authorization_flow': OIDCClient.FLOW_IMPLICIT,
'idtoken_duration': datetime.timedelta(hours=1),
},
]
@ -198,7 +205,13 @@ def test_authorization_code_sso(login_first, oidc_settings, oidc_client, simple_
assert claims['aud'] == oidc_client.client_id
assert parse_timestamp(claims['iat']) <= now()
assert parse_timestamp(claims['auth_time']) <= now()
assert parse_timestamp(claims['exp']) >= now()
exp_delta = (parse_timestamp(claims['exp']) - now()).total_seconds()
assert exp_delta > 0
if oidc_client.idtoken_duration:
assert abs(exp_delta - oidc_client.idtoken_duration.total_seconds()) < 2
else:
assert abs(exp_delta - 30) < 2
if login_first:
assert claims['acr'] == '0'
else: