diff --git a/djangosaml2/overrides.py b/djangosaml2/overrides.py index 96849bec..32bf673a 100644 --- a/djangosaml2/overrides.py +++ b/djangosaml2/overrides.py @@ -21,4 +21,11 @@ def do_logout(self, *args, **kwargs): except AttributeError: logger.warning('SAML_LOGOUT_REQUEST_PREFERRED_BINDING setting is' ' not defined. Default binding will be used.') + + # 1. global_logout calls do_logout but does not forward kwargs, so we cannot use global_logout(sigalg=sigalg) + # 2. sigalg is used by BINDING_HTTP_REDIRECT + if kwargs.get('sign_alg') and not kwargs.get('sigalg'): + logger.debug("Setting sigalg: %s", kwargs.get('sign_alg')) + kwargs['sigalg'] = kwargs.get('sign_alg') + return super(Saml2Client, self).do_logout(*args, **kwargs) diff --git a/djangosaml2/views.py b/djangosaml2/views.py index b71f3218..21273f2e 100644 --- a/djangosaml2/views.py +++ b/djangosaml2/views.py @@ -82,6 +82,31 @@ def callable_bool(value): return value +def get_sigalg(conf): + # See also: + # 1. https://github.com/IdentityPython/pysaml2/pull/396 + # 2. https://github.com/IdentityPython/pysaml2/pull/495 + # + # Configuration example: + # { + # 'service': { + # 'sp': { + # 'authn_requests_signed': True, + # 'authn_requests_signed_alg': 'sha256' + # } + # } + # } + # + sign_requests = getattr(conf, '_sp_authn_requests_signed', False) + + sig_alg_option_map = {'sha1': SIG_RSA_SHA1, + 'sha256': SIG_RSA_SHA256} + + sig_alg_option = getattr(conf, '_sp_authn_requests_signed_alg', 'sha1') + logger.debug("sig_alg_option: %s", sig_alg_option) + return sig_alg_option_map.get(sig_alg_option, SIG_RSA_SHA1) if sign_requests else None + + def login(request, config_loader_path=None, wayf_template='djangosaml2/wayf.html', @@ -171,15 +196,13 @@ def login(request, client = Saml2Client(conf) http_response = None + sigalg = get_sigalg(conf) + logger.debug('Redirecting user to the IdP via %s binding.', binding) if binding == BINDING_HTTP_REDIRECT: try: # do not sign the xml itself, instead use the sigalg to # generate the signature as a URL param - sig_alg_option_map = {'sha1': SIG_RSA_SHA1, - 'sha256': SIG_RSA_SHA256} - sig_alg_option = getattr(conf, '_sp_authn_requests_signed_alg', 'sha1') - sigalg = sig_alg_option_map[sig_alg_option] if sign_requests else None nsprefix = get_namespace_prefixes() session_id, result = client.prepare_for_authenticate( entityid=selected_idp, relay_state=came_from, @@ -200,7 +223,8 @@ def login(request, return HttpResponse(text_type(e)) session_id, request_xml = client.create_authn_request( location, - binding=binding) + binding=binding, + sign_alg=sigalg) try: if PY3: saml_request = base64.b64encode(binary_type(request_xml, 'UTF-8')) @@ -222,7 +246,7 @@ def login(request, try: session_id, result = client.prepare_for_authenticate( entityid=selected_idp, relay_state=came_from, - binding=binding) + binding=binding, sign_alg=sigalg) except TypeError as e: logger.error('Unable to know which IdP to use') return HttpResponse(text_type(e)) @@ -364,6 +388,7 @@ def logout(request, config_loader_path=None): """ state = StateCache(request.session) conf = get_config(config_loader_path, request) + sigalg = get_sigalg(conf) client = Saml2Client(conf, state_cache=state, identity_cache=IdentityCache(request.session)) @@ -373,7 +398,7 @@ def logout(request, config_loader_path=None): 'The session does not contain the subject id for user %s', request.user) - result = client.global_logout(subject_id) + result = client.global_logout(subject_id, sign_alg=sigalg) state.sync()