@@ -918,51 +918,163 @@ def validate_sign(xml, cert=None, fingerprint=None, fingerprintalg='sha1', valid
918918
919919 xmlsec .addIDs (elem , ["ID" ])
920920
921- signature_nodes = OneLogin_Saml2_Utils .query (elem , '//ds:Signature' )
921+ signature_nodes = OneLogin_Saml2_Utils .query (elem , '/samlp:Response /ds:Signature' )
922922
923- if len (signature_nodes ) > 0 :
923+ if not len (signature_nodes ) > 0 :
924+ signature_nodes += OneLogin_Saml2_Utils .query (elem , '/samlp:Response/saml:EncryptedAssertion/saml:Assertion/ds:Signature' )
925+ signature_nodes += OneLogin_Saml2_Utils .query (elem , '/samlp:Response/saml:Assertion/ds:Signature' )
926+
927+ if len (signature_nodes ) == 1 :
924928 signature_node = signature_nodes [0 ]
925929
926- if (cert is None or cert == '' ) and fingerprint :
927- x509_certificate_nodes = OneLogin_Saml2_Utils .query (signature_node , '//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate' )
928- if len (x509_certificate_nodes ) > 0 :
929- x509_certificate_node = x509_certificate_nodes [0 ]
930- x509_cert_value = x509_certificate_node .text
931- x509_fingerprint_value = OneLogin_Saml2_Utils .calculate_x509_fingerprint (x509_cert_value , fingerprintalg )
932- if fingerprint == x509_fingerprint_value :
933- cert = OneLogin_Saml2_Utils .format_cert (x509_cert_value )
930+ return OneLogin_Saml2_Utils .validate_node_sign (signature_node , elem , cert , fingerprint , fingerprintalg , validatecert , debug )
931+ else :
932+ return False
933+ except Exception :
934+ return False
934935
935- if cert is None or cert == '' :
936- return False
936+ @staticmethod
937+ def validate_metadata_sign (xml , cert = None , fingerprint = None , fingerprintalg = 'sha1' , validatecert = False , debug = False ):
938+ """
939+ Validates a signature of a EntityDescriptor.
937940
938- # Check if Reference URI is empty
939- reference_elem = OneLogin_Saml2_Utils .query (signature_node , '//ds:Reference' )
940- if len (reference_elem ) > 0 :
941- if reference_elem [0 ].get ('URI' ) == '' :
942- reference_elem [0 ].set ('URI' , '#%s' % signature_node .getparent ().get ('ID' ))
941+ :param xml: The element we should validate
942+ :type: string | Document
943943
944- dsig_ctx = xmlsec .DSigCtx ()
944+ :param cert: The pubic cert
945+ :type: string
945946
946- file_cert = OneLogin_Saml2_Utils .write_temp_file (cert )
947+ :param fingerprint: The fingerprint of the public cert
948+ :type: string
947949
948- if validatecert :
949- mngr = xmlsec .KeysMngr ()
950- mngr .loadCert (file_cert .name , xmlsec .KeyDataFormatCertPem , xmlsec .KeyDataTypeTrusted )
951- dsig_ctx = xmlsec .DSigCtx (mngr )
952- else :
953- dsig_ctx = xmlsec .DSigCtx ()
954- dsig_ctx .signKey = xmlsec .Key .load (file_cert .name , xmlsec .KeyDataFormatCertPem , None )
950+ :param fingerprintalg: The algorithm used to build the fingerprint
951+ :type: string
952+
953+ :param validatecert: If true, will verify the signature and if the cert is valid.
954+ :type: bool
955+
956+ :param debug: Activate the xmlsec debug
957+ :type: bool
958+ """
959+ try :
960+ if xml is None or xml == '' :
961+ raise Exception ('Empty string supplied as input' )
962+ elif isinstance (xml , etree ._Element ):
963+ elem = xml
964+ elif isinstance (xml , Document ):
965+ xml = xml .toxml ()
966+ elem = fromstring (str (xml ))
967+ elif isinstance (xml , Element ):
968+ xml .setAttributeNS (
969+ unicode (OneLogin_Saml2_Constants .NS_MD ),
970+ 'xmlns:md' ,
971+ unicode (OneLogin_Saml2_Constants .NS_MD )
972+ )
973+ xml = xml .toxml ()
974+ elem = fromstring (str (xml ))
975+ elif isinstance (xml , basestring ):
976+ elem = fromstring (str (xml ))
977+ else :
978+ raise Exception ('Error parsing xml string' )
979+
980+ xmlsec .initialize ()
981+
982+ if debug :
983+ xmlsec .set_error_callback (print_xmlsec_errors )
984+
985+ xmlsec .addIDs (elem , ["ID" ])
986+
987+ signature_nodes = OneLogin_Saml2_Utils .query (elem , '/md:EntitiesDescriptor/ds:Signature' )
955988
956- file_cert .close ()
989+ if len (signature_nodes ) == 0 :
990+ signature_nodes += OneLogin_Saml2_Utils .query (elem , '/md:EntityDescriptor/ds:Signature' )
957991
958- dsig_ctx .setEnabledKeyData ([xmlsec .KeyDataX509 ])
959- dsig_ctx .verify (signature_node )
992+ if len (signature_nodes ) == 0 :
993+ signature_nodes += OneLogin_Saml2_Utils .query (elem , '/md:EntityDescriptor/md:SPSSODescriptor/ds:Signature' )
994+ signature_nodes += OneLogin_Saml2_Utils .query (elem , '/md:EntityDescriptor/md:IDPSSODescriptor/ds:Signature' )
995+
996+ if len (signature_nodes ) > 0 :
997+ for signature_node in signature_nodes :
998+ if not OneLogin_Saml2_Utils .validate_node_sign (signature_node , elem , cert , fingerprint , fingerprintalg , validatecert , debug ):
999+ return False
9601000 return True
9611001 else :
9621002 return False
9631003 except Exception :
9641004 return False
9651005
1006+ @staticmethod
1007+ def validate_node_sign (signature_node , elem , cert = None , fingerprint = None , fingerprintalg = 'sha1' , validatecert = False , debug = False ):
1008+ """
1009+ Validates a signature node.
1010+
1011+ :param signature_node: The signature node
1012+ :type: Node
1013+
1014+ :param xml: The element we should validate
1015+ :type: Document
1016+
1017+ :param cert: The pubic cert
1018+ :type: string
1019+
1020+ :param fingerprint: The fingerprint of the public cert
1021+ :type: string
1022+
1023+ :param fingerprintalg: The algorithm used to build the fingerprint
1024+ :type: string
1025+
1026+ :param validatecert: If true, will verify the signature and if the cert is valid.
1027+ :type: bool
1028+
1029+ :param debug: Activate the xmlsec debug
1030+ :type: bool
1031+ """
1032+ try :
1033+ xmlsec .initialize ()
1034+
1035+ if debug :
1036+ xmlsec .set_error_callback (print_xmlsec_errors )
1037+
1038+ xmlsec .addIDs (elem , ["ID" ])
1039+
1040+ if (cert is None or cert == '' ) and fingerprint :
1041+ x509_certificate_nodes = OneLogin_Saml2_Utils .query (signature_node , '//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate' )
1042+ if len (x509_certificate_nodes ) > 0 :
1043+ x509_certificate_node = x509_certificate_nodes [0 ]
1044+ x509_cert_value = x509_certificate_node .text
1045+ x509_fingerprint_value = OneLogin_Saml2_Utils .calculate_x509_fingerprint (x509_cert_value , fingerprintalg )
1046+ if fingerprint == x509_fingerprint_value :
1047+ cert = OneLogin_Saml2_Utils .format_cert (x509_cert_value )
1048+
1049+ if cert is None or cert == '' :
1050+ return False
1051+
1052+ # Check if Reference URI is empty
1053+ reference_elem = OneLogin_Saml2_Utils .query (signature_node , '//ds:Reference' )
1054+ if len (reference_elem ) > 0 :
1055+ if reference_elem [0 ].get ('URI' ) == '' :
1056+ reference_elem [0 ].set ('URI' , '#%s' % signature_node .getparent ().get ('ID' ))
1057+
1058+ dsig_ctx = xmlsec .DSigCtx ()
1059+
1060+ file_cert = OneLogin_Saml2_Utils .write_temp_file (cert )
1061+
1062+ if validatecert :
1063+ mngr = xmlsec .KeysMngr ()
1064+ mngr .loadCert (file_cert .name , xmlsec .KeyDataFormatCertPem , xmlsec .KeyDataTypeTrusted )
1065+ dsig_ctx = xmlsec .DSigCtx (mngr )
1066+ else :
1067+ dsig_ctx = xmlsec .DSigCtx ()
1068+ dsig_ctx .signKey = xmlsec .Key .load (file_cert .name , xmlsec .KeyDataFormatCertPem , None )
1069+
1070+ file_cert .close ()
1071+
1072+ dsig_ctx .setEnabledKeyData ([xmlsec .KeyDataX509 ])
1073+ dsig_ctx .verify (signature_node )
1074+ return True
1075+ except Exception :
1076+ return False
1077+
9661078 @staticmethod
9671079 def validate_binary_sign (signed_query , signature , cert = None , algorithm = OneLogin_Saml2_Constants .RSA_SHA1 , debug = False ):
9681080 """
0 commit comments