Announcement

Collapse
No announcement yet.

Web Service sender and WSSE

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Web Service sender and WSSE

    We need to digitally sign a timestamp within a SOAP message. Is this doable from within Mirth? We have the SSH extension but I don't know whether it handles this.

    Thanks.

    Here's an example message we've been provided; presumably it is the Signature tag that we'll need to generate based on the message's timestamp:
    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:urn="urn:cdc:iisb:2011">
    <soap:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <ds:Signature Id="SIG-D8234953C823AFAE2415536312716865" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-excc14n#">
    <ec:InclusiveNamespaces PrefixList="soap urn" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    </ds:CanonicalizationMethod>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsasha1"/>
    <ds:Reference URI="#TS-D8234953C823AFAE2415536312715641">
    <ds:Transforms>
    <ds:Transform Algorithm="http://www.w3.org/2001/10/xmlexc-c14n#">
    <ec:InclusiveNamespaces PrefixList="wsse soap urn" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    </ds:Transform>
    </ds:Transforms>
    <dsigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <dsigestValue>Content Redacted
    </dsigestValue>
    </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>Content Redacted</ds:SignatureValue>
    <ds:KeyInfo Id="KI-D8234953C823AFAE2415536312716723">
    <wsse:SecurityTokenReference wsu:Id="STRD8234953C823AFAE2415536312716744">
    <wsse:KeyIdentifier EncodingType="http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
    Content Redacted
    </wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
    </ds:KeyInfo>
    </ds:Signature>
    <wsu:Timestamp wsu:Id="TS-D8234953C823AFAE2415536312715641">
    <wsu:Created>2019-03-26T20:14:31Z</wsu:Created>
    <wsu:Expires>2019-03-26T20:15:01Z</wsu:Expires>
    </wsu:Timestamp>
    </wsse:Security>
    </soap:Header>
    <soap:Body>
    <urn:submitSingleMessage>
    <urn:username>Content Redacted – User name provided by DOH</urn:username>
    <urnassword>Content Redacted – Password provided by DOH</urnassword>
    <urn:facilityID>Content Redacted – Facility ID provided by OHP</urn:facilityID>
    <urn:hl7Message>Content Redacted – Message content information available DOH
    </urn:hl7Message>
    </urn:submitSingleMessage>
    </soap:Body>
    </soap:Envelope

    Thanks.

  • #2
    It's likely doable. Most things are.

    I assume you meant the SSL (not SSH) extension, and as far as I know that is only for setting up encrypted tunnels, not for digital signatures.

    I'm afraid I don't know enough about your requirements to give you a definite answer.

    Comment


    • #3
      Yes, SSL extension. Thank you so much. Is anyone else able to offer a definite answer?

      Comment


      • #4
        You don't have the requirements of what you're trying to do?

        Comment


        • #5
          The requirement is to apply a digital signature to fields including the timestamp, as described in WSSE, and include it in the SOAP message.

          As an aside, when you cannot actually be helpful, there is absolutely no need to post.

          Comment


          • #6
            Hi mitch_nchin

            Did you find a solution to sign a timestamp ?

            I have the same problem, add a signed timestamp in SOAP WSS request.

            Thanks for help

            Comment


            • #7
              Just an FYI we did add this ability with a new commercial extension in 3.6, the Interoperability Connector Suite. The NHIN-compliant assertion and timestamp are both automatically signed, and it integrates with the SSL Manager so you can choose which local cert/keypair you want to sign with.

              Otherwise, I would look into a third-party library like CryptoJS. I think you should be able to create signatures and set them in the SOAP header with that.
              Step 1: JAVA CACHE...DID YOU CLEAR ...wait, ding dong the witch is dead?

              Nicholas Rupley
              Work: 949-237-6069
              Always include what Mirth Connect version you're working with. Also include (if applicable) the code you're using and full stacktraces for errors (use CODE tags). Posting your entire channel is helpful as well; make sure to scrub any PHI/passwords first.


              - How do I foo?
              - You just bar.

              Comment


              • #8
                Hi folks,

                I’m not sure if you found a solution that works for you yet, but you should be able to implement the functionality you’re describing here using the Java XML-DSig API, which is available pretty much out of the box with commercial and open source java implementations (and accessible via Mirth Connect). That message envelop you initially included looks strikingly similar to the requirements defined by WAIIS/OneHealthPort, which I think I ended up implementing something like:

                Code:
                //////////////////////////////////////////////////////////////////////////////////
                // Generate our dynamic message values
                //
                var timestampId = UUIDGenerator.getUUID();
                var createdTimestamp = new Date().toISOString();
                var expiresTimestamp = new Date((new Date()).getTime() + 1000*10).toISOString();
                var hl7Message = xmlToHL7(msg);
                
                var soapEnvelope = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:urn=\"urn:cdc:iisb:2011\">" +
                					"<soap:Header>" +
                						"<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
                							"<wsu:Timestamp wsu:Id=\"" + timestampId + "\">" +
                								"<wsu:Created>" + createdTimestamp + "</wsu:Created>" +
                								"<wsu:Expires>" + expiresTimestamp + "</wsu:Expires>" +
                							"</wsu:Timestamp>" +
                						"</wsse:Security>" +
                					"</soap:Header>" +
                					"<soap:Body>" +
                						"<urn:submitSingleMessage>" +
                							"<urn:username>username</urn:username>" +
                							"<urn:password>password</urn:password>" +
                							"<urn:facilityID>facility</urn:facilityID>" +
                							"<urn:hl7Message><![CDATA[" + hl7Message +"]]></urn:hl7Message>" +
                						"</urn:submitSingleMessage>" +
                					"</soap:Body>" +
                				"</soap:Envelope>";
                var soapString = new java.lang.String(soapEnvelope);
                
                ////////////////////////////////////////////////////////////////////////////////////
                // Build our XML DOM for signature
                //
                var documentBuilderFactory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
                documentBuilderFactory.setNamespaceAware(true);
                var document = documentBuilderFactory.newDocumentBuilder().parse(new java.io.ByteArrayInputStream(soapString.getBytes("utf-8")));
                
                ////////////////////////////////////////////////////////////////////////////////////
                // Configure Digital Signature utilities for required crypto operations
                //
                var xmlDsigFactory = javax.xml.crypto.dsig.XMLSignatureFactory.getInstance("DOM");
                var parameterSpec = new javax.xml.crypto.dsig.spec.ExcC14NParameterSpec();
                
                var reference = xmlDsigFactory.newReference
                (
                	"#" + timestampId,
                	xmlDsigFactory.newDigestMethod(javax.xml.crypto.dsig.DigestMethod.SHA1, null),
                	java.util.Collections.singletonList(xmlDsigFactory.newTransform("http://www.w3.org/2001/10/xml-exc-c14n#", parameterSpec)),
                	null, //type
                	null //id
                )
                
                var signedInfo = xmlDsigFactory.newSignedInfo
                (
                	xmlDsigFactory.newCanonicalizationMethod
                	(
                		javax.xml.crypto.dsig.CanonicalizationMethod.EXCLUSIVE,
                		parameterSpec	
                	),
                	xmlDsigFactory.newSignatureMethod(javax.xml.crypto.dsig.SignatureMethod.RSA_SHA1, null),
                	java.util.Collections.singletonList(reference)
                )
                
                //////////////////////////////////////////////////////
                // Fetch our certificate and key
                //
                var certificate;
                
                try 
                {
                	var inputStream = new java.io.FileInputStream(“/path/to/your/cert”);
                	var certificateFactory = java.security.cert.CertificateFactory.getInstance("X.509");
                	certificate = certificateFactory.generateCertificate(inputStream);
                } 
                finally 
                {
                	if (inputStream != null)
                		inputStream.close();
                }
                
                var privateKey;
                
                var keyFactory = java.security.KeyFactory.getInstance("RSA");
                var keySpec = new java.security.spec.PKCS8EncodedKeySpec(java.nio.file.Files.readAllBytes(new java.io.File(“/path/to/your/pkcs8”).toPath()));
                privateKey = keyFactory.generatePrivate(keySpec);
                
                ////////////////////////////////////////////////////////
                // Generate the KeyInfo for our signature
                //
                var keyInfoFactory = xmlDsigFactory.getKeyInfoFactory();
                var x509Content = new java.util.ArrayList();
                x509Content.add(certificate);
                var x509Data = keyInfoFactory.newX509Data(x509Content);
                var keyInfo = keyInfoFactory.newKeyInfo(java.util.Collections.singletonList(x509Data));
                
                ////////////////////////////////////////////////////////
                // Sign the document (timestamp element)
                //
                var timestampElement = document.getElementsByTagNameNS("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Timestamp").item(0);
                var securityElement = document.getElementsByTagNameNS("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security").item(0);
                var domSignContext = new javax.xml.crypto.dsig.dom.DOMSignContext(privateKey, securityElement);
                domSignContext.setIdAttributeNS(timestampElement,"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");
                var xmlSignature = xmlDsigFactory.newXMLSignature(signedInfo, keyInfo);
                xmlSignature.sign(domSignContext);
                
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // Define any formatting preferences get the signed document as a string
                //
                var transformerFactory = javax.xml.transform.TransformerFactory.newInstance();
                var transformer = transformerFactory.newTransformer();
                transformer.setOutputProperty(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
                var stringWriter = new java.io.StringWriter();
                transformer.transform(new javax.xml.transform.dom.DOMSource(document), new javax.xml.transform.stream.StreamResult(stringWriter));
                
                channelMap.put("soapMessage", stringWriter.toString());
                Obviously, you would want to adapt the above code to your specific use-case/requirements (transforms, canonicalization methods, keyinfo types, etc.), but it ought to provide some sense of how you could leverage the provided XML-DSig utilities to get it done. The transformer above could potentially operate as a destination transformer, with a source connector that polls files, or gets hl7v2 messages over MLLP, etc. One drawback is that you don't get to leverage the fancy Mirth features that come from WDSL-generated SOAP Envelopes in the destination connector (the example above then puts the message body to the channel map, which then makes it available to an HTTP Sender which is manually configured to invoke the expected SOAP operation). There's an old how-to on the Java dsig API here: https://www.oracle.com/technical-res...ature-api.html

                Fortunately I don't think much has changed in there since 2007...

                Comment


                • #9
                  Just seeing this. THANK YOU skirby!!

                  Comment

                  Working...
                  X