This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new a119256dca75 [CAMEL-22000] Expose mTLS headers for camel-mllp (#20587)
a119256dca75 is described below
commit a119256dca7538d0933be17f7df4abd0cba12cef
Author: anders-p-andersson-vgregion-se <[email protected]>
AuthorDate: Thu Jan 1 10:29:06 2026 +0100
[CAMEL-22000] Expose mTLS headers for camel-mllp (#20587)
* [CAMEL-22000] Expose peer certificate values through headers for
camel-mllp
* [CAMEL-22000] - Corrections based on feeback
- MLLP_SSL_CLIENT_CERT_NOT_BEFORE and MLLP_SSL_CLIENT_CERT_NOT_AFTER
supposed to be java.util.Date as camel-netty does it.
- Fixed test case to expect SSLHandshakeException instead of
SocketException.
- Ran mvn clean install -DskipTests to ensure formatting and code
generation doesn't leave modified files behind.
---------
Co-authored-by: Anders Andersson <[email protected]>
---
.../org/apache/camel/catalog/components/mllp.json | 37 ++--
.../org/apache/camel/component/mllp/mllp.json | 37 ++--
.../apache/camel/component/mllp/MllpConstants.java | 11 ++
.../component/mllp/MllpTcpServerConsumer.java | 58 +++++-
.../mllp/MllpMutualTlsConnectionAndHeaderBase.java | 202 +++++++++++++++++++++
...nectionAndHeaderNoClientAuthenticationTest.java | 73 ++++++++
...nAndHeaderRequiresClientAuthenticationTest.java | 68 +++++++
...tionAndHeaderWantsClientAuthenticationTest.java | 83 +++++++++
.../endpoint/dsl/MllpEndpointBuilderFactory.java | 60 ++++++
9 files changed, 592 insertions(+), 37 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mllp.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mllp.json
index 64e17075301f..1791ae834f81 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mllp.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mllp.json
@@ -62,22 +62,27 @@
"headers": {
"CamelMllpLocalAddress": { "index": 0, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "String",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The local TCP Address of the Socket", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_LOCAL_ADDRESS" },
"CamelMllpRemoteAddress": { "index": 1, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "String",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The remote TCP Address of the Socket", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_REMOTE_ADDRESS" },
- "CamelMllpAcknowledgement": { "index": 2, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "byte[]",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The HL7 Acknowledgment received in bytes",
"constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT" },
- "CamelMllpAcknowledgementString": { "index": 3, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 Acknowledgment received,
converted to a String", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_STRING" },
- "CamelMllpAcknowledgementType": { "index": 4, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 acknowledgement type (AA, AE,
AR, etc)", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_TYPE" },
- "CamelMllpSendingApplication": { "index": 5, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-3 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_APPLICATION" },
- "CamelMllpSendingFacility": { "index": 6, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-4 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_FACILITY" },
- "CamelMllpReceivingApplication": { "index": 7, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-5 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_APPLICATION" },
- "CamelMllpReceivingFacility": { "index": 8, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-6 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_FACILITY" },
- "CamelMllpTimestamp": { "index": 9, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-7 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TIMESTAMP" },
- "CamelMllpSecurity": { "index": 10, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-8 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SECURITY" },
- "CamelMllpMessageType": { "index": 11, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_TYPE" },
- "CamelMllpEventType": { "index": 12, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.1 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_EVENT_TYPE" },
- "CamelMllpTriggerEvent": { "index": 13, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.2 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TRIGGER_EVENT" },
- "CamelMllpMessageControlId": { "index": 14, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-10 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_CONTROL" },
- "CamelMllpProcessingId": { "index": 15, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-11 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_PROCESSING_ID" },
- "CamelMllpVersionId": { "index": 16, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-12 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_VERSION_ID" },
- "CamelMllpCharset": { "index": 17, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-18 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_CHARSET" }
+ "CamelMllpSslClientCertSubjectName": { "index": 2, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The SSL client certificate subject
name", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_SUBJECT_NAME"
},
+ "CamelMllpSslClientCertIssuerName": { "index": 3, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The SSL client certificate issuer
name", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_ISSUER_NAME"
},
+ "CamelMllpSslClientCertSerialNo": { "index": 4, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The SSL client certificate serial
number", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_SERIAL_NO"
},
+ "CamelMllpSslClientCertNotBefore": { "index": 5, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "java.util.Date", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The SSL client certificate
not before.", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_NOT_BEFORE"
},
+ "CamelMllpSslClientCertNotAfter": { "index": 6, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "java.util.Date", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The SSL client certificate
not after.", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_NOT_AFTER"
},
+ "CamelMllpAcknowledgement": { "index": 7, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "byte[]",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The HL7 Acknowledgment received in bytes",
"constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT" },
+ "CamelMllpAcknowledgementString": { "index": 8, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 Acknowledgment received,
converted to a String", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_STRING" },
+ "CamelMllpAcknowledgementType": { "index": 9, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 acknowledgement type (AA, AE,
AR, etc)", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_TYPE" },
+ "CamelMllpSendingApplication": { "index": 10, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-3 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_APPLICATION" },
+ "CamelMllpSendingFacility": { "index": 11, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-4 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_FACILITY" },
+ "CamelMllpReceivingApplication": { "index": 12, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-5 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_APPLICATION" },
+ "CamelMllpReceivingFacility": { "index": 13, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-6 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_FACILITY" },
+ "CamelMllpTimestamp": { "index": 14, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-7 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TIMESTAMP" },
+ "CamelMllpSecurity": { "index": 15, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-8 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SECURITY" },
+ "CamelMllpMessageType": { "index": 16, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_TYPE" },
+ "CamelMllpEventType": { "index": 17, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.1 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_EVENT_TYPE" },
+ "CamelMllpTriggerEvent": { "index": 18, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.2 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TRIGGER_EVENT" },
+ "CamelMllpMessageControlId": { "index": 19, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-10 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_CONTROL" },
+ "CamelMllpProcessingId": { "index": 20, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-11 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_PROCESSING_ID" },
+ "CamelMllpVersionId": { "index": 21, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-12 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_VERSION_ID" },
+ "CamelMllpCharset": { "index": 22, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-18 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_CHARSET" }
},
"properties": {
"hostname": { "index": 0, "kind": "path", "displayName": "Hostname",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Hostname or IP for connection for the
TCP connection. The default value is null, which means any local IP address" },
diff --git
a/components/camel-mllp/src/generated/resources/META-INF/org/apache/camel/component/mllp/mllp.json
b/components/camel-mllp/src/generated/resources/META-INF/org/apache/camel/component/mllp/mllp.json
index 64e17075301f..1791ae834f81 100644
---
a/components/camel-mllp/src/generated/resources/META-INF/org/apache/camel/component/mllp/mllp.json
+++
b/components/camel-mllp/src/generated/resources/META-INF/org/apache/camel/component/mllp/mllp.json
@@ -62,22 +62,27 @@
"headers": {
"CamelMllpLocalAddress": { "index": 0, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "String",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The local TCP Address of the Socket", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_LOCAL_ADDRESS" },
"CamelMllpRemoteAddress": { "index": 1, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "String",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The remote TCP Address of the Socket", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_REMOTE_ADDRESS" },
- "CamelMllpAcknowledgement": { "index": 2, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "byte[]",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The HL7 Acknowledgment received in bytes",
"constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT" },
- "CamelMllpAcknowledgementString": { "index": 3, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 Acknowledgment received,
converted to a String", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_STRING" },
- "CamelMllpAcknowledgementType": { "index": 4, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 acknowledgement type (AA, AE,
AR, etc)", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_TYPE" },
- "CamelMllpSendingApplication": { "index": 5, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-3 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_APPLICATION" },
- "CamelMllpSendingFacility": { "index": 6, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-4 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_FACILITY" },
- "CamelMllpReceivingApplication": { "index": 7, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-5 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_APPLICATION" },
- "CamelMllpReceivingFacility": { "index": 8, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-6 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_FACILITY" },
- "CamelMllpTimestamp": { "index": 9, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-7 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TIMESTAMP" },
- "CamelMllpSecurity": { "index": 10, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-8 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SECURITY" },
- "CamelMllpMessageType": { "index": 11, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_TYPE" },
- "CamelMllpEventType": { "index": 12, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.1 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_EVENT_TYPE" },
- "CamelMllpTriggerEvent": { "index": 13, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.2 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TRIGGER_EVENT" },
- "CamelMllpMessageControlId": { "index": 14, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-10 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_CONTROL" },
- "CamelMllpProcessingId": { "index": 15, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-11 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_PROCESSING_ID" },
- "CamelMllpVersionId": { "index": 16, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-12 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_VERSION_ID" },
- "CamelMllpCharset": { "index": 17, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-18 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_CHARSET" }
+ "CamelMllpSslClientCertSubjectName": { "index": 2, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The SSL client certificate subject
name", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_SUBJECT_NAME"
},
+ "CamelMllpSslClientCertIssuerName": { "index": 3, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The SSL client certificate issuer
name", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_ISSUER_NAME"
},
+ "CamelMllpSslClientCertSerialNo": { "index": 4, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The SSL client certificate serial
number", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_SERIAL_NO"
},
+ "CamelMllpSslClientCertNotBefore": { "index": 5, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "java.util.Date", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The SSL client certificate
not before.", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_NOT_BEFORE"
},
+ "CamelMllpSslClientCertNotAfter": { "index": 6, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "java.util.Date", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The SSL client certificate
not after.", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SSL_CLIENT_CERT_NOT_AFTER"
},
+ "CamelMllpAcknowledgement": { "index": 7, "kind": "header", "displayName":
"", "group": "common", "label": "", "required": false, "javaType": "byte[]",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The HL7 Acknowledgment received in bytes",
"constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT" },
+ "CamelMllpAcknowledgementString": { "index": 8, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 Acknowledgment received,
converted to a String", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_STRING" },
+ "CamelMllpAcknowledgementType": { "index": 9, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The HL7 acknowledgement type (AA, AE,
AR, etc)", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_ACKNOWLEDGEMENT_TYPE" },
+ "CamelMllpSendingApplication": { "index": 10, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-3 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_APPLICATION" },
+ "CamelMllpSendingFacility": { "index": 11, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-4 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SENDING_FACILITY" },
+ "CamelMllpReceivingApplication": { "index": 12, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-5 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_APPLICATION" },
+ "CamelMllpReceivingFacility": { "index": 13, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-6 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_RECEIVING_FACILITY" },
+ "CamelMllpTimestamp": { "index": 14, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-7 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TIMESTAMP" },
+ "CamelMllpSecurity": { "index": 15, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-8 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_SECURITY" },
+ "CamelMllpMessageType": { "index": 16, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_TYPE" },
+ "CamelMllpEventType": { "index": 17, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.1 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_EVENT_TYPE" },
+ "CamelMllpTriggerEvent": { "index": 18, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-9.2 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_TRIGGER_EVENT" },
+ "CamelMllpMessageControlId": { "index": 19, "kind": "header",
"displayName": "", "group": "consumer", "label": "consumer", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "MSH-10 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_MESSAGE_CONTROL" },
+ "CamelMllpProcessingId": { "index": 20, "kind": "header", "displayName":
"", "group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-11 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_PROCESSING_ID" },
+ "CamelMllpVersionId": { "index": 21, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-12 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_VERSION_ID" },
+ "CamelMllpCharset": { "index": 22, "kind": "header", "displayName": "",
"group": "consumer", "label": "consumer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "MSH-18 value", "constantName":
"org.apache.camel.component.mllp.MllpConstants#MLLP_CHARSET" }
},
"properties": {
"hostname": { "index": 0, "kind": "path", "displayName": "Hostname",
"group": "common", "label": "", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Hostname or IP for connection for the
TCP connection. The default value is null, which means any local IP address" },
diff --git
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
index 00eede06d2cf..1b084c2ae2b8 100644
---
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
+++
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
@@ -26,6 +26,17 @@ public final class MllpConstants {
public static final String MLLP_LOCAL_ADDRESS = "CamelMllpLocalAddress";
@Metadata(description = "The remote TCP Address of the Socket", javaType =
"String")
public static final String MLLP_REMOTE_ADDRESS = "CamelMllpRemoteAddress";
+ @Metadata(description = "The SSL client certificate subject name", label =
"consumer", javaType = "String")
+ public static final String MLLP_SSL_CLIENT_CERT_SUBJECT_NAME =
"CamelMllpSslClientCertSubjectName";
+ @Metadata(description = "The SSL client certificate issuer name", label =
"consumer", javaType = "String")
+ public static final String MLLP_SSL_CLIENT_CERT_ISSUER_NAME =
"CamelMllpSslClientCertIssuerName";
+ @Metadata(description = "The SSL client certificate serial number", label
= "consumer", javaType = "String")
+ public static final String MLLP_SSL_CLIENT_CERT_SERIAL_NO =
"CamelMllpSslClientCertSerialNo";
+ @Metadata(description = "The SSL client certificate not before.", label =
"consumer", javaType = "java.util.Date")
+ public static final String MLLP_SSL_CLIENT_CERT_NOT_BEFORE =
"CamelMllpSslClientCertNotBefore";
+ @Metadata(description = "The SSL client certificate not after.", label =
"consumer", javaType = "java.util.Date")
+ public static final String MLLP_SSL_CLIENT_CERT_NOT_AFTER =
"CamelMllpSslClientCertNotAfter";
+
@Metadata(description = "The HL7 Acknowledgment received in bytes",
javaType = "byte[]")
public static final String MLLP_ACKNOWLEDGEMENT =
"CamelMllpAcknowledgement";
@Metadata(description = "The HL7 Acknowledgment received, converted to a
String", javaType = "String")
diff --git
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
index 037b8e66be2d..8ab1e9884137 100644
---
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
+++
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
@@ -17,15 +17,15 @@
package org.apache.camel.component.mllp;
import java.io.IOException;
+import java.math.BigInteger;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -35,6 +35,10 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.ExchangePropertyKey;
@@ -255,6 +259,10 @@ public class MllpTcpServerConsumer extends DefaultConsumer
{
Message message = exchange.getIn();
+ if (consumerRunnable.getSocket() instanceof SSLSocket sslSocket) {
+ enrichWithClientCertInformation(sslSocket.getSession(),
message);
+ }
+
if (consumerRunnable.hasLocalAddress()) {
message.setHeader(MllpConstants.MLLP_LOCAL_ADDRESS,
consumerRunnable.getLocalAddress());
}
@@ -305,6 +313,46 @@ public class MllpTcpServerConsumer extends DefaultConsumer
{
}
}
+ /**
+ * Enriches the message with client certificate details such as subject
name, serial number, etc.
+ * <p/>
+ * If the certificate is unverified then the headers is not enriched.
+ *
+ * @param sslSession the SSL session
+ * @param message the message to enrich
+ */
+ protected void enrichWithClientCertInformation(SSLSession sslSession,
Message message) {
+ if (sslSession == null || message == null) {
+ return;
+ }
+
+ try {
+ Certificate[] certificates = sslSession.getPeerCertificates();
+ if (certificates != null && certificates.length > 0) {
+ if (!(certificates[0] instanceof X509Certificate cert)) {
+ return;
+ }
+
+ Principal subject = cert.getSubjectX500Principal();
+ if (subject != null) {
+
message.setHeader(MllpConstants.MLLP_SSL_CLIENT_CERT_SUBJECT_NAME,
subject.toString());
+ }
+ Principal issuer = cert.getIssuerX500Principal();
+ if (issuer != null) {
+
message.setHeader(MllpConstants.MLLP_SSL_CLIENT_CERT_ISSUER_NAME,
issuer.toString());
+ }
+ BigInteger serial = cert.getSerialNumber();
+ if (serial != null) {
+
message.setHeader(MllpConstants.MLLP_SSL_CLIENT_CERT_SERIAL_NO,
serial.toString());
+ }
+
message.setHeader(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_BEFORE,
cert.getNotBefore());
+
message.setHeader(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_AFTER,
cert.getNotAfter());
+ }
+ } catch (SSLPeerUnverifiedException e) {
+ // ignore
+ }
+ }
+
void populateHl7DataHeaders(Exchange exchange, Message message, byte[]
hl7MessageBytes) {
if (getConfiguration().isHl7Headers() && exchange != null &&
exchange.getException() == null) {
if (hl7MessageBytes == null || hl7MessageBytes.length < 8) {
diff --git
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderBase.java
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderBase.java
new file mode 100644
index 000000000000..5289311b0c0d
--- /dev/null
+++
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderBase.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mllp;
+
+import java.io.File;
+import java.net.URI;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.jsse.*;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit.rule.mllp.MllpClientResource;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+/**
+ * Does mTLS connection with MLLP and asserts that the headers are properly
set.
+ */
+public class MllpMutualTlsConnectionAndHeaderBase extends CamelTestSupport {
+
+ public static final String WANTS_CLIENT_AUTHENTICATION =
"sslContextParametersWantsClientAuthentication";
+ public static final String REQUIRES_CLIENT_AUTHENTICATION =
"sslContextParametersRequiresClientAuthentication";
+ public static final String NO_CLIENT_AUTHENTICATION =
"sslContextParametersNoClientAuthentication";
+ public static final String WITH_ONLY_TRUSTSTORE =
"sslContextParametersWithOnlyTruststore";
+
+ public static final String TEST_PAYLOAD =
"MSH|^~\\&|CLIENT|TEST|SERVER|ACK|20231118120000||ADT^A01|123456|T|2.6\r" +
+ "EVN|A01|20231118120000\r" +
+
"PID|1|12345|67890||DOE^JOHN||19800101|M|||123 Main
St^^Springfield^IL^62704||(555)555-5555|||||S\r"
+ +
+ "PV1|1|O\r";
+
+ private final String sslContextParamtersUsedInTestRoute;
+
+ protected String expectedCertSubjectName;
+ protected String expectedCertIssuerName;
+ protected String expectedCertSerialNo;
+ protected Date expectedCertNotBefore;
+ protected Date expectedCertNotAfter;
+
+ @RegisterExtension
+ public MllpClientResource mllpClient = new MllpClientResource();
+
+ @EndpointInject("mock://result")
+ protected MockEndpoint result;
+
+ protected MllpMutualTlsConnectionAndHeaderBase(String
sslContextParametersUsedInTestRoute) {
+ this.sslContextParamtersUsedInTestRoute =
sslContextParametersUsedInTestRoute;
+ }
+
+ /**
+ * Creates test route.
+ *
+ * @return RouteBuilder.
+ */
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+
+ public void configure() {
+ fromF(assembleEndpointUri(sslContextParamtersUsedInTestRoute))
+ .log(LoggingLevel.INFO, "mllp-ssl-sender", "Received
Message: ${body}")
+ .to(result);
+ }
+ };
+ }
+
+ /**
+ * Creates an SSLContextParameters object with a key and truststore so
that mTLS is conducted.
+ *
+ * @return SSLContextParamters with both keystore and truststore
paramters.
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ private SSLContextParameters
createSslContextParameters(ClientAuthentication clientAuthentication) throws
Exception {
+ KeyStoreParameters ksp = new KeyStoreParameters();
+
ksp.setResource(this.getClass().getClassLoader().getResource("keystore.jks").toString());
+ ksp.setPassword("password");
+
+ KeyManagersParameters kmp = new KeyManagersParameters();
+ kmp.setKeyPassword("password");
+ kmp.setKeyStore(ksp);
+
+ TrustManagersParameters tmp = new TrustManagersParameters();
+ tmp.setKeyStore(ksp);
+
+ SSLContextParameters sslContextParameters = new SSLContextParameters();
+ sslContextParameters.setKeyManagers(kmp);
+ sslContextParameters.setTrustManagers(tmp);
+
+ extractExpectedSSLCertHeaderValuesFromActualCertificate(ksp);
+
+ sslContextParameters.setServerParameters(new
SSLContextServerParameters());
+
sslContextParameters.getServerParameters().setClientAuthentication(clientAuthentication.name());
+
+ return sslContextParameters;
+ }
+
+ /**
+ * Extracts values from the certificate the client will use to be used for
validation during the tests.
+ *
+ * @param ksp KeyStoreParameters object created from
SSLContextParameters creation. Holds the certificate
+ * information.
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ private void
extractExpectedSSLCertHeaderValuesFromActualCertificate(KeyStoreParameters ksp)
+ throws Exception {
+ File certFile = new File(URI.create(ksp.getResource()));
+ char[] password = ksp.getPassword().toCharArray();
+
+ KeyStore ks = KeyStore.getInstance(certFile, password);
+ X509Certificate certificate = (X509Certificate)
ks.getCertificate("testKey");
+
+ expectedCertIssuerName =
certificate.getIssuerX500Principal().toString();
+ expectedCertSubjectName =
certificate.getSubjectX500Principal().toString();
+ expectedCertSerialNo = certificate.getSerialNumber().toString();
+ expectedCertNotBefore = certificate.getNotBefore();
+ expectedCertNotAfter = certificate.getNotAfter();
+
+ // Be really sure the expected headers aren't null as
expectedHeaderReceived can accept null values,
+ // which could cause false positive test results when the mocks use
these for comparing with the actual values.
+ Assertions.assertNotNull(expectedCertIssuerName);
+ Assertions.assertNotNull(expectedCertSubjectName);
+ Assertions.assertNotNull(expectedCertSerialNo);
+ Assertions.assertNotNull(expectedCertNotBefore);
+ Assertions.assertNotNull(expectedCertNotAfter);
+ }
+
+ /**
+ * Creates a SSLContextParameters object with only a truststore. With
this, the client will only do TLS connection,
+ * it will not send its own certificate for validation.
+ *
+ * @return SSLContextParameter object with only a truststore
configured.
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ private SSLContextParameters
createSslContextParametersWithOnlyTruststore() {
+ KeyStoreParameters ksp = new KeyStoreParameters();
+
ksp.setResource(this.getClass().getClassLoader().getResource("keystore.jks").toString());
+ ksp.setPassword("password");
+
+ TrustManagersParameters tmp = new TrustManagersParameters();
+ tmp.setKeyStore(ksp);
+
+ SSLContextParameters sslContextParameters = new SSLContextParameters();
+ sslContextParameters.setTrustManagers(tmp);
+
+ return sslContextParameters;
+ }
+
+ /**
+ * Registers sslContextParametes, both of them, to camel context.
+ *
+ * @return camelContext.
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ mllpClient.setMllpHost("localhost");
+ mllpClient.setMllpPort(AvailablePortFinder.getNextAvailable());
+
+ DefaultCamelContext context = (DefaultCamelContext)
super.createCamelContext();
+
+ context.setUseMDCLogging(true);
+
context.getCamelContextExtension().setName(this.getClass().getSimpleName());
+
+ context.getRegistry().bind(WANTS_CLIENT_AUTHENTICATION,
+ createSslContextParameters(ClientAuthentication.WANT));
+ context.getRegistry().bind(REQUIRES_CLIENT_AUTHENTICATION,
+ createSslContextParameters(ClientAuthentication.REQUIRE));
+ context.getRegistry().bind(NO_CLIENT_AUTHENTICATION,
+ createSslContextParameters(ClientAuthentication.NONE));
+
+ SSLContextParameters sslContextParametersWithOnlyTruststore =
createSslContextParametersWithOnlyTruststore();
+ context.getRegistry().bind(WITH_ONLY_TRUSTSTORE,
sslContextParametersWithOnlyTruststore);
+ return context;
+ }
+
+ protected String assembleEndpointUri(String sslContextParameters) {
+ return String.format("mllp://%s:%d?sslContextParameters=#%s",
mllpClient.getMllpHost(), mllpClient.getMllpPort(),
+ sslContextParameters);
+ }
+}
diff --git
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderNoClientAuthenticationTest.java
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderNoClientAuthenticationTest.java
new file mode 100644
index 000000000000..a592ce2ce80f
--- /dev/null
+++
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderNoClientAuthenticationTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mllp;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Does mTLS connection with MLLP and asserts that the headers are properly
set.
+ */
+class MllpMutualTlsConnectionAndHeaderNoClientAuthenticationTest extends
MllpMutualTlsConnectionAndHeaderBase {
+ MllpMutualTlsConnectionAndHeaderNoClientAuthenticationTest() {
+ super(NO_CLIENT_AUTHENTICATION);
+ }
+
+ /**
+ * This test does TLS connection without a client sending its certificate,
that is, no mTLS. In this case, none of
+ * the MLLP_SSL_CLIENT_CERT* headers should exist as the client didn't
provide a certificate.
+ *
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ @Test
+ void
testSendingTlsWithNoClientCertificateToMllpConsumerWithNoClientAuthentication()
throws Exception {
+ result.expectedBodiesReceived(TEST_PAYLOAD);
+
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SUBJECT_NAME,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_ISSUER_NAME,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SERIAL_NO,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_BEFORE,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_AFTER,
null);
+
+ template.sendBody(assembleEndpointUri(WITH_ONLY_TRUSTSTORE),
TEST_PAYLOAD);
+ result.assertIsSatisfied();
+ }
+
+ /**
+ * As the server is configured to not do any client authentication, make
sure the MLLP_SSL_CLIENT_CERT* headers are
+ * not present.
+ *
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ @Test
+ void
testCommunicationWithConfiguredClientCertificateWithMllpConsumerWhichDoesNotDoClientAuthentication()
+ throws Exception {
+ result.expectedBodiesReceived(TEST_PAYLOAD);
+
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SUBJECT_NAME,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_ISSUER_NAME,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SERIAL_NO,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_BEFORE,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_AFTER,
null);
+
+ // Any sslContextParameter with a client certificate should be valid
here, but the worst case scenario for this test
+ // should be the context with the server flag for requiring client
authentication. That flag should not matter,
+ // and here is the proof it doesn't.
+ template.sendBody(assembleEndpointUri(REQUIRES_CLIENT_AUTHENTICATION),
TEST_PAYLOAD);
+ result.assertIsSatisfied();
+
+ }
+}
diff --git
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderRequiresClientAuthenticationTest.java
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderRequiresClientAuthenticationTest.java
new file mode 100644
index 000000000000..4a63d482d9c5
--- /dev/null
+++
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderRequiresClientAuthenticationTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mllp;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import org.apache.camel.CamelExecutionException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Does mTLS connection with MLLP and asserts that the headers are properly
set.
+ */
+class MllpMutualTlsConnectionAndHeaderRequiresClientAuthenticationTest extends
MllpMutualTlsConnectionAndHeaderBase {
+ MllpMutualTlsConnectionAndHeaderRequiresClientAuthenticationTest() {
+ super(REQUIRES_CLIENT_AUTHENTICATION);
+ }
+
+ /**
+ * This test does TLS connection without a client sending its certificate,
i.e., no mTLS. As the server is
+ * configured to require client authentication, this should fail.
+ *
+ */
+ @Test
+ void
testSendingTlsWithNoClientCertificateToMllpConsumerWhichRequiresClientAuthentication()
{
+ try {
+ template.sendBody(assembleEndpointUri(WITH_ONLY_TRUSTSTORE),
TEST_PAYLOAD);
+ Assertions.fail("Should not be able to connect without a client
certificate");
+ } catch (CamelExecutionException e) {
+ Assertions.assertInstanceOf(SSLHandshakeException.class,
e.getCause().getCause().getCause());
+ }
+ }
+
+ /**
+ * This test does a proper mTLS connection with MLLP. Here the headers are
asserted to be present and non-null, all
+ * the MLLP_SSL* headers.
+ *
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ @Test
+ void testMutualTlsInOutWithMllpConsumer() throws Exception {
+ result.expectedBodiesReceived(TEST_PAYLOAD);
+
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SUBJECT_NAME,
expectedCertSubjectName);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_ISSUER_NAME,
expectedCertIssuerName);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SERIAL_NO,
expectedCertSerialNo);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_BEFORE,
expectedCertNotBefore);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_AFTER,
expectedCertNotAfter);
+
+ template.sendBody(assembleEndpointUri(REQUIRES_CLIENT_AUTHENTICATION),
TEST_PAYLOAD);
+ result.assertIsSatisfied();
+
+ }
+}
diff --git
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderWantsClientAuthenticationTest.java
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderWantsClientAuthenticationTest.java
new file mode 100644
index 000000000000..472ae5e5413e
--- /dev/null
+++
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpMutualTlsConnectionAndHeaderWantsClientAuthenticationTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mllp;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Does mTLS connection with MLLP and asserts that the headers are properly
set.
+ */
+class MllpMutualTlsConnectionAndHeaderWantsClientAuthenticationTest extends
MllpMutualTlsConnectionAndHeaderBase {
+
+ MllpMutualTlsConnectionAndHeaderWantsClientAuthenticationTest() {
+ super(WANTS_CLIENT_AUTHENTICATION);
+ }
+
+ /**
+ * This test does TLS connection without client sending its certificate
i.e., no mTLS. In this case, none of the
+ * MLLP_SSL_CLIENT_CERT* headers should exist as the client didn't provide
a certificate.
+ *
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ @Test
+ void testTlsNoClientCertificateInOutWithMllpConsumer() throws Exception {
+ result.expectedBodiesReceived(TEST_PAYLOAD);
+
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SUBJECT_NAME,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_ISSUER_NAME,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SERIAL_NO,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_BEFORE,
null);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_AFTER,
null);
+
+ String endpointUri =
String.format("mllp://%s:%d?sslContextParameters=#sslContextParametersWithOnlyTruststore",
+ mllpClient.getMllpHost(), mllpClient.getMllpPort());
+ template.sendBody(endpointUri, TEST_PAYLOAD);
+ result.assertIsSatisfied();
+
+ }
+
+ /**
+ * This test does a proper mTLS connection with MLLP. Here the headers are
asserted to be present and non-null, all
+ * MLLP_SSL* headers.
+ *
+ * @throws Exception if anything goes wrong and then should fail the test.
+ */
+ @Test
+ void testMutalTlsInOutWithMllpConsumer() throws Exception {
+ result.expectedBodiesReceived(TEST_PAYLOAD);
+
+ // Be really sure the expected headers aren't null as
expectedHeaderReceived can accept null values,
+ // which could create false positive test results.
+ Assertions.assertNotNull(expectedCertIssuerName);
+ Assertions.assertNotNull(expectedCertSubjectName);
+ Assertions.assertNotNull(expectedCertNotBefore);
+ Assertions.assertNotNull(expectedCertNotAfter);
+ Assertions.assertNotNull(expectedCertSerialNo);
+
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SUBJECT_NAME,
expectedCertSubjectName);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_ISSUER_NAME,
expectedCertIssuerName);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_SERIAL_NO,
expectedCertSerialNo);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_BEFORE,
expectedCertNotBefore);
+
result.expectedHeaderReceived(MllpConstants.MLLP_SSL_CLIENT_CERT_NOT_AFTER,
expectedCertNotAfter);
+
+ String endpointUri =
String.format("mllp://%s:%d?sslContextParameters=#sslContextParametersWantsClientAuthentication",
+ mllpClient.getMllpHost(), mllpClient.getMllpPort());
+ template.sendBody(endpointUri, TEST_PAYLOAD);
+ result.assertIsSatisfied();
+ }
+}
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MllpEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MllpEndpointBuilderFactory.java
index e2170af38eef..8268dcf65514 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MllpEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MllpEndpointBuilderFactory.java
@@ -2096,6 +2096,66 @@ public interface MllpEndpointBuilderFactory {
public String mllpRemoteAddress() {
return "CamelMllpRemoteAddress";
}
+ /**
+ * The SSL client certificate subject name.
+ *
+ * The option is a: {@code String} type.
+ *
+ * Group: consumer
+ *
+ * @return the name of the header {@code MllpSslClientCertSubjectName}.
+ */
+ public String mllpSslClientCertSubjectName() {
+ return "CamelMllpSslClientCertSubjectName";
+ }
+ /**
+ * The SSL client certificate issuer name.
+ *
+ * The option is a: {@code String} type.
+ *
+ * Group: consumer
+ *
+ * @return the name of the header {@code MllpSslClientCertIssuerName}.
+ */
+ public String mllpSslClientCertIssuerName() {
+ return "CamelMllpSslClientCertIssuerName";
+ }
+ /**
+ * The SSL client certificate serial number.
+ *
+ * The option is a: {@code String} type.
+ *
+ * Group: consumer
+ *
+ * @return the name of the header {@code MllpSslClientCertSerialNo}.
+ */
+ public String mllpSslClientCertSerialNo() {
+ return "CamelMllpSslClientCertSerialNo";
+ }
+ /**
+ * The SSL client certificate not before.
+ *
+ * The option is a: {@code java.util.Date} type.
+ *
+ * Group: consumer
+ *
+ * @return the name of the header {@code MllpSslClientCertNotBefore}.
+ */
+ public String mllpSslClientCertNotBefore() {
+ return "CamelMllpSslClientCertNotBefore";
+ }
+ /**
+ * The SSL client certificate not after.
+ *
+ * The option is a: {@code java.util.Date} type.
+ *
+ * Group: consumer
+ *
+ * @return the name of the header {@code MllpSslClientCertNotAfter}.
+ */
+ public String mllpSslClientCertNotAfter() {
+ return "CamelMllpSslClientCertNotAfter";
+ }
/**
* The HL7 Acknowledgment received in bytes.
*