1616from xml .dom .minidom import Document
1717
1818from onelogin .saml2 .constants import OneLogin_Saml2_Constants
19- from onelogin .saml2 .utils import OneLogin_Saml2_Utils
19+ from onelogin .saml2 .utils import OneLogin_Saml2_Utils , return_false_on_exception
2020
2121
2222class OneLogin_Saml2_Response (object ):
@@ -93,13 +93,21 @@ def is_valid(self, request_data, request_id=None):
9393
9494 if self .__settings .is_strict ():
9595 no_valid_xml_msg = 'Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd'
96- res = OneLogin_Saml2_Utils .validate_xml (etree .tostring (self .document ), 'saml-schema-protocol-2.0.xsd' , self .__settings .is_debug_active ())
96+ res = OneLogin_Saml2_Utils .validate_xml (
97+ etree .tostring (self .document ),
98+ 'saml-schema-protocol-2.0.xsd' ,
99+ self .__settings .is_debug_active ()
100+ )
97101 if not isinstance (res , Document ):
98102 raise Exception (no_valid_xml_msg )
99103
100104 # If encrypted, check also the decrypted document
101105 if self .encrypted :
102- res = OneLogin_Saml2_Utils .validate_xml (etree .tostring (self .decrypted_document ), 'saml-schema-protocol-2.0.xsd' , self .__settings .is_debug_active ())
106+ res = OneLogin_Saml2_Utils .validate_xml (
107+ etree .tostring (self .decrypted_document ),
108+ 'saml-schema-protocol-2.0.xsd' ,
109+ self .__settings .is_debug_active ()
110+ )
103111 if not isinstance (res , Document ):
104112 raise Exception (no_valid_xml_msg )
105113
@@ -125,8 +133,7 @@ def is_valid(self, request_data, request_id=None):
125133 raise Exception ('The Assertion must include a Conditions element' )
126134
127135 # Validates Assertion timestamps
128- if not self .validate_timestamps ():
129- raise Exception ('Timing issues (please check your clock settings)' )
136+ self .validate_timestamps (raise_exceptions = True )
130137
131138 # Checks that an AuthnStatement element exists and is unique
132139 if not self .check_one_authnstatement ():
@@ -217,12 +224,14 @@ def is_valid(self, request_data, request_id=None):
217224 fingerprintalg = idp_data .get ('certFingerprintAlgorithm' , None )
218225
219226 # If find a Signature on the Response, validates it checking the original response
220- if has_signed_response and not OneLogin_Saml2_Utils .validate_sign (self .document , cert , fingerprint , fingerprintalg , xpath = OneLogin_Saml2_Utils .RESPONSE_SIGNATURE_XPATH ):
221- raise Exception ('Signature validation failed. SAML Response rejected' )
227+ if has_signed_response :
228+ # Raise exception if response signature is invalid
229+ OneLogin_Saml2_Utils .validate_sign (self .document , cert , fingerprint , fingerprintalg , xpath = OneLogin_Saml2_Utils .RESPONSE_SIGNATURE_XPATH , raise_exceptions = True )
222230
223231 document_check_assertion = self .decrypted_document if self .encrypted else self .document
224- if has_signed_assertion and not OneLogin_Saml2_Utils .validate_sign (document_check_assertion , cert , fingerprint , fingerprintalg , xpath = OneLogin_Saml2_Utils .ASSERTION_SIGNATURE_XPATH ):
225- raise Exception ('Signature validation failed. SAML Response rejected' )
232+ if has_signed_assertion :
233+ # Raise exception if assertion signature is invalid
234+ OneLogin_Saml2_Utils .validate_sign (document_check_assertion , cert , fingerprint , fingerprintalg , xpath = OneLogin_Saml2_Utils .ASSERTION_SIGNATURE_XPATH , raise_exceptions = True )
226235
227236 return True
228237 except Exception as err :
@@ -485,13 +494,20 @@ def process_signed_elements(self):
485494 signed_elements .append (signed_element )
486495
487496 if signed_elements :
488- if not self .validate_signed_elements (signed_elements ):
497+ if not self .validate_signed_elements (signed_elements , raise_exceptions = True ):
489498 raise Exception ('Found an unexpected Signature Element. SAML Response rejected' )
490499 return signed_elements
491500
501+ @return_false_on_exception
492502 def validate_signed_elements (self , signed_elements ):
493503 """
494504 Verifies that the document has the expected signed nodes.
505+
506+ :param signed_elements: The signed elements to be checked
507+ :type signed_elements: list
508+
509+ :param raise_exceptions: Whether to return false on failure or raise an exception
510+ :type raise_exceptions: Boolean
495511 """
496512 if len (signed_elements ) > 2 :
497513 return False
@@ -518,10 +534,14 @@ def validate_signed_elements(self, signed_elements):
518534
519535 return True
520536
537+ @return_false_on_exception
521538 def validate_timestamps (self ):
522539 """
523540 Verifies that the document is valid according to Conditions Element
524541
542+ :param raise_exceptions: Whether to return false on failure or raise an exception
543+ :type raise_exceptions: Boolean
544+
525545 :returns: True if the condition is valid, False otherwise
526546 :rtype: bool
527547 """
@@ -531,9 +551,9 @@ def validate_timestamps(self):
531551 nb_attr = conditions_node .get ('NotBefore' )
532552 nooa_attr = conditions_node .get ('NotOnOrAfter' )
533553 if nb_attr and OneLogin_Saml2_Utils .parse_SAML_to_time (nb_attr ) > OneLogin_Saml2_Utils .now () + OneLogin_Saml2_Constants .ALLOWED_CLOCK_DRIFT :
534- return False
554+ raise Exception ( 'Could not validate timestamp: not yet valid. Check system clock.' )
535555 if nooa_attr and OneLogin_Saml2_Utils .parse_SAML_to_time (nooa_attr ) + OneLogin_Saml2_Constants .ALLOWED_CLOCK_DRIFT <= OneLogin_Saml2_Utils .now ():
536- return False
556+ raise Exception ( 'Could not validate timestamp: expired. Check system clock.' )
537557 return True
538558
539559 def __query_assertion (self , xpath_expr ):
@@ -588,8 +608,10 @@ def __decrypt_assertion(self, dom):
588608 Decrypts the Assertion
589609
590610 :raises: Exception if no private key available
611+
591612 :param dom: Encrypted Assertion
592613 :type dom: Element
614+
593615 :returns: Decrypted Assertion
594616 :rtype: Element
595617 """
0 commit comments