@@ -272,6 +272,17 @@ def _signature_prepare(envelope, key, signature_method, digest_method, signature
272272 header .find (QName (node ["Namespace" ], node ["Name" ])),
273273 digest_method ,
274274 )
275+ # Sign elements specified by XPath expressions
276+ for element in signatures .get ("elements" , []):
277+ _sign_node_by_xpath (
278+ ctx ,
279+ signature ,
280+ envelope ,
281+ element ["xpath" ],
282+ element ["xpath_version" ],
283+ digest_method
284+ )
285+
275286 ctx .sign (signature )
276287
277288 # Place the X509 data inside a WSSE SecurityTokenReference within
@@ -281,6 +292,20 @@ def _signature_prepare(envelope, key, signature_method, digest_method, signature
281292 sec_token_ref = etree .SubElement (key_info , QName (ns .WSSE , "SecurityTokenReference" ))
282293 return security , sec_token_ref , x509_data
283294
295+ def _sign_node_by_xpath (ctx , signature , envelope , xpath , xpath_version , digest_method ):
296+ # Create an XPath evaluator with the appropriate version
297+ if xpath_version == '1.0' :
298+ evaluator = etree .XPath (xpath , namespaces = envelope .nsmap )
299+ else :
300+ evaluator = etree .XPath (xpath , namespaces = envelope .nsmap , extension = {('http://www.w3.org/TR/1999/REC-xpath-19991116' , 'version' ): xpath_version })
301+
302+ # Evaluate the XPath expression
303+ nodes = evaluator (envelope )
304+
305+ # Sign each node found by the XPath expression
306+ for node in nodes :
307+ _sign_node (ctx , signature , node , digest_method )
308+
284309
285310def _sign_envelope_with_key (
286311 envelope , key , signature_method , digest_method , signatures = None
0 commit comments