2929from django .utils .http import is_safe_url
3030from django .views .decorators .csrf import csrf_exempt
3131from django .views .decorators .http import require_POST
32- from saml2 import BINDING_HTTP_POST , BINDING_HTTP_REDIRECT
32+ from saml2 import BINDING_HTTP_REDIRECT , BINDING_HTTP_POST
33+ from saml2 .client_base import LogoutError
34+ from saml2 .metadata import entity_descriptor
3335from saml2 .ident import code , decode
3436from saml2 .metadata import entity_descriptor
3537from saml2 .response import (SignatureError , StatusAuthnFailed , StatusError ,
3638 StatusNoAuthnContext , StatusRequestDenied ,
3739 UnsolicitedResponse )
3840from saml2 .s_utils import UnsupportedBinding
41+ from saml2 .response import (
42+ StatusError , StatusAuthnFailed , SignatureError , StatusRequestDenied ,
43+ UnsolicitedResponse , StatusNoAuthnContext ,
44+ )
45+ from saml2 .mdstore import SourceNotFound
3946from saml2 .sigver import MissingKey
4047from saml2 .validate import ResponseLifetimeExceed , ToEarly
4148from saml2 .xmldsig import ( # support for SHA1 is required by spec
@@ -122,7 +129,15 @@ def login(request,
122129 })
123130
124131 selected_idp = request .GET .get ('idp' , None )
125- conf = get_config (config_loader_path , request )
132+ try :
133+ conf = get_config (config_loader_path , request )
134+ except SourceNotFound as excp :
135+ msg = ('Error, IdP EntityID was not found '
136+ 'in metadata: {}' )
137+ logger .exception (msg .format (excp ))
138+ return HttpResponse (msg .format (('Please contact '
139+ 'technical support.' )),
140+ status = 500 )
126141
127142 kwargs = {}
128143 # pysaml needs a string otherwise: "cannot serialize True (type bool)"
@@ -176,17 +191,18 @@ def login(request,
176191 logger .debug ('Redirecting user to the IdP via %s binding.' , binding )
177192 if binding == BINDING_HTTP_REDIRECT :
178193 try :
179- # do not sign the xml itself, instead use the sigalg to
180- # generate the signature as a URL param
181- sig_alg_option_map = {'sha1' : SIG_RSA_SHA1 ,
182- 'sha256' : SIG_RSA_SHA256 }
183- sig_alg_option = getattr (conf , '_sp_authn_requests_signed_alg' , 'sha1' )
184- sigalg = sig_alg_option_map [sig_alg_option ] if sign_requests else None
185194 nsprefix = get_namespace_prefixes ()
195+ if sign_requests :
196+ # do not sign the xml itself, instead use the sigalg to
197+ # generate the signature as a URL param
198+ sig_alg_option_map = {'sha1' : SIG_RSA_SHA1 ,
199+ 'sha256' : SIG_RSA_SHA256 }
200+ sig_alg_option = getattr (conf , '_sp_authn_requests_signed_alg' , 'sha1' )
201+ kwargs ["sigalg" ] = sig_alg_option_map [sig_alg_option ]
186202 session_id , result = client .prepare_for_authenticate (
187203 entityid = selected_idp , relay_state = came_from ,
188- binding = binding , sign = False , sigalg = sigalg ,
189- nsprefix = nsprefix , ** kwargs )
204+ binding = binding , sign = False , nsprefix = nsprefix ,
205+ ** kwargs )
190206 except TypeError as e :
191207 logger .error ('Unable to know which IdP to use' )
192208 return HttpResponse (str (e ))
@@ -269,34 +285,34 @@ def assertion_consumer_service(request,
269285
270286 try :
271287 response = client .parse_authn_request_response (xmlstr , BINDING_HTTP_POST , outstanding_queries )
272- except (StatusError , ToEarly ):
288+ except (StatusError , ToEarly ) as e :
273289 logger .exception ("Error processing SAML Assertion." )
274- return fail_acs_response (request )
275- except ResponseLifetimeExceed :
290+ return fail_acs_response (request , exception = e )
291+ except ResponseLifetimeExceed as e :
276292 logger .info ("SAML Assertion is no longer valid. Possibly caused by network delay or replay attack." , exc_info = True )
277- return fail_acs_response (request )
278- except SignatureError :
293+ return fail_acs_response (request , exception = e )
294+ except SignatureError as e :
279295 logger .info ("Invalid or malformed SAML Assertion." , exc_info = True )
280- return fail_acs_response (request )
281- except StatusAuthnFailed :
296+ return fail_acs_response (request , exception = e )
297+ except StatusAuthnFailed as e :
282298 logger .info ("Authentication denied for user by IdP." , exc_info = True )
283- return fail_acs_response (request )
284- except StatusRequestDenied :
299+ return fail_acs_response (request , exception = e )
300+ except StatusRequestDenied as e :
285301 logger .warning ("Authentication interrupted at IdP." , exc_info = True )
286- return fail_acs_response (request )
287- except StatusNoAuthnContext :
302+ return fail_acs_response (request , exception = e )
303+ except StatusNoAuthnContext as e :
288304 logger .warning ("Missing Authentication Context from IdP." , exc_info = True )
289- return fail_acs_response (request )
290- except MissingKey :
305+ return fail_acs_response (request , exception = e )
306+ except MissingKey as e :
291307 logger .exception ("SAML Identity Provider is not configured correctly: certificate key is missing!" )
292- return fail_acs_response (request )
293- except UnsolicitedResponse :
308+ return fail_acs_response (request , exception = e )
309+ except UnsolicitedResponse as e :
294310 logger .exception ("Received SAMLResponse when no request has been made." )
295- return fail_acs_response (request )
311+ return fail_acs_response (request , exception = e )
296312
297313 if response is None :
298314 logger .warning ("Invalid SAML Assertion received (unknown error)." )
299- return fail_acs_response (request , status = 400 , exc_class = SuspiciousOperation )
315+ return fail_acs_response (request , status = 400 , exception = SuspiciousOperation ( 'Unknown SAML2 error' ) )
300316
301317 session_id = response .session_id ()
302318 oq_cache .delete (session_id )
@@ -316,7 +332,7 @@ def assertion_consumer_service(request,
316332 create_unknown_user = create_unknown_user )
317333 if user is None :
318334 logger .warning ("Could not authenticate user received in SAML Assertion. Session info: %s" , session_info )
319- raise PermissionDenied
335+ return fail_acs_response ( request , exception = PermissionDenied ( 'No user could be authenticated.' ))
320336
321337 auth .login (request , user )
322338 _set_subject_id (request .session , session_info ['name_id' ])
@@ -376,7 +392,13 @@ def logout(request, config_loader_path=None):
376392 'The session does not contain the subject id for user %s' ,
377393 request .user )
378394
379- result = client .global_logout (subject_id )
395+ try :
396+ result = client .global_logout (subject_id )
397+ except LogoutError as exp :
398+ logger .exception ('Error Handled - SLO not supported by IDP: {}' .format (exp ))
399+ auth .logout (request )
400+ state .sync ()
401+ return HttpResponseRedirect ('/' )
380402
381403 state .sync ()
382404
0 commit comments