Receive HL7 via HTTP(s)

[Channel File]

Listening on an HTTP port is a security-elevated operation. This means when configuring the HTTP sender device, you should run the Connexion UI on the same machine as the service, and run the UI as administrator.

The HTTP listener device can act as a web service which can receive any type of message. In this example, we will create a channel which receives HL7 messages via a TLS-enabled endpoint.

The first step is to create a channel which contains the HTTP Listener device (and a downstream queue).

In the HTTP Listener configuration, select the port which your service will listen on. If you have multiple network interfaces and only wish to listen on a specific one, select the Specific Interface option and enter the IP of the desired interface. In this sample, we’ll listen on port 8485.

Since we’ll be receiving PHI, we must ensure our data stream is encrypted. We’ll employ SSL (TLS) and certificate exchange to enable an encrypted tunnel between the sender and Connexion. Check the Enable SSL checkbox and then click the Create Self-Signed Certificate button. This will generate a self-signed certificate and install it into the operating system certificate store. In production systems, you will be using 3rd-party purchased certificates (or ones generated by your security staff). In this case you should use the Installed (Subject Name) drop-down list to select the certificate (it must be installed in the Local Computer\Personal store).

When running a Connexion cluster, both active and passive nodes must have all certificates installed and port binding commands run.

Save your channel. At this point we must manually associate the Connexion service account with the port on which our service will listen. Navigate to the Port Binding Commands section and click the Run All Commands link. This link will run each command which is listed within the Port Binding Commands section. These commands are used to associate Connexion with specific ports and certificates, allowing traffic to be routed to your channel. If you change any of the following settings, you will need to re-run these commands:

  • Listening interface

  • Port

  • SSL enabled state

  • SSL certificate

  • Client certificate validation

A dialog with the command result will be displayed. If any of your commands are not successful, you can use the [Copy] command and run each command individually from an elevated command prompt (and view failure messages).

Start your channel. We should now be able to send any message data by POSTing data to https://127.0.01:8485. You can test sending some messages by using the free Postman tool. Since we are using a self-signed certificate, we will need to disable certificate validation within Postman.

You may need to disable (or update) your firewall in order to receive traffic on port 8485. In this example, a temporary exception was added to Windows Firewall.

This tutorial is about receiving HL7, so let’s try sending some HL7 from Postman. Copy a sample HL7 message into the Postman value field and post the message.

Great! But this service accepts anything, and we want it to only accept valid HL7. This will require us to enter some custom logic in the Custom Actions tab.

The following code was added to the AfterMessageParsed(…) callback:

// use the HL7Message.Create method to parse the sent payload var hl7 = HL7Message.Create(args.ParsedContent); if (hl7.Errors.Any()) { // if there are any errors, throw a descriptive exception back to the sender args.Exception = new Exception($"Invalid HL7: {hl7.Errors.Stringify()}"); throw args.Exception; }

For our scenario, we want to ensure the incoming payload is valid HL7. We use the HL7Message.Create() method to parse the incoming payload and provide any parse errors. If there are any parse errors, we throw a new exception with a descriptive message. This will return a 500 status code along with the error back to the sender, effectively rejecting the message.

We could also update the code to the following to alert us when we receive an invalid payload. This might be useful to enable/disable when a customer is unsuccessfully attempting to send data.

public override void AfterMessageParsed(MessageReceivedEventArgs args) { // use the HL7Message.Create method to parse the sent payload var hl7 = HL7Message.Create(args.ParsedContent); if (hl7.Errors.Any()) { var errorText = $"Invalid HL7: {hl7.Errors.Stringify()}"; var sender = args.HttpContext.Request.RemoteEndPoint.Address; var payload = args.ParsedContent.Truncate(5000); // log an event that someone tried to send malformed HL7 MessageChannel.Logger.Write(EventSeverity.Warning, $"Received invalid payload from {sender}: {payload}"); // if there are any errors, throw a descriptive exception back to the sender args.Exception = new Exception(errorText); throw args.Exception; } }

Now we are able to accept only valid HL7, returning a 500 status code response to the sender if they send an invalid payload.

At this point are accepting valid HL7 from any sender. Typically, we would only accept HL7 from a specific sender (or set of senders). In order to restrict access to specific senders, we can use client certificates. This feature requires senders to include a client certificate as part of the SSL handshake. You can accept or reject any client certificate at any point, effectively revoking access to your service.

Stop your channel, then enable the Validate Client Certificate option followed by re-running the Run All Commands link.

We now need to create a list of client certificates that we will accept. There are two methods to do this:

  • [Create New] - Create a self-signed certificate and export it to a file. Supply this certificate file to the sender.

  • [Import] - The sender already has a certificate and they have supplied it to you (public key only).

In our example, we will use the [Import] option to accept an existing certificate.

Note that if we try and re-send the previous HL7 from Postman, it will now be rejected.

If we add the same certificate we imported in the previous step into postman, then our payload will now be accepted.

To summarize, we are now accepting (only) valid HL7, over an encrypted SSL/TLS tunnel from (only) senders which provide a specific certificate.

We recommend you use a distinct certificate per client. This way you can reject connections from a specific sender without affecting any other senders. You can also use this information to identify each sender and add related metadata. For example, we can add a description to each certificate (perhaps a customer ID) and then write that into the processing history of each received message.

This is the code added to the AfterMessageParsed(…) method:

// add the sender's certificate description in the processing history if(args.ClientCertificate != null) { var customerId = args.ClientCertificateDescription; args.MessageContext.WriteEvent(EventSeverity.Info, $"Customer ID {customerId}"); }