1515
1616import base64
1717import logging
18+ import saml2
1819
1920from django .conf import settings
2021from django .contrib import auth
3132from django .views .decorators .csrf import csrf_exempt
3233from django .views .generic import View
3334from django .utils .module_loading import import_string
34- from saml2 import BINDING_HTTP_POST , BINDING_HTTP_REDIRECT
3535from saml2 .client_base import LogoutError
3636from saml2 .config import SPConfig
3737from saml2 .ident import code , decode
@@ -191,61 +191,73 @@ def get(self, request, *args, **kwargs):
191191 selected_idp = list (configured_idps .keys ())[0 ]
192192
193193 # choose a binding to try first
194- sign_requests = getattr (conf , '_sp_authn_requests_signed' , False )
195- binding = BINDING_HTTP_POST if sign_requests else BINDING_HTTP_REDIRECT
196- logger .debug ('Trying binding %s for IDP %s' , binding , selected_idp )
194+ binding = getattr (settings , 'SAML_DEFAULT_BINDING' , saml2 .BINDING_HTTP_POST )
195+ logger .debug (f'Trying binding { binding } for IDP { selected_idp } ' )
197196
198197 # ensure our selected binding is supported by the IDP
199198 supported_bindings = get_idp_sso_supported_bindings (
200199 selected_idp , config = conf )
200+
201201 if binding not in supported_bindings :
202- logger .debug ('Binding %s not in IDP %s supported bindings: %s' ,
203- binding , selected_idp , supported_bindings )
204- if binding == BINDING_HTTP_POST :
205- logger .warning ('IDP %s does not support %s, trying %s' ,
206- selected_idp , binding , BINDING_HTTP_REDIRECT )
207- binding = BINDING_HTTP_REDIRECT
202+ logger .debug (
203+ f'Binding { binding } not in IDP { selected_idp } '
204+ f'supported bindings: { supported_bindings } . Trying to switch ...' ,
205+ )
206+ if binding == saml2 .BINDING_HTTP_POST :
207+ logger .warning (
208+ f'IDP { selected_idp } does not support { binding } '
209+ f'trying { saml2 .BINDING_HTTP_REDIRECT } ' ,
210+ )
211+ binding = saml2 .BINDING_HTTP_REDIRECT
208212 else :
209- logger .warning ('IDP %s does not support %s, trying %s' ,
210- selected_idp , binding , BINDING_HTTP_POST )
211- binding = BINDING_HTTP_POST
213+ logger .warning (
214+ f'IDP { selected_idp } does not support { binding } '
215+ f'trying { saml2 .BINDING_HTTP_POST } ' ,
216+ )
217+ binding = saml2 .BINDING_HTTP_POST
212218 # if switched binding still not supported, give up
213219 if binding not in supported_bindings :
214220 raise UnsupportedBinding (
215- 'IDP %s does not support %s or %s' , selected_idp , BINDING_HTTP_POST , BINDING_HTTP_REDIRECT )
221+ f'IDP { selected_idp } does not support '
222+ f'{ saml2 .BINDING_HTTP_POST } and { saml2 .BINDING_HTTP_REDIRECT } '
223+ )
216224
217225 client = Saml2Client (conf )
218226 http_response = None
219227
220- kwargs = {}
228+ # SSO options
229+ sign_requests = getattr (conf , '_sp_authn_requests_signed' , False )
230+ sso_kwargs = {}
231+ if sign_requests :
232+ sso_kwargs ["sigalg" ] = settings .SAML_CONFIG ['service' ]['sp' ]\
233+ .get ('signing_algorithm' ,
234+ saml2 .xmldsig .SIG_RSA_SHA256 )
235+ sso_kwargs ["digest_alg" ] = settings .SAML_CONFIG ['service' ]['sp' ]\
236+ .get ('digest_algorithm' ,
237+ saml2 .xmldsig .DIGEST_SHA256 )
238+
221239 # pysaml needs a string otherwise: "cannot serialize True (type bool)"
222240 if getattr (conf , '_sp_force_authn' , False ):
223- kwargs ['force_authn' ] = "true"
241+ sso_kwargs ['force_authn' ] = "true"
224242 if getattr (conf , '_sp_allow_create' , False ):
225- kwargs ['allow_create' ] = "true"
243+ sso_kwargs ['allow_create' ] = "true"
226244
227- logger .debug ('Redirecting user to the IdP via %s binding.' , binding )
228- if binding == BINDING_HTTP_REDIRECT :
245+ # custom nsprefixes
246+ sso_kwargs ['nsprefix' ] = get_namespace_prefixes ()
247+
248+ logger .debug (f'Redirecting user to the IdP via { binding } binding.' )
249+ if binding == saml2 .BINDING_HTTP_REDIRECT :
229250 try :
230- nsprefix = get_namespace_prefixes ()
231- if sign_requests :
232- # do not sign the xml itself, instead use the sigalg to
233- # generate the signature as a URL param
234- sig_alg_option_map = {
235- 'sha1' : SIG_RSA_SHA1 , 'sha256' : SIG_RSA_SHA256 }
236- sig_alg_option = getattr (
237- conf , '_sp_authn_requests_signed_alg' , 'sha1' )
238- kwargs ["sigalg" ] = sig_alg_option_map [sig_alg_option ]
239251 session_id , result = client .prepare_for_authenticate (
240252 entityid = selected_idp , relay_state = next_path ,
241- binding = binding , sign = sign_requests , nsprefix = nsprefix ,
242- ** kwargs )
253+ binding = binding , sign = sign_requests ,
254+ ** sso_kwargs )
243255 except TypeError as e :
244256 logger .error ('Unable to know which IdP to use' )
245257 return HttpResponse (str (e ))
246258 else :
247259 http_response = HttpResponseRedirect (get_location (result ))
248- elif binding == BINDING_HTTP_POST :
260+ elif binding == saml2 . BINDING_HTTP_POST :
249261 if self .post_binding_form_template :
250262 # get request XML to build our own html based on the template
251263 try :
@@ -256,7 +268,7 @@ def get(self, request, *args, **kwargs):
256268 session_id , request_xml = client .create_authn_request (
257269 location ,
258270 binding = binding ,
259- ** kwargs )
271+ ** sso_kwargs )
260272 try :
261273 if isinstance (request_xml , AuthnRequest ):
262274 # request_xml will be an instance of AuthnRequest if the message is not signed
@@ -271,8 +283,8 @@ def get(self, request, *args, **kwargs):
271283 'RelayState' : next_path ,
272284 },
273285 })
274- except TemplateDoesNotExist :
275- pass
286+ except TemplateDoesNotExist as e :
287+ logger . error ( f'TemplateDoesNotExist: { e } ' )
276288
277289 if not http_response :
278290 # use the html provided by pysaml2 if no template was specified or it didn't exist
@@ -286,13 +298,15 @@ def get(self, request, *args, **kwargs):
286298 else :
287299 http_response = HttpResponse (result ['data' ])
288300 else :
289- raise UnsupportedBinding ('Unsupported binding: %s' , binding )
301+ raise UnsupportedBinding (f 'Unsupported binding: { binding } ' )
290302
291303 # success, so save the session ID and return our response
292304 oq_cache = OutstandingQueriesCache (request .saml_session )
293305 oq_cache .set (session_id , next_path )
294306 logger .debug (
295- 'Saving the session_id "%s" in the OutstandingQueries cache' , oq_cache .__dict__ )
307+ f'Saving the session_id "{ oq_cache .__dict__ } " '
308+ 'in the OutstandingQueries cache' ,
309+ )
296310 return http_response
297311
298312
@@ -344,7 +358,7 @@ def post(self, request, attribute_mapping=None, create_unknown_user=None):
344358 _exception = None
345359 try :
346360 response = client .parse_authn_request_response (request .POST ['SAMLResponse' ],
347- BINDING_HTTP_POST ,
361+ saml2 . BINDING_HTTP_POST ,
348362 outstanding_queries )
349363 except (StatusError , ToEarly ) as e :
350364 _exception = e
@@ -525,12 +539,12 @@ def get(self, request, *args, **kwargs):
525539 for entityid , logout_info in result .items ():
526540 if isinstance (logout_info , tuple ):
527541 binding , http_info = logout_info
528- if binding == BINDING_HTTP_POST :
542+ if binding == saml2 . BINDING_HTTP_POST :
529543 logger .debug (
530544 'Returning form to the IdP to continue the logout process' )
531545 body = '' .join (http_info ['data' ])
532546 return HttpResponse (body )
533- elif binding == BINDING_HTTP_REDIRECT :
547+ elif binding == saml2 . BINDING_HTTP_REDIRECT :
534548 logger .debug (
535549 'Redirecting to the IdP to continue the logout process' )
536550 return HttpResponseRedirect (get_location (http_info ))
@@ -569,10 +583,10 @@ class LogoutView(SPConfigMixin, View):
569583 logout_error_template = 'djangosaml2/logout_error.html'
570584
571585 def get (self , request , * args , ** kwargs ):
572- return self .do_logout_service (request , request .GET , BINDING_HTTP_REDIRECT , * args , ** kwargs )
586+ return self .do_logout_service (request , request .GET , saml2 . BINDING_HTTP_REDIRECT , * args , ** kwargs )
573587
574588 def post (self , request , * args , ** kwargs ):
575- return self .do_logout_service (request , request .POST , BINDING_HTTP_POST , * args , ** kwargs )
589+ return self .do_logout_service (request , request .POST , saml2 . BINDING_HTTP_POST , * args , ** kwargs )
576590
577591 def do_logout_service (self , request , data , binding ):
578592 logger .debug ('Logout service started' )
0 commit comments