From 4309f4256cb7e42a96fe7af91d996abd1aa0ee11 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Tue, 16 Apr 2019 10:40:19 +0200 Subject: [PATCH 2/2] views: handle authentication levels requests and responses --- README | 9 +++++++++ mellon/app_settings.py | 1 + mellon/views.py | 14 +++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README b/README index a06e1e9..9afb0f2 100644 --- a/README +++ b/README @@ -216,6 +216,15 @@ value means everything is authorized. Authentication class reference must be obtained from your identity provider but SHOULD come from the SAML 2.0 specification. +MELLON_AUTHN_CLASSREF_LEVELS +---------------------------- + +When working with an idp which provides authentication levels, this +should be the URI it is expecting as a class reference, to which +will be appended the authentication level passed as a GET parameter +to LOGIN_URL. + + MELLON_GROUP_ATTRIBUTE ---------------------- diff --git a/mellon/app_settings.py b/mellon/app_settings.py index fe1a566..d15aa21 100644 --- a/mellon/app_settings.py +++ b/mellon/app_settings.py @@ -39,6 +39,7 @@ class AppSettings(object): 'LOGOUT_URL': 'mellon_logout', 'ARTIFACT_RESOLVE_TIMEOUT': 10.0, 'LOGIN_HINTS': [], + 'AUTHN_CLASSREF_LEVELS': 'https://entrouvert.org/auth-level/', } @property diff --git a/mellon/views.py b/mellon/views.py index 5a39adf..7a4764a 100644 --- a/mellon/views.py +++ b/mellon/views.py @@ -217,6 +217,11 @@ class LoginView(ProfileMixin, LogMixin, View): if user is not None: if user.is_active: utils.login(request, user) + class_ref = attributes['authn_context_class_ref'] + idp = self.get_idp(request) + authn_classref_levels = utils.get_setting(idp, 'AUTHN_CLASSREF_LEVELS') + if authn_classref_levels and class_ref.startswith(authn_classref_levels): + request.session['auth_level'] = int(class_ref.split('/')[-1]) self.log.info('user %s (NameID is %r) logged in using SAML', user, attributes['name_id_content']) request.session['mellon_session'] = utils.flatten_datetime(attributes) @@ -375,6 +380,7 @@ class LoginView(ProfileMixin, LogMixin, View): request, is_passive=request.GET.get('passive') == '1') next_url = check_next_url(self.request, request.GET.get(REDIRECT_FIELD_NAME)) + requested_auth_level = request.GET.get('auth_level') idp = self.get_idp(request) if idp is None: return HttpResponseBadRequest('no idp found') @@ -394,7 +400,13 @@ class LoginView(ProfileMixin, LogMixin, View): authn_request.isPassive = True # configure requested AuthnClassRef authn_classref = utils.get_setting(idp, 'AUTHN_CLASSREF') - if authn_classref: + authn_classref_levels = utils.get_setting(idp, 'AUTHN_CLASSREF_LEVELS') + if requested_auth_level and authn_classref_levels: + authn_classref = (authn_classref_levels + str(requested_auth_level),) + req_authncontext = lasso.Samlp2RequestedAuthnContext() + authn_request.requestedAuthnContext = req_authncontext + req_authncontext.authnContextClassRef = authn_classref + elif authn_classref: authn_classref = tuple([str(x) for x in authn_classref]) req_authncontext = lasso.Samlp2RequestedAuthnContext() authn_request.requestedAuthnContext = req_authncontext -- 2.20.1