Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to not encrypt by setting the recipient certificate as optional #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 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
Expand Down
5 changes: 3 additions & 2 deletions wsse/signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
28 changes: 22 additions & 6 deletions wsse/suds.py
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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)