46
46
from saml2 .samlp import AuthnRequest , IDPEntry , IDPList , Scoping
47
47
from saml2 .sigver import MissingKey
48
48
from saml2 .validate import ResponseLifetimeExceed , ToEarly
49
- from saml2 .xmldsig import ( # support for SHA1 is required by spec
50
- SIG_RSA_SHA1 , SIG_RSA_SHA256 )
51
49
52
50
from .cache import IdentityCache , OutstandingQueriesCache , StateCache
53
51
from .conf import get_config
@@ -160,6 +158,8 @@ def get(self, request, *args, **kwargs):
160
158
configured_idps = available_idps (conf )
161
159
selected_idp = request .GET .get ('idp' , None )
162
160
161
+ sso_kwargs = {}
162
+
163
163
# Do we have a Discovery Service?
164
164
if not selected_idp :
165
165
discovery_service = getattr (settings , 'SAML2_DISCO_URL' , None )
@@ -193,14 +193,19 @@ def get(self, request, *args, **kwargs):
193
193
selected_idp = list (configured_idps .keys ())[0 ]
194
194
195
195
# perform IdP Scoping if scoping param is present
196
- idp_scoping = Scoping ()
197
196
idp_scoping_param = request .GET .get ('scoping' , None )
198
197
if idp_scoping_param :
198
+ idp_scoping = Scoping ()
199
199
idp_scoping .idp_list = IDPList ()
200
- idp_scoping .idp_list .idp_entry .append (IDPEntry (provider_id = idp_scoping_param ))
200
+ idp_scoping .idp_list .idp_entry .append (
201
+ IDPEntry (provider_id = idp_scoping_param )
202
+ )
203
+ sso_kwargs ['scoping' ] = idp_scoping
204
+
201
205
202
206
# choose a binding to try first
203
- binding = getattr (settings , 'SAML_DEFAULT_BINDING' , saml2 .BINDING_HTTP_POST )
207
+ binding = getattr (settings , 'SAML_DEFAULT_BINDING' ,
208
+ saml2 .BINDING_HTTP_POST )
204
209
logger .debug (f'Trying binding { binding } for IDP { selected_idp } ' )
205
210
206
211
# ensure our selected binding is supported by the IDP
@@ -232,18 +237,16 @@ def get(self, request, *args, **kwargs):
232
237
)
233
238
234
239
client = Saml2Client (conf )
235
- http_response = None
236
240
237
241
# SSO options
238
242
sign_requests = getattr (conf , '_sp_authn_requests_signed' , False )
239
- sso_kwargs = {}
243
+
240
244
if sign_requests :
241
- sso_kwargs ["sigalg" ] = settings .SAML_CONFIG ['service' ]['sp' ]\
242
- .get ('signing_algorithm' ,
243
- saml2 .xmldsig .SIG_RSA_SHA256 )
244
- sso_kwargs ["digest_alg" ] = settings .SAML_CONFIG ['service' ]['sp' ]\
245
- .get ('digest_algorithm' ,
246
- saml2 .xmldsig .DIGEST_SHA256 )
245
+ csc = settings .SAML_CONFIG ['service' ]['sp' ]
246
+ sso_kwargs ["sigalg" ] = csc .get ('signing_algorithm' ,
247
+ saml2 .xmldsig .SIG_RSA_SHA256 )
248
+ sso_kwargs ["digest_alg" ] = csc .get ('digest_algorithm' ,
249
+ saml2 .xmldsig .DIGEST_SHA256 )
247
250
248
251
# pysaml needs a string otherwise: "cannot serialize True (type bool)"
249
252
if getattr (conf , '_sp_force_authn' , False ):
@@ -256,17 +259,20 @@ def get(self, request, *args, **kwargs):
256
259
257
260
logger .debug (f'Redirecting user to the IdP via { binding } binding.' )
258
261
_msg = 'Unable to know which IdP to use'
262
+ http_response = None
263
+
259
264
if binding == saml2 .BINDING_HTTP_REDIRECT :
260
265
try :
261
266
session_id , result = client .prepare_for_authenticate (
262
267
entityid = selected_idp , relay_state = next_path ,
263
- binding = binding , sign = sign_requests , scoping = idp_scoping ,
268
+ binding = binding , sign = sign_requests ,
264
269
** sso_kwargs )
265
270
except TypeError as e :
266
271
logger .error (f'{ _msg } : { e } ' )
267
272
return HttpResponse (_msg )
268
273
else :
269
274
http_response = HttpResponseRedirect (get_location (result ))
275
+
270
276
elif binding == saml2 .BINDING_HTTP_POST :
271
277
if self .post_binding_form_template :
272
278
# get request XML to build our own html based on the template
@@ -275,10 +281,12 @@ def get(self, request, *args, **kwargs):
275
281
except TypeError as e :
276
282
logger .error (f'{ _msg } : { e } ' )
277
283
return HttpResponse (_msg )
284
+
278
285
session_id , request_xml = client .create_authn_request (
279
286
location ,
280
287
binding = binding ,
281
- ** sso_kwargs )
288
+ ** sso_kwargs
289
+ )
282
290
try :
283
291
if isinstance (request_xml , AuthnRequest ):
284
292
# request_xml will be an instance of AuthnRequest if the message is not signed
@@ -294,14 +302,16 @@ def get(self, request, *args, **kwargs):
294
302
},
295
303
})
296
304
except TemplateDoesNotExist as e :
297
- logger .error (f'TemplateDoesNotExist: { e } ' )
305
+ logger .error (
306
+ f'TemplateDoesNotExist: [{ self .post_binding_form_template } ] - { e } '
307
+ )
298
308
299
309
if not http_response :
300
310
# use the html provided by pysaml2 if no template was specified or it doesn't exist
301
311
try :
302
312
session_id , result = client .prepare_for_authenticate (
303
313
entityid = selected_idp , relay_state = next_path ,
304
- binding = binding , scoping = idp_scoping )
314
+ binding = binding , ** sso_kwargs )
305
315
except TypeError as e :
306
316
_msg = f"Can't prepare the authentication for { selected_idp } "
307
317
logger .error (f'{ _msg } : { e } ' )
@@ -380,7 +390,8 @@ def post(self, request, attribute_mapping=None, create_unknown_user=None):
380
390
except ResponseLifetimeExceed as e :
381
391
_exception = e
382
392
logger .info (
383
- ("SAML Assertion is no longer valid. Possibly caused by network delay or replay attack." ), exc_info = True )
393
+ ("SAML Assertion is no longer valid. Possibly caused "
394
+ "by network delay or replay attack." ), exc_info = True )
384
395
except SignatureError as e :
385
396
_exception = e
386
397
logger .info ("Invalid or malformed SAML Assertion." , exc_info = True )
@@ -435,7 +446,8 @@ def post(self, request, attribute_mapping=None, create_unknown_user=None):
435
446
for sc in assertion .subject .subject_confirmation :
436
447
if sc .method == SCM_BEARER :
437
448
assertion_not_on_or_after = sc .subject_confirmation_data .not_on_or_after
438
- assertion_info = {'assertion_id' : assertion .id , 'not_on_or_after' : assertion_not_on_or_after }
449
+ assertion_info = {'assertion_id' : assertion .id ,
450
+ 'not_on_or_after' : assertion_not_on_or_after }
439
451
break
440
452
441
453
if callable (attribute_mapping ):
@@ -607,10 +619,14 @@ class LogoutView(SPConfigMixin, View):
607
619
logout_error_template = 'djangosaml2/logout_error.html'
608
620
609
621
def get (self , request , * args , ** kwargs ):
610
- return self .do_logout_service (request , request .GET , saml2 .BINDING_HTTP_REDIRECT , * args , ** kwargs )
622
+ return self .do_logout_service (
623
+ request , request .GET , saml2 .BINDING_HTTP_REDIRECT , * args , ** kwargs
624
+ )
611
625
612
626
def post (self , request , * args , ** kwargs ):
613
- return self .do_logout_service (request , request .POST , saml2 .BINDING_HTTP_POST , * args , ** kwargs )
627
+ return self .do_logout_service (
628
+ request , request .POST , saml2 .BINDING_HTTP_POST , * args , ** kwargs
629
+ )
614
630
615
631
def do_logout_service (self , request , data , binding ):
616
632
logger .debug ('Logout service started' )
0 commit comments