Skip to content

Commit 5e66ccc

Browse files
committed
Sign elements required by WSDL
1 parent 764b96b commit 5e66ccc

File tree

4 files changed

+31
-16
lines changed

4 files changed

+31
-16
lines changed

src/zeep/wsdl/bindings/soap.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ def _create(self, operation, args, kwargs, client=None, options=None):
8989
if isinstance(client.wsse, list):
9090
for wsse in client.wsse:
9191
envelope, http_headers = wsse.apply(
92-
envelope, http_headers)
92+
envelope, http_headers, operation_obj.binding.signatures)
9393
else:
9494
envelope, http_headers = client.wsse.apply(
95-
envelope, http_headers)
95+
envelope, http_headers, operation_obj.binding.signatures)
9696

9797
# Add extra http headers from the setings object
9898
if client.settings.extra_http_headers:

src/zeep/wsse/signature.py

+25-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from zeep import ns
1515
from zeep.exceptions import SignatureVerificationFailed
1616
from zeep.utils import detect_soap_env
17+
from zeep.wsdl.utils import get_or_create_header
1718
from zeep.wsse.utils import ensure_id, get_security_header
1819

1920
try:
@@ -52,9 +53,9 @@ def __init__(self, key_data, cert_data, password=None):
5253
self.cert_data = cert_data
5354
self.password = password
5455

55-
def apply(self, envelope, headers):
56+
def apply(self, envelope, headers, signatures=None):
5657
key = _make_sign_key(self.key_data, self.cert_data, self.password)
57-
_sign_envelope_with_key(envelope, key)
58+
_sign_envelope_with_key(envelope, key, signatures)
5859
return envelope, headers
5960

6061
def verify(self, envelope):
@@ -76,9 +77,9 @@ class BinarySignature(Signature):
7677
7778
Place the key information into BinarySecurityElement."""
7879

79-
def apply(self, envelope, headers):
80+
def apply(self, envelope, headers, signatures=None):
8081
key = _make_sign_key(self.key_data, self.cert_data, self.password)
81-
_sign_envelope_with_key_binary(envelope, key)
82+
_sign_envelope_with_key_binary(envelope, key, signatures)
8283
return envelope, headers
8384

8485

@@ -91,7 +92,7 @@ def check_xmlsec_import():
9192
)
9293

9394

94-
def sign_envelope(envelope, keyfile, certfile, password=None):
95+
def sign_envelope(envelope, keyfile, certfile, password=None, signatures=None):
9596
"""Sign given SOAP envelope with WSSE sig using given key and cert.
9697
9798
Sign the wsu:Timestamp node in the wsse:Security header and the soap:Body;
@@ -181,10 +182,10 @@ def sign_envelope(envelope, keyfile, certfile, password=None):
181182
"""
182183
# Load the signing key and certificate.
183184
key = _make_sign_key(_read_file(keyfile), _read_file(certfile), password)
184-
return _sign_envelope_with_key(envelope, key)
185+
return _sign_envelope_with_key(envelope, key, signatures)
185186

186187

187-
def _signature_prepare(envelope, key):
188+
def _signature_prepare(envelope, key, signatures=None):
188189
"""Prepare envelope and sign."""
189190
soap_env = detect_soap_env(envelope)
190191

@@ -210,8 +211,20 @@ def _signature_prepare(envelope, key):
210211
# Perform the actual signing.
211212
ctx = xmlsec.SignatureContext()
212213
ctx.key = key
213-
_sign_node(ctx, signature, envelope.find(QName(soap_env, 'Body')))
214+
# Sign default elements
214215
_sign_node(ctx, signature, security.find(QName(ns.WSU, 'Timestamp')))
216+
217+
# Sign extra elements defined in WSDL
218+
if signatures is not None:
219+
if signatures['body'] or signatures['everything']:
220+
_sign_node(ctx, signature, envelope.find(QName(soap_env, 'Body')))
221+
header = get_or_create_header(envelope)
222+
if signatures['everything']:
223+
for node in header.iterchildren():
224+
_sign_node(ctx, signature, node)
225+
else:
226+
for node in signatures['header']:
227+
_sign_node(ctx, signature, header.find(QName(node['Namespace'], node['Name'])))
215228
ctx.sign(signature)
216229

217230
# Place the X509 data inside a WSSE SecurityTokenReference within
@@ -223,13 +236,13 @@ def _signature_prepare(envelope, key):
223236
return security, sec_token_ref, x509_data
224237

225238

226-
def _sign_envelope_with_key(envelope, key):
227-
_, sec_token_ref, x509_data = _signature_prepare(envelope, key)
239+
def _sign_envelope_with_key(envelope, key, signatures=None):
240+
_, sec_token_ref, x509_data = _signature_prepare(envelope, key, signatures=signatures)
228241
sec_token_ref.append(x509_data)
229242

230243

231-
def _sign_envelope_with_key_binary(envelope, key):
232-
security, sec_token_ref, x509_data = _signature_prepare(envelope, key)
244+
def _sign_envelope_with_key_binary(envelope, key, signatures=None):
245+
security, sec_token_ref, x509_data = _signature_prepare(envelope, key, signatures=signatures)
233246
ref = etree.SubElement(sec_token_ref, QName(ns.WSSE, 'Reference'),
234247
{'ValueType': 'http://docs.oasis-open.org/wss/2004/01/'
235248
'oasis-200401-wss-x509-token-profile-1.0#X509v3'})

src/zeep/wsse/username.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __init__(self, username, password=None, password_digest=None,
4646
self.created = created
4747
self.use_digest = use_digest
4848

49-
def apply(self, envelope, headers):
49+
def apply(self, envelope, headers, operation_obj=None):
5050
security = utils.get_security_header(envelope)
5151

5252
# The token placeholder might already exists since it is specified in

tests/test_wsse_signature.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ def test_verify_error():
8282
</soapenv:Envelope>
8383
""")
8484

85-
signature.sign_envelope(envelope, KEY_FILE, KEY_FILE)
85+
# Force body signature
86+
signatures = {'everything': False, 'body': True, 'header': []}
87+
signature.sign_envelope(envelope, KEY_FILE, KEY_FILE, signatures=signatures)
8688
nsmap = {'tns': 'http://tests.python-zeep.org/'}
8789

8890
for elm in envelope.xpath('//tns:Argument', namespaces=nsmap):

0 commit comments

Comments
 (0)