From 5a250724a73a095e4be9a841740831184718672a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20LAJOIE?= Date: Sat, 26 Nov 2016 15:37:21 +0100 Subject: [PATCH 1/2] Allow to not encrypt by setting the recipient certificate as optional --- doc/index.rst | 4 ++-- wsse/suds.py | 28 ++++++++++++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 14dbb5f..28e4d68 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -112,8 +112,8 @@ used to encrypt outgoing messages and verify the signature on incoming messages. Note that ``WssePlugin`` is currently hardcoded to sign the ``wsu:Timestamp`` -and ``soap:Body`` elements, and to encrypt only the first child of the -``soap:Body`` element. Pull requests to add more flexibility are welcome. +and ``soap:Body`` elements, and to optionally encrypt only the first child of +the ``soap:Body`` element. Pull requests to add more flexibility are welcome. Standalone functions diff --git a/wsse/suds.py b/wsse/suds.py index 3fe1d11..5a07984 100644 --- a/wsse/suds.py +++ b/wsse/suds.py @@ -2,17 +2,22 @@ from __future__ import absolute_import from suds.plugin import MessagePlugin +from logging import getLogger + from .encryption import encrypt, decrypt from .signing import sign, verify +log = getLogger(__name__) + class WssePlugin(MessagePlugin): """Suds message plugin that performs WS-Security signing and encryption. - Encrypts and signs outgoing messages (the soap:Body and the wsu:Timestamp - security token, which must be present); decrypts and verifies signature on - incoming messages. + Encrypts (optional) and signs outgoing messages (the soap:Body and the + wsu:Timestamp security token, which must be present); decrypts and verifies + signature on incoming messages. + Encryption is done if their_certfile is set. Uses X509 certificates for both encryption and signing. Requires our cert and its private key, and their cert (all as file paths). @@ -39,19 +44,30 @@ class WssePlugin(MessagePlugin): only the first child element of the soap:Body will be encrypted). """ - def __init__(self, keyfile, certfile, their_certfile): + def __init__(self, keyfile, certfile, their_certfile=None): + """ + @param keyfile path to the private key to sign the content + @param certfile path to the certificate to sign the content + @param their_certfile Optional, path to the recipient certificate to + encrypt, if not set no encryption is done + """ self.keyfile = keyfile self.certfile = certfile self.their_certfile = their_certfile + log.info("WSSE plugin initialized") def sending(self, context): """Sign and encrypt outgoing message envelope.""" context.envelope = sign( context.envelope, self.keyfile, self.certfile) - context.envelope = encrypt(context.envelope, self.their_certfile) + if self.their_certfile: + log.debug("Encrypt the body") + context.envelope = encrypt(context.envelope, self.their_certfile) def received(self, context): """Decrypt and verify signature of incoming reply envelope.""" if context.reply: - context.reply = decrypt(context.reply, self.keyfile) + if self.their_certfile: + log.debug("Decrypt the body") + context.reply = decrypt(context.reply, self.keyfile) verify(context.reply, self.their_certfile) From 0651987b5bbfd190cdafefdb9087222fa21bf325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20LAJOIE?= Date: Thu, 1 Dec 2016 14:40:14 +0100 Subject: [PATCH 2/2] Sign timestamp only when the tag is set --- doc/index.rst | 11 ++++++----- wsse/signing.py | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 28e4d68..bad4d43 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -100,9 +100,9 @@ list of ``plugins`` passed to a new ``Client`` instance:: ) ``WssePlugin`` requires that the outgoing messages already have a -``wsse:Security`` element in the ``soap:Header`` with a ``wsu:Timestamp`` -token. Suds can do this via its ``Security`` and ``Timestamp`` objects, as -shown in the above example. +``wsse:Security`` element in the ``soap:Header`` with an optional +``wsu:Timestamp`` token. Suds can do this via its ``Security`` and +``Timestamp`` objects, as shown in the above example. In the example, ``our_keyfile_path``, ``our_certfile_path``, and ``their_certfile_path`` should all be absolute filesystem paths to X509 @@ -112,8 +112,9 @@ used to encrypt outgoing messages and verify the signature on incoming messages. Note that ``WssePlugin`` is currently hardcoded to sign the ``wsu:Timestamp`` -and ``soap:Body`` elements, and to optionally encrypt only the first child of -the ``soap:Body`` element. Pull requests to add more flexibility are welcome. +(if it is present) and ``soap:Body`` elements, and to optionally encrypt only +the first child of the ``soap:Body`` element. +Pull requests to add more flexibility are welcome. Standalone functions diff --git a/wsse/signing.py b/wsse/signing.py index 22beac7..321aa54 100644 --- a/wsse/signing.py +++ b/wsse/signing.py @@ -20,7 +20,7 @@ def sign(envelope, keyfile, certfile): """Sign given SOAP envelope with WSSE sig using given key and cert. Sign the wsu:Timestamp node in the wsse:Security header and the soap:Body; - both must be present. + Timestamp is optional, Body must be present. Add a ds:Signature node in the wsse:Security header containing the signature. @@ -135,7 +135,8 @@ def sign(envelope, keyfile, certfile): ctx = xmlsec.SignatureContext() ctx.key = key _sign_node(ctx, signature, doc.find(ns(SOAP_NS, 'Body'))) - _sign_node(ctx, signature, security.find(ns(WSU_NS, 'Timestamp'))) + if security.find(ns(WSU_NS, 'Timestamp')): + _sign_node(ctx, signature, security.find(ns(WSU_NS, 'Timestamp'))) ctx.sign(signature) # Place the X509 data inside a WSSE SecurityTokenReference within