@@ -272,6 +272,17 @@ def _signature_prepare(envelope, key, signature_method, digest_method, signature
272
272
header .find (QName (node ["Namespace" ], node ["Name" ])),
273
273
digest_method ,
274
274
)
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
+
275
286
ctx .sign (signature )
276
287
277
288
# Place the X509 data inside a WSSE SecurityTokenReference within
@@ -281,6 +292,20 @@ def _signature_prepare(envelope, key, signature_method, digest_method, signature
281
292
sec_token_ref = etree .SubElement (key_info , QName (ns .WSSE , "SecurityTokenReference" ))
282
293
return security , sec_token_ref , x509_data
283
294
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
+
284
309
285
310
def _sign_envelope_with_key (
286
311
envelope , key , signature_method , digest_method , signatures = None
0 commit comments