25
25
from django .contrib import auth
26
26
from django .contrib .auth .decorators import login_required
27
27
from django .contrib .auth .views import logout as django_logout
28
- from django .core .exceptions import PermissionDenied
28
+ from django .core .exceptions import PermissionDenied , SuspiciousOperation
29
29
from django .http import Http404 , HttpResponse
30
30
from django .http import HttpResponseRedirect # 30x
31
31
from django .http import HttpResponseBadRequest , HttpResponseForbidden # 40x
43
43
from saml2 .ident import code , decode
44
44
from saml2 .sigver import MissingKey
45
45
from saml2 .s_utils import UnsupportedBinding
46
- from saml2 .response import StatusError
46
+ from saml2 .response import StatusError , StatusAuthnFailed , SignatureError , StatusRequestDenied
47
47
from saml2 .validate import ResponseLifetimeExceed , ToEarly
48
48
from saml2 .xmldsig import SIG_RSA_SHA1 , SIG_RSA_SHA256 # support for SHA1 is required by spec
49
49
50
50
from djangosaml2 .cache import IdentityCache , OutstandingQueriesCache
51
51
from djangosaml2 .cache import StateCache
52
52
from djangosaml2 .conf import get_config
53
53
from 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
55
55
56
56
57
57
logger = logging .getLogger ('djangosaml2' )
@@ -235,38 +235,44 @@ def assertion_consumer_service(request,
235
235
djangosaml2.backends.Saml2Backend that should be
236
236
enabled in the settings.py
237
237
"""
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 )
244
240
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
+
249
247
client = Saml2Client (conf , identity_cache = IdentityCache (request .session ))
250
248
251
249
oq_cache = OutstandingQueriesCache (request .session )
252
250
outstanding_queries = oq_cache .outstanding_queries ()
253
251
254
252
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 )
261
269
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
+
266
273
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 )
270
276
271
277
session_id = response .session_id ()
272
278
oq_cache .delete (session_id )
@@ -279,17 +285,18 @@ def assertion_consumer_service(request,
279
285
if callable (create_unknown_user ):
280
286
create_unknown_user = create_unknown_user ()
281
287
282
- logger .debug ('Trying to authenticate the user' )
288
+ logger .debug ('Trying to authenticate the user. Session info: %s' , session_info )
283
289
user = auth .authenticate (request = request ,
284
290
session_info = session_info ,
285
291
attribute_mapping = attribute_mapping ,
286
292
create_unknown_user = create_unknown_user )
287
293
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 )
289
295
raise PermissionDenied
290
296
291
297
auth .login (request , user )
292
298
_set_subject_id (request .session , session_info ['name_id' ])
299
+ logger .debug ("User %s authenticated via SSO." , user )
293
300
294
301
logger .debug ('Sending the post_authenticated signal' )
295
302
post_authenticated .send_robust (sender = user , session_info = session_info )
0 commit comments