15
15
16
16
import base64
17
17
import logging
18
+ import saml2
18
19
19
20
from django .conf import settings
20
21
from django .contrib import auth
31
32
from django .views .decorators .csrf import csrf_exempt
32
33
from django .views .generic import View
33
34
from django .utils .module_loading import import_string
34
- from saml2 import BINDING_HTTP_POST , BINDING_HTTP_REDIRECT
35
35
from saml2 .client_base import LogoutError
36
36
from saml2 .config import SPConfig
37
37
from saml2 .ident import code , decode
@@ -191,61 +191,73 @@ def get(self, request, *args, **kwargs):
191
191
selected_idp = list (configured_idps .keys ())[0 ]
192
192
193
193
# 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 } ' )
197
196
198
197
# ensure our selected binding is supported by the IDP
199
198
supported_bindings = get_idp_sso_supported_bindings (
200
199
selected_idp , config = conf )
200
+
201
201
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
208
212
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
212
218
# if switched binding still not supported, give up
213
219
if binding not in supported_bindings :
214
220
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
+ )
216
224
217
225
client = Saml2Client (conf )
218
226
http_response = None
219
227
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
+
221
239
# pysaml needs a string otherwise: "cannot serialize True (type bool)"
222
240
if getattr (conf , '_sp_force_authn' , False ):
223
- kwargs ['force_authn' ] = "true"
241
+ sso_kwargs ['force_authn' ] = "true"
224
242
if getattr (conf , '_sp_allow_create' , False ):
225
- kwargs ['allow_create' ] = "true"
243
+ sso_kwargs ['allow_create' ] = "true"
226
244
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 :
229
250
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 ]
239
251
session_id , result = client .prepare_for_authenticate (
240
252
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 )
243
255
except TypeError as e :
244
256
logger .error ('Unable to know which IdP to use' )
245
257
return HttpResponse (str (e ))
246
258
else :
247
259
http_response = HttpResponseRedirect (get_location (result ))
248
- elif binding == BINDING_HTTP_POST :
260
+ elif binding == saml2 . BINDING_HTTP_POST :
249
261
if self .post_binding_form_template :
250
262
# get request XML to build our own html based on the template
251
263
try :
@@ -256,7 +268,7 @@ def get(self, request, *args, **kwargs):
256
268
session_id , request_xml = client .create_authn_request (
257
269
location ,
258
270
binding = binding ,
259
- ** kwargs )
271
+ ** sso_kwargs )
260
272
try :
261
273
if isinstance (request_xml , AuthnRequest ):
262
274
# request_xml will be an instance of AuthnRequest if the message is not signed
@@ -271,8 +283,8 @@ def get(self, request, *args, **kwargs):
271
283
'RelayState' : next_path ,
272
284
},
273
285
})
274
- except TemplateDoesNotExist :
275
- pass
286
+ except TemplateDoesNotExist as e :
287
+ logger . error ( f'TemplateDoesNotExist: { e } ' )
276
288
277
289
if not http_response :
278
290
# 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):
286
298
else :
287
299
http_response = HttpResponse (result ['data' ])
288
300
else :
289
- raise UnsupportedBinding ('Unsupported binding: %s' , binding )
301
+ raise UnsupportedBinding (f 'Unsupported binding: { binding } ' )
290
302
291
303
# success, so save the session ID and return our response
292
304
oq_cache = OutstandingQueriesCache (request .saml_session )
293
305
oq_cache .set (session_id , next_path )
294
306
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
+ )
296
310
return http_response
297
311
298
312
@@ -344,7 +358,7 @@ def post(self, request, attribute_mapping=None, create_unknown_user=None):
344
358
_exception = None
345
359
try :
346
360
response = client .parse_authn_request_response (request .POST ['SAMLResponse' ],
347
- BINDING_HTTP_POST ,
361
+ saml2 . BINDING_HTTP_POST ,
348
362
outstanding_queries )
349
363
except (StatusError , ToEarly ) as e :
350
364
_exception = e
@@ -525,12 +539,12 @@ def get(self, request, *args, **kwargs):
525
539
for entityid , logout_info in result .items ():
526
540
if isinstance (logout_info , tuple ):
527
541
binding , http_info = logout_info
528
- if binding == BINDING_HTTP_POST :
542
+ if binding == saml2 . BINDING_HTTP_POST :
529
543
logger .debug (
530
544
'Returning form to the IdP to continue the logout process' )
531
545
body = '' .join (http_info ['data' ])
532
546
return HttpResponse (body )
533
- elif binding == BINDING_HTTP_REDIRECT :
547
+ elif binding == saml2 . BINDING_HTTP_REDIRECT :
534
548
logger .debug (
535
549
'Redirecting to the IdP to continue the logout process' )
536
550
return HttpResponseRedirect (get_location (http_info ))
@@ -569,10 +583,10 @@ class LogoutView(SPConfigMixin, View):
569
583
logout_error_template = 'djangosaml2/logout_error.html'
570
584
571
585
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 )
573
587
574
588
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 )
576
590
577
591
def do_logout_service (self , request , data , binding ):
578
592
logger .debug ('Logout service started' )
0 commit comments