mvantellingen / python-zeep

A Python SOAP client
http://docs.python-zeep.org
Other
1.88k stars 578 forks source link

Adding timestamp, signature and encryption on SOAP server with signature (x509) #1281

Open conradogarciaberrotaran opened 2 years ago

conradogarciaberrotaran commented 2 years ago

Hey all, i'm trying to send SOAP messages to a server that requires x509 certificates. I've got private and public keys and a keystore generated using keytool. I have the instructions to make the connection using SOAP UI and on the "Outgoing WS-Security Configurations", this are the fields that I need to set: Timestamp information Signature configuration Encryption configuration

image image image image

I'm not sure how to replicate this on zeep, any help is appreciated.

Thanks!

davisfelipe commented 2 years ago

Hi, few days ago, i made this code example:

from datetime import datetime, timedelta

from zeep import Client
from zeep.wsse import utils
from zeep.wsse.signature import Signature

# You must install xmlsec in your environment to use Signatures, by default
# Signature class have signature algorithm with RSA_SHA1 and digestive
# algorithm with SHA1.

# In my case, i sign payload with issuer name and serial number, if you need
# a binary security token, check this method and rewrite:
# https://github.com/mvantellingen/python-zeep/blob/2f35b7d29355ba646f5e3c6e9925033d5d6df8bb/src/zeep/wsse/signature.py#L219
class OwnSignature(Signature):

    def apply(self, envelope, headers):
        # Get security header or create if not exist and add Timestamp
        security = utils.get_security_header(envelope)

        created = datetime.utcnow()
        expired = created + timedelta(seconds=5000)

        timestamp_header = utils.WSU('Timestamp')
        timestamp_header.extend([
            utils.WSU(
                'Created', created.replace(microsecond=0).isoformat() + 'Z'
            ),
            utils.WSU(
                'Expires', expired.replace(microsecond=0).isoformat() + 'Z'
            )
        ])

        security.append(timestamp_header)
        super().apply(envelope, headers)

        return envelope, headers

# Verify your sign file, in my case, i can't read JKS extension, so i used
# KeyStore explorer to export file as pem format  and create the cer file.
signature = OwnSignature(
    key_file='file.key',
    certfile='cert_file.cer',
    password='MyPasswordFile'
)

client = Client(
    '...?wsdl',
    wsse=signature
)

and that is all.

conradogarciaberrotaran commented 2 years ago

Thank you @davisfelipe. I'm going to check it out. Couple of questions: shouldn't the apply method return the envelope and headers? I have both private and public keys labeled as "client", a JKS file, a public key labeled as "server" and a .pem certificate.

Not sure which file should I use. Also, they didin't provide a password file. i'm a bit confused by that. Any help will be huge, i've been stucked with this task for months.

davisfelipe commented 2 years ago

Thank you @davisfelipe. I'm going to check it out. Couple of questions: shouldn't the apply method return the envelope and headers? I have both private and public keys labeled as "client", a JKS file, a public key labeled as "server" and a .pem certificate.

Not sure which file should I use. Also, they didin't provide a password file. i'm a bit confused by that. Any help will be huge, i've been stucked with this task for months.

  1. you're right, you must return envelope and headers and call super().apply(envelope, headers) class for the signature. I edited the example.
  2. I'm not sure about files, i don't know enough about certificates, but if you use SoapUI, when you load the JKS file, must request the password, if not, i don't know, sorry.
conradogarciaberrotaran commented 2 years ago

@davisfelipe thank you very much, i'll keep trying!