2525from django .contrib import auth
2626from django .contrib .auth .decorators import login_required
2727from django .contrib .auth .views import logout as django_logout
28- from django .core .exceptions import PermissionDenied
28+ from django .core .exceptions import PermissionDenied , SuspiciousOperation
2929from django .http import Http404 , HttpResponse
3030from django .http import HttpResponseRedirect # 30x
3131from django .http import HttpResponseBadRequest , HttpResponseForbidden # 40x
4343from saml2 .ident import code , decode
4444from saml2 .sigver import MissingKey
4545from saml2 .s_utils import UnsupportedBinding
46- from saml2 .response import StatusError
46+ from saml2 .response import StatusError , StatusAuthnFailed , SignatureError , StatusRequestDenied
4747from saml2 .validate import ResponseLifetimeExceed , ToEarly
4848from saml2 .xmldsig import SIG_RSA_SHA1 , SIG_RSA_SHA256 # support for SHA1 is required by spec
4949
5050from djangosaml2 .cache import IdentityCache , OutstandingQueriesCache
5151from djangosaml2 .cache import StateCache
5252from djangosaml2 .conf import get_config
5353from djangosaml2 .signals import post_authenticated
54- from djangosaml2 .utils import get_custom_setting , available_idps , get_location , get_idp_sso_supported_bindings
54+ from djangosaml2 .utils import fail_acs_response , get_custom_setting , available_idps , get_location , get_idp_sso_supported_bindings
5555
5656
5757logger = logging .getLogger ('djangosaml2' )
@@ -235,38 +235,44 @@ def assertion_consumer_service(request,
235235 djangosaml2.backends.Saml2Backend that should be
236236 enabled in the settings.py
237237 """
238- attribute_mapping = attribute_mapping or get_custom_setting (
239- 'SAML_ATTRIBUTE_MAPPING' , {'uid' : ('username' , )})
240- create_unknown_user = create_unknown_user or get_custom_setting (
241- 'SAML_CREATE_UNKNOWN_USER' , True )
242- logger .debug ('Assertion Consumer Service started' )
243-
238+ attribute_mapping = attribute_mapping or get_custom_setting ('SAML_ATTRIBUTE_MAPPING' , {'uid' : ('username' , )})
239+ create_unknown_user = create_unknown_user or get_custom_setting ('SAML_CREATE_UNKNOWN_USER' , True )
244240 conf = get_config (config_loader_path , request )
245- if 'SAMLResponse' not in request .POST :
246- return HttpResponseBadRequest (
247- 'Couldn\' t find "SAMLResponse" in POST data.' )
248- xmlstr = request .POST ['SAMLResponse' ]
241+ try :
242+ xmlstr = request .POST ['SAMLResponse' ]
243+ except KeyError :
244+ logger .warning ('Missing "SAMLResponse" parameter in POST data.' )
245+ raise SuspiciousOperation
246+
249247 client = Saml2Client (conf , identity_cache = IdentityCache (request .session ))
250248
251249 oq_cache = OutstandingQueriesCache (request .session )
252250 outstanding_queries = oq_cache .outstanding_queries ()
253251
254252 try :
255- response = client .parse_authn_request_response (xmlstr , BINDING_HTTP_POST ,
256- outstanding_queries )
257- except (StatusError , ResponseLifetimeExceed , ToEarly ):
258- logger .exception ('Error processing SAML Assertion' )
259- return render (request , 'djangosaml2/login_error.html' , status = 403 )
260-
253+ response = client .parse_authn_request_response (xmlstr , BINDING_HTTP_POST , outstanding_queries )
254+ except (StatusError , ToEarly ):
255+ logger .exception ("Error processing SAML Assertion." )
256+ return fail_acs_response (request )
257+ except ResponseLifetimeExceed :
258+ logger .info ("SAML Assertion is no longer valid. Possibly caused by network delay or replay attack." , exc_info = True )
259+ return fail_acs_response (request )
260+ except SignatureError :
261+ logger .info ("Invalid or malformed SAML Assertion." , exc_info = True )
262+ return fail_acs_response (request )
263+ except StatusAuthnFailed :
264+ logger .info ("Authentication denied for user by IdP." , exc_info = True )
265+ return fail_acs_response (request )
266+ except StatusRequestDenied :
267+ logger .warning ("Authentication interrupted at IdP." , exc_info = True )
268+ return fail_acs_response (request )
261269 except MissingKey :
262- logger .error ('MissingKey error in ACS' )
263- return HttpResponseForbidden (
264- "The Identity Provider is not configured correctly: "
265- "the certificate key is missing" )
270+ logger .exception ("SAML Identity Provider is not configured correctly: certificate key is missing!" )
271+ return fail_acs_response (request )
272+
266273 if response is None :
267- logger .error ('SAML response is None' )
268- return HttpResponseBadRequest (
269- "SAML response has errors. Please check the logs" )
274+ logger .warning ("Invalid SAML Assertion received (unknown error)." )
275+ return fail_acs_response (request , status = 400 , exc_class = SuspiciousOperation )
270276
271277 session_id = response .session_id ()
272278 oq_cache .delete (session_id )
@@ -279,17 +285,18 @@ def assertion_consumer_service(request,
279285 if callable (create_unknown_user ):
280286 create_unknown_user = create_unknown_user ()
281287
282- logger .debug ('Trying to authenticate the user' )
288+ logger .debug ('Trying to authenticate the user. Session info: %s' , session_info )
283289 user = auth .authenticate (request = request ,
284290 session_info = session_info ,
285291 attribute_mapping = attribute_mapping ,
286292 create_unknown_user = create_unknown_user )
287293 if user is None :
288- logger .error ( 'The user is None' )
294+ logger .warning ( "Could not authenticate user received in SAML Assertion. Session info: %s" , session_info )
289295 raise PermissionDenied
290296
291297 auth .login (request , user )
292298 _set_subject_id (request .session , session_info ['name_id' ])
299+ logger .debug ("User %s authenticated via SSO." , user )
293300
294301 logger .debug ('Sending the post_authenticated signal' )
295302 post_authenticated .send_robust (sender = user , session_info = session_info )
0 commit comments