27
27
from satosa .internal import AuthenticationInformation
28
28
from satosa .internal import InternalData
29
29
from satosa .exception import SATOSAAuthenticationError
30
+ from satosa .exception import SATOSAMissingStateError
31
+ from satosa .exception import SATOSAAuthenticationFlowError
30
32
from satosa .response import SeeOther , Response
31
33
from satosa .saml_util import make_saml_response
32
34
from satosa .metadata_creation .description import (
@@ -224,6 +226,14 @@ def disco_query(self, context):
224
226
loc = self .sp .create_discovery_service_request (
225
227
disco_url , self .sp .config .entityid , ** args
226
228
)
229
+
230
+ msg = {
231
+ "message" : "Sending user to the discovery service" ,
232
+ "disco_url" : loc
233
+ }
234
+ logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
235
+ logger .info (logline )
236
+
227
237
return SeeOther (loc )
228
238
229
239
def construct_requested_authn_context (self , entity_id , * , target_accr = None ):
@@ -268,10 +278,13 @@ def authn_request(self, context, entity_id):
268
278
with open (self .idp_blacklist_file ) as blacklist_file :
269
279
blacklist_array = json .load (blacklist_file )['blacklist' ]
270
280
if entity_id in blacklist_array :
271
- msg = "IdP with EntityID {} is blacklisted" .format (entity_id )
281
+ msg = {
282
+ "message" : "AuthnRequest Failed" ,
283
+ "error" : f"Selected IdP with EntityID { entity_id } is blacklisted for this backend" ,
284
+ }
272
285
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
273
- logger .debug (logline , exc_info = False )
274
- raise SATOSAAuthenticationError (context .state , "Selected IdP is blacklisted for this backend" )
286
+ logger .info (logline )
287
+ raise SATOSAAuthenticationError (context .state , msg )
275
288
276
289
kwargs = {}
277
290
target_accr = context .state .get (Context .KEY_TARGET_AUTHN_CONTEXT_CLASS_REF )
@@ -299,16 +312,22 @@ def authn_request(self, context, entity_id):
299
312
** kwargs ,
300
313
)
301
314
except Exception as e :
302
- msg = "Failed to construct the AuthnRequest for state"
315
+ msg = {
316
+ "message" : "AuthnRequest Failed" ,
317
+ "error" : f"Failed to construct the AuthnRequest for state: { e } " ,
318
+ }
303
319
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
304
- logger .error (logline , exc_info = True )
305
- raise SATOSAAuthenticationError (context .state , "Failed to construct the AuthnRequest" ) from e
320
+ logger .info (logline )
321
+ raise SATOSAAuthenticationError (context .state , msg ) from e
306
322
307
323
if self .sp .config .getattr ('allow_unsolicited' , 'sp' ) is False :
308
324
if req_id in self .outstanding_queries :
309
- msg = "Request with duplicate id {}" .format (req_id )
325
+ msg = {
326
+ "message" : "AuthnRequest Failed" ,
327
+ "error" : f"Request with duplicate id { req_id } " ,
328
+ }
310
329
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
311
- logger .debug (logline )
330
+ logger .info (logline )
312
331
raise SATOSAAuthenticationError (context .state , msg )
313
332
self .outstanding_queries [req_id ] = req_id
314
333
@@ -378,43 +397,78 @@ def authn_response(self, context, binding):
378
397
:param binding: The saml binding type
379
398
:return: response
380
399
"""
400
+
401
+ if self .name not in context .state :
402
+ """
403
+ If we end up here, it means that the user returns to the proxy
404
+ without the SATOSA session cookie. This can happen at least in the
405
+ following cases:
406
+ - the user deleted the cookie from the browser
407
+ - the browser of the user blocked the cookie
408
+ - the user has completed an authentication flow, the cookie has
409
+ been removed by SATOSA and then the user used the back button
410
+ of their browser and resend the authentication response, but
411
+ without the SATOSA session cookie
412
+ """
413
+ msg = {
414
+ "message" : "Authentication failed" ,
415
+ "error" : "Received AuthN response without a SATOSA session cookie" ,
416
+ }
417
+ logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
418
+ logger .info (logline )
419
+ raise SATOSAMissingStateError (msg )
420
+
381
421
if not context .request .get ("SAMLResponse" ):
382
- msg = "Missing Response for state"
422
+ msg = {
423
+ "message" : "Authentication failed" ,
424
+ "error" : "SAML Response not found in context.request" ,
425
+ }
383
426
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
384
- logger .debug (logline )
385
- raise SATOSAAuthenticationError (context .state , "Missing Response" )
427
+ logger .info (logline )
428
+ raise SATOSAAuthenticationError (context .state , msg )
386
429
387
430
try :
388
431
authn_response = self .sp .parse_authn_request_response (
389
432
context .request ["SAMLResponse" ],
390
- binding , outstanding = self .outstanding_queries )
391
- except Exception as err :
392
- msg = "Failed to parse authn request for state"
433
+ binding ,
434
+ outstanding = self .outstanding_queries ,
435
+ )
436
+ except Exception as e :
437
+ msg = {
438
+ "message" : "Authentication failed" ,
439
+ "error" : f"Failed to parse Authn response: { err } " ,
440
+ }
393
441
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
394
442
logger .debug (logline , exc_info = True )
395
- raise SATOSAAuthenticationError (context .state , "Failed to parse authn request" ) from err
443
+ logger .info (logline )
444
+ raise SATOSAAuthenticationError (context .state , msg ) from e
396
445
397
446
if self .sp .config .getattr ('allow_unsolicited' , 'sp' ) is False :
398
447
req_id = authn_response .in_response_to
399
448
if req_id not in self .outstanding_queries :
400
- msg = "No request with id: {}" .format (req_id ),
449
+ msg = {
450
+ "message" : "Authentication failed" ,
451
+ "error" : f"No corresponding request with id: { req_id } " ,
452
+ }
401
453
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
402
- logger .debug (logline )
454
+ logger .info (logline )
403
455
raise SATOSAAuthenticationError (context .state , msg )
404
456
del self .outstanding_queries [req_id ]
405
457
406
458
# check if the relay_state matches the cookie state
407
459
if context .state [self .name ]["relay_state" ] != context .request ["RelayState" ]:
408
- msg = "State did not match relay state for state"
460
+ msg = {
461
+ "message" : "Authentication failed" ,
462
+ "error" : "Response state query param did not match relay state for request" ,
463
+ }
409
464
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
410
- logger .debug (logline )
411
- raise SATOSAAuthenticationError (context .state , "State did not match relay state" )
465
+ logger .info (logline )
466
+ raise SATOSAAuthenticationError (context .state , msg )
412
467
413
468
context .decorate (Context .KEY_METADATA_STORE , self .sp .metadata )
414
469
if self .config .get (SAMLBackend .KEY_MEMORIZE_IDP ):
415
470
issuer = authn_response .response .issuer .text .strip ()
416
471
context .state [Context .KEY_MEMORIZED_IDP ] = issuer
417
- context .state .pop (self .name , None )
418
472
context .state .pop (Context .KEY_FORCE_AUTHN , None )
419
473
return self .auth_callback_func (context , self ._translate_response (authn_response , context .state ))
420
474
@@ -431,13 +485,18 @@ def disco_response(self, context):
431
485
info = context .request
432
486
state = context .state
433
487
434
- try :
435
- entity_id = info ["entityID" ]
436
- except KeyError as err :
437
- msg = "No IDP chosen for state"
438
- logline = lu .LOG_FMT .format (id = lu .get_session_id (state ), message = msg )
439
- logger .debug (logline , exc_info = True )
440
- raise SATOSAAuthenticationError (state , "No IDP chosen" ) from err
488
+ if 'SATOSA_BASE' not in state :
489
+ raise SATOSAAuthenticationFlowError ("Discovery response without AuthN request" )
490
+
491
+ entity_id = info .get ("entityID" )
492
+ msg = {
493
+ "message" : "Received response from the discovery service" ,
494
+ "entity_id" : entity_id ,
495
+ }
496
+ logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
497
+ logger .info (logline )
498
+ if not entity_id :
499
+ raise SATOSAAuthenticationError (state , msg ) from err
441
500
442
501
return self .authn_request (context , entity_id )
443
502
@@ -488,11 +547,20 @@ def _translate_response(self, response, state):
488
547
subject_id = name_id ,
489
548
)
490
549
491
- msg = "backend received attributes:\n {}" .format (
492
- json .dumps (response .ava , indent = 4 )
493
- )
550
+ msg = "backend received attributes: {}" .format (response .ava )
494
551
logline = lu .LOG_FMT .format (id = lu .get_session_id (state ), message = msg )
495
552
logger .debug (logline )
553
+
554
+ msg = {
555
+ "message" : "Attributes received by the backend" ,
556
+ "issuer" : issuer ,
557
+ "attributes" : " " .join (list (response .ava .keys ()))
558
+ }
559
+ if name_id_format :
560
+ msg ['name_id' ] = name_id_format
561
+ logline = lu .LOG_FMT .format (id = lu .get_session_id (state ), message = msg )
562
+ logger .info (logline )
563
+
496
564
return internal_resp
497
565
498
566
def _metadata_endpoint (self , context ):
0 commit comments