ebXML messaging

ebMS 2.0 exchanges in Python - MessageHeader, Manifest, MIME payloads and per-payload signing and encryption.

ebXML Message Service (ebMS 2.0) predates the WS-* stack and is still the backbone of several national health networks - the NHS Spine in England and the Norwegian Helsenett among them. An ebMS message is a SOAP 1.1 envelope whose header contains an eb:MessageHeader naming the parties, the service and the action, whose body holds an eb:Manifest pointing at the payloads, and whose payloads travel as MIME parts next to the envelope.

In Zato, ebXML runs over the same outgoing SOAP connections as everything else - the difference is a dedicated call, invoke_ebxml, which takes the exchange's addressing details and the payload parts.

Sending a message

# -*- coding: utf-8 -*-

# Zato
from zato.common.soap.ebxml import EbXMLInfo
from zato.common.util.xml_.mime_ import Part
from zato.server.service import Service

class SendPatientRecord(Service):

    name = 'demo.ebxml.send-patient-record'

    def handle(self) -> 'None':

        # Who is talking to whom, about what
        info = EbXMLInfo()
        info.from_party = 'my-organization'
        info.to_party = 'their-organization'
        info.cpa_id = 'cpa-123'
        info.conversation_id = self.cid
        info.service = 'urn:example:records'
        info.action = 'SubmitRecord'

        # The business payload is a MIME part
        part = Part()
        part.content_id = 'payload-1'
        part.content_type = 'application/xml'
        part.data = b'<PatientRecord>...</PatientRecord>'

        # Send and read the acknowledgment
        conn = self.soap['Health Network']
        ack = conn.invoke_ebxml(info, [part])

        self.logger.info('Acknowledged, ref: %s', ack.ref_to_message_id)

The platform builds the eb:MessageHeader with a fresh eb:MessageId and timestamp, adds the eb:Manifest referencing each part, packages everything as a MIME multipart and returns the parsed header of the reply - typically an ebMS acknowledgment whose ref_to_message_id points back at what was sent.

Party identifiers that need a type attribute - the NHS convention of urn:nhs:names:partyType:... values, for instance - use info.from_party_type and info.to_party_type.

Payload signing and encryption

Networks that protect the payloads themselves, rather than the transport alone, sign and encrypt each MIME part - the Norwegian health network profile is the canonical example. Both are switches on the call:

ack = conn.invoke_ebxml(info, [part], sign=True, encrypt=True)

Each payload is signed first, so the signature covers the plaintext, then encrypted for the recipient. The keys and certificates come from the WS-Security definition attached to the connection - the same Signing key, Peer certificate and related fields that the X.509 mode uses.

Mutual TLS

ebMS endpoints commonly authenticate at the transport layer as well - the connection's Client certificate and Client key fields cover that, exactly as they do for any other SOAP connection.

Learn more