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 e24f5f28ed8e CAMEL-25604, CAMEL-25605: camel-mllp, camel-mina - verify
the host name of the server over TLS (#27770)
e24f5f28ed8e is described below
commit e24f5f28ed8ee1477c4d8602de31d0b9b3999dc6
Author: Andrea Cosentino <[email protected]>
AuthorDate: Wed Oct 14 21:20:16 2026 +0200
CAMEL-25604, CAMEL-25605: camel-mllp, camel-mina - verify the host name of
the server over TLS (#27770)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../org/apache/camel/catalog/components/mina.json | 8 +-
.../org/apache/camel/catalog/components/mllp.json | 12 +-
.../apache/camel/catalog/docs/mina-component.adoc | 16 ++
.../apache/camel/catalog/docs/mllp-component.adoc | 11 ++
.../component/mina/MinaComponentConfigurer.java | 6 +
.../component/mina/MinaEndpointConfigurer.java | 6 +
.../component/mina/MinaEndpointUriFactory.java | 3 +-
.../org/apache/camel/component/mina/mina.json | 8 +-
.../camel-mina/src/main/docs/mina-component.adoc | 16 ++
.../camel/component/mina/MinaClientSslFilter.java | 53 ++++++
.../camel/component/mina/MinaConfiguration.java | 15 ++
.../apache/camel/component/mina/MinaConsumer.java | 5 +-
.../apache/camel/component/mina/MinaProducer.java | 5 +-
.../component/mina/MinaClientSslFilterTest.java | 190 +++++++++++++++++++++
...lContextParametersHostnameVerificationTest.java | 90 ++++++++++
.../component/mllp/MllpComponentConfigurer.java | 6 +
.../component/mllp/MllpEndpointConfigurer.java | 6 +
.../component/mllp/MllpEndpointUriFactory.java | 3 +-
.../org/apache/camel/component/mllp/mllp.json | 12 +-
.../camel-mllp/src/main/docs/mllp-component.adoc | 11 ++
.../camel/component/mllp/MllpConfiguration.java | 21 ++-
.../apache/camel/component/mllp/MllpEndpoint.java | 8 +
.../component/mllp/MllpTcpClientProducer.java | 8 +
...pTcpClientProducerHostnameVerificationTest.java | 133 +++++++++++++++
.../camel-mllp/src/test/resources/keystore.jks | Bin 2762 -> 2778 bytes
.../java/org/apache/camel/util/SecurityUtils.java | 2 +
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 28 +++
.../component/dsl/MinaComponentBuilderFactory.java | 21 +++
.../component/dsl/MllpComponentBuilderFactory.java | 21 +++
.../endpoint/dsl/MinaEndpointBuilderFactory.java | 108 ++++++++++++
.../endpoint/dsl/MllpEndpointBuilderFactory.java | 36 ++++
31 files changed, 845 insertions(+), 23 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mina.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mina.json
index f730336c73a9..52573c005b39 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mina.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mina.json
@@ -51,8 +51,9 @@
"objectCodecPattern": { "index": 24, "kind": "property", "displayName":
"Object Codec Pattern", "group": "codec", "label": "codec", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:serialization",
"configurationClass": "org.apache.camel.component.mina.MinaConfiguration",
"configurationField": "configuration", "description": "Accept the wildcard
specified classes for Object deserializat [...]
"textline": { "index": 25, "kind": "property", "displayName": "Textline",
"group": "codec", "label": "codec", "required": false, "type": "boolean",
"javaType": "boolean", "deprecated": false, "autowired": false, "secret":
false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used for TCP. If no codec is specified,
you can use this flag to indicate a text line based codec; if [...]
"textlineDelimiter": { "index": 26, "kind": "property", "displayName":
"Textline Delimiter", "group": "codec", "label": "codec", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.mina.MinaTextLineDelimiter", "enum": [ "DEFAULT",
"AUTO", "UNIX", "WINDOWS", "MAC" ], "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used [...]
- "sslContextParameters": { "index": 27, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." },
- "useGlobalSslContextParameters": { "index": 28, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." }
+ "hostnameVerification": { "index": 27, "kind": "property", "displayName":
"Hostname Verification", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Whether to check that [...]
+ "sslContextParameters": { "index": 28, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." },
+ "useGlobalSslContextParameters": { "index": 29, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." }
},
"headers": {
"CamelMinaCloseSessionWhenComplete": { "index": 0, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Indicates whether the session should be
closed after complete", "constantName":
"org.apache.camel.component.mina.MinaConstants#MINA_CLOSE_SESSION_WHEN_COMPLETE"
},
@@ -91,6 +92,7 @@
"objectCodecPattern": { "index": 27, "kind": "parameter", "displayName":
"Object Codec Pattern", "group": "codec", "label": "codec", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:serialization",
"configurationClass": "org.apache.camel.component.mina.MinaConfiguration",
"configurationField": "configuration", "description": "Accept the wildcard
specified classes for Object deserializa [...]
"textline": { "index": 28, "kind": "parameter", "displayName": "Textline",
"group": "codec", "label": "codec", "required": false, "type": "boolean",
"javaType": "boolean", "deprecated": false, "autowired": false, "secret":
false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used for TCP. If no codec is specified,
you can use this flag to indicate a text line based codec; i [...]
"textlineDelimiter": { "index": 29, "kind": "parameter", "displayName":
"Textline Delimiter", "group": "codec", "label": "codec", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.mina.MinaTextLineDelimiter", "enum": [ "DEFAULT",
"AUTO", "UNIX", "WINDOWS", "MAC" ], "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used [...]
- "sslContextParameters": { "index": 30, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." }
+ "hostnameVerification": { "index": 30, "kind": "parameter", "displayName":
"Hostname Verification", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Whether to check that [...]
+ "sslContextParameters": { "index": 31, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." }
}
}
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 b6b4035441c1..d3e2f7e8d80b 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
@@ -55,9 +55,10 @@
"receiveBufferSize": { "index": 28, "kind": "property", "displayName":
"Receive Buffer Size", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_RCVBUF
option to the specified value (in bytes)" },
"receiveTimeout": { "index": 29, "kind": "property", "displayName":
"Receive Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 15000, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The SO_TIMEOUT value (in milliseconds) used
when waiting for the start of an MLLP frame" },
"sendBufferSize": { "index": 30, "kind": "property", "displayName": "Send
Buffer Size", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_SNDBUF
option to the specified value (in bytes)" },
- "sslContextParameters": { "index": 31, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connecti [...]
- "useGlobalSslContextParameters": { "index": 32, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." },
- "idleTimeout": { "index": 33, "kind": "property", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value l [...]
+ "hostnameVerification": { "index": 31, "kind": "property", "displayName":
"Hostname Verification", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Whether the p [...]
+ "sslContextParameters": { "index": 32, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connecti [...]
+ "useGlobalSslContextParameters": { "index": 33, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." },
+ "idleTimeout": { "index": 34, "kind": "property", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value l [...]
},
"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" },
@@ -114,7 +115,8 @@
"receiveBufferSize": { "index": 26, "kind": "parameter", "displayName":
"Receive Buffer Size", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_RCVBUF
option to the specified value (in bytes)" },
"receiveTimeout": { "index": 27, "kind": "parameter", "displayName":
"Receive Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 15000, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The SO_TIMEOUT value (in milliseconds) used
when waiting for the start of an MLLP frame" },
"sendBufferSize": { "index": 28, "kind": "parameter", "displayName": "Send
Buffer Size", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_SNDBUF
option to the specified value (in bytes)" },
- "sslContextParameters": { "index": 29, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connect [...]
- "idleTimeout": { "index": 30, "kind": "parameter", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value [...]
+ "hostnameVerification": { "index": 29, "kind": "parameter", "displayName":
"Hostname Verification", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Whether the [...]
+ "sslContextParameters": { "index": 30, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connect [...]
+ "idleTimeout": { "index": 31, "kind": "parameter", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value [...]
}
}
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mina-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mina-component.adoc
index 1610cd2cd73b..0b4c3786da8b 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mina-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mina-component.adoc
@@ -97,6 +97,22 @@ can also implement some customized filters. Please note that
`codec` and
filters you may define are appended to the end of the filter chain; that
is, after `codec` and `logger`.
+=== Using SSL/TLS
+
+Set `sslContextParameters` on the endpoint, or `useGlobalSslContextParameters`
on the component, to use SSL/TLS with
+the TCP protocol. The trust store, key store, protocols and cipher suites are
configured with the
+xref:manual::camel-configuration-utilities.adoc[Camel JSSE Configuration
Utility].
+
+When Camel opens the connection (the producer, or the consumer with
`clientMode=true`), it checks that the certificate
+of the server matches the `host` of the endpoint, with the same rules as an
HTTPS client. A connection to an IP address
+needs a certificate that lists that address as a subject alternative name. Set
`hostnameVerification=false` to turn
+this check off; the certificate chain is still validated against the trust
store.
+
+MINA keeps a failed handshake in its SSL handler instead of passing the error
on, so a certificate that does not match
+shows up as a timeout of the producer (after `writeTimeout`, or `timeout`
while waiting for a reply) rather than as an
+SSL error. The handshake error is logged at `ERROR` level by
`org.apache.mina.filter.ssl.SslHandler`: when a producer
+times out after you enable SSL, check that log and the subject alternative
names of the certificate.
+
== Examples
=== Example with sync=false
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mllp-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mllp-component.adoc
index 8c1a8db9211e..06ff16298cb8 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mllp-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mllp-component.adoc
@@ -109,3 +109,14 @@ The state of the TCP Socket can be controlled by these
properties on the Camel e
|`CamelMllpCloseConnectionAfterSend` | `Boolean` | If true, the Socket will be
closed immediately after sending data
|`CamelMllpResetConnectionAfterSend` | `Boolean` | If true, the Socket will be
reset immediately after sending any data
|====================================
+
+=== Using TLS
+
+Set `sslContextParameters` on the endpoint, or `useGlobalSslContextParameters`
on the component, to secure the
+connections of the consumer and the producer with TLS. The trust store, key
store, protocols and cipher suites are
+configured with the xref:manual::camel-configuration-utilities.adoc[Camel JSSE
Configuration Utility].
+
+The producer checks that the certificate of the server matches the `hostname`
of the endpoint, with the same rules as
+an HTTPS client. A producer that connects by IP address needs a certificate
that lists that address as a subject
+alternative name, and a producer URI without a host name (such as
`mllp://8888`) cannot pass the check. Set
+`hostnameVerification=false` to turn this check off; the certificate chain is
still validated against the trust store.
diff --git
a/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaComponentConfigurer.java
b/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaComponentConfigurer.java
index 3139756c570b..933b91a12572 100644
---
a/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaComponentConfigurer.java
+++
b/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaComponentConfigurer.java
@@ -51,6 +51,8 @@ public class MinaComponentConfigurer extends
PropertyConfigurerSupport implement
case "encoderMaxLineLength":
getOrCreateConfiguration(target).setEncoderMaxLineLength(property(camelContext,
int.class, value)); return true;
case "encoding":
getOrCreateConfiguration(target).setEncoding(property(camelContext,
java.lang.String.class, value)); return true;
case "filters":
getOrCreateConfiguration(target).setFilters(property(camelContext,
java.util.List.class, value)); return true;
+ case "hostnameverification":
+ case "hostnameVerification":
getOrCreateConfiguration(target).setHostnameVerification(property(camelContext,
boolean.class, value)); return true;
case "lazysessioncreation":
case "lazySessionCreation":
getOrCreateConfiguration(target).setLazySessionCreation(property(camelContext,
boolean.class, value)); return true;
case "lazystartproducer":
@@ -108,6 +110,8 @@ public class MinaComponentConfigurer extends
PropertyConfigurerSupport implement
case "encoderMaxLineLength": return int.class;
case "encoding": return java.lang.String.class;
case "filters": return java.util.List.class;
+ case "hostnameverification":
+ case "hostnameVerification": return boolean.class;
case "lazysessioncreation":
case "lazySessionCreation": return boolean.class;
case "lazystartproducer":
@@ -166,6 +170,8 @@ public class MinaComponentConfigurer extends
PropertyConfigurerSupport implement
case "encoderMaxLineLength": return
getOrCreateConfiguration(target).getEncoderMaxLineLength();
case "encoding": return getOrCreateConfiguration(target).getEncoding();
case "filters": return getOrCreateConfiguration(target).getFilters();
+ case "hostnameverification":
+ case "hostnameVerification": return
getOrCreateConfiguration(target).isHostnameVerification();
case "lazysessioncreation":
case "lazySessionCreation": return
getOrCreateConfiguration(target).isLazySessionCreation();
case "lazystartproducer":
diff --git
a/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointConfigurer.java
b/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointConfigurer.java
index 291ed3295a55..c5eb4307d1c1 100644
---
a/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointConfigurer.java
+++
b/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointConfigurer.java
@@ -45,6 +45,8 @@ public class MinaEndpointConfigurer extends
PropertyConfigurerSupport implements
case "exchangepattern":
case "exchangePattern":
target.setExchangePattern(property(camelContext,
org.apache.camel.ExchangePattern.class, value)); return true;
case "filters":
target.getConfiguration().setFilters(property(camelContext,
java.util.List.class, value)); return true;
+ case "hostnameverification":
+ case "hostnameVerification":
target.getConfiguration().setHostnameVerification(property(camelContext,
boolean.class, value)); return true;
case "lazysessioncreation":
case "lazySessionCreation":
target.getConfiguration().setLazySessionCreation(property(camelContext,
boolean.class, value)); return true;
case "lazystartproducer":
@@ -101,6 +103,8 @@ public class MinaEndpointConfigurer extends
PropertyConfigurerSupport implements
case "exchangepattern":
case "exchangePattern": return org.apache.camel.ExchangePattern.class;
case "filters": return java.util.List.class;
+ case "hostnameverification":
+ case "hostnameVerification": return boolean.class;
case "lazysessioncreation":
case "lazySessionCreation": return boolean.class;
case "lazystartproducer":
@@ -158,6 +162,8 @@ public class MinaEndpointConfigurer extends
PropertyConfigurerSupport implements
case "exchangepattern":
case "exchangePattern": return target.getExchangePattern();
case "filters": return target.getConfiguration().getFilters();
+ case "hostnameverification":
+ case "hostnameVerification": return
target.getConfiguration().isHostnameVerification();
case "lazysessioncreation":
case "lazySessionCreation": return
target.getConfiguration().isLazySessionCreation();
case "lazystartproducer":
diff --git
a/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointUriFactory.java
b/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointUriFactory.java
index db6e0770e621..2b3f17cb9aac 100644
---
a/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointUriFactory.java
+++
b/components/camel-mina/src/generated/java/org/apache/camel/component/mina/MinaEndpointUriFactory.java
@@ -24,7 +24,7 @@ public class MinaEndpointUriFactory extends
org.apache.camel.support.component.E
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(31);
+ Set<String> props = new HashSet<>(32);
props.add("allowDefaultCodec");
props.add("bridgeErrorHandler");
props.add("cachedAddress");
@@ -39,6 +39,7 @@ public class MinaEndpointUriFactory extends
org.apache.camel.support.component.E
props.add("exchangePattern");
props.add("filters");
props.add("host");
+ props.add("hostnameVerification");
props.add("lazySessionCreation");
props.add("lazyStartProducer");
props.add("maximumPoolSize");
diff --git
a/components/camel-mina/src/generated/resources/META-INF/org/apache/camel/component/mina/mina.json
b/components/camel-mina/src/generated/resources/META-INF/org/apache/camel/component/mina/mina.json
index f730336c73a9..52573c005b39 100644
---
a/components/camel-mina/src/generated/resources/META-INF/org/apache/camel/component/mina/mina.json
+++
b/components/camel-mina/src/generated/resources/META-INF/org/apache/camel/component/mina/mina.json
@@ -51,8 +51,9 @@
"objectCodecPattern": { "index": 24, "kind": "property", "displayName":
"Object Codec Pattern", "group": "codec", "label": "codec", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:serialization",
"configurationClass": "org.apache.camel.component.mina.MinaConfiguration",
"configurationField": "configuration", "description": "Accept the wildcard
specified classes for Object deserializat [...]
"textline": { "index": 25, "kind": "property", "displayName": "Textline",
"group": "codec", "label": "codec", "required": false, "type": "boolean",
"javaType": "boolean", "deprecated": false, "autowired": false, "secret":
false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used for TCP. If no codec is specified,
you can use this flag to indicate a text line based codec; if [...]
"textlineDelimiter": { "index": 26, "kind": "property", "displayName":
"Textline Delimiter", "group": "codec", "label": "codec", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.mina.MinaTextLineDelimiter", "enum": [ "DEFAULT",
"AUTO", "UNIX", "WINDOWS", "MAC" ], "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used [...]
- "sslContextParameters": { "index": 27, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." },
- "useGlobalSslContextParameters": { "index": 28, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." }
+ "hostnameVerification": { "index": 27, "kind": "property", "displayName":
"Hostname Verification", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Whether to check that [...]
+ "sslContextParameters": { "index": 28, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." },
+ "useGlobalSslContextParameters": { "index": 29, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." }
},
"headers": {
"CamelMinaCloseSessionWhenComplete": { "index": 0, "kind": "header",
"displayName": "", "group": "common", "label": "", "required": false,
"javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "Indicates whether the session should be
closed after complete", "constantName":
"org.apache.camel.component.mina.MinaConstants#MINA_CLOSE_SESSION_WHEN_COMPLETE"
},
@@ -91,6 +92,7 @@
"objectCodecPattern": { "index": 27, "kind": "parameter", "displayName":
"Object Codec Pattern", "group": "codec", "label": "codec", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:serialization",
"configurationClass": "org.apache.camel.component.mina.MinaConfiguration",
"configurationField": "configuration", "description": "Accept the wildcard
specified classes for Object deserializa [...]
"textline": { "index": 28, "kind": "parameter", "displayName": "Textline",
"group": "codec", "label": "codec", "required": false, "type": "boolean",
"javaType": "boolean", "deprecated": false, "autowired": false, "secret":
false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used for TCP. If no codec is specified,
you can use this flag to indicate a text line based codec; i [...]
"textlineDelimiter": { "index": 29, "kind": "parameter", "displayName":
"Textline Delimiter", "group": "codec", "label": "codec", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.mina.MinaTextLineDelimiter", "enum": [ "DEFAULT",
"AUTO", "UNIX", "WINDOWS", "MAC" ], "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Only used [...]
- "sslContextParameters": { "index": 30, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." }
+ "hostnameVerification": { "index": 30, "kind": "parameter", "displayName":
"Hostname Verification", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "Whether to check that [...]
+ "sslContextParameters": { "index": 31, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mina.MinaConfiguration", "configurationField":
"configuration", "description": "To configure SSL security." }
}
}
diff --git a/components/camel-mina/src/main/docs/mina-component.adoc
b/components/camel-mina/src/main/docs/mina-component.adoc
index 1610cd2cd73b..0b4c3786da8b 100644
--- a/components/camel-mina/src/main/docs/mina-component.adoc
+++ b/components/camel-mina/src/main/docs/mina-component.adoc
@@ -97,6 +97,22 @@ can also implement some customized filters. Please note that
`codec` and
filters you may define are appended to the end of the filter chain; that
is, after `codec` and `logger`.
+=== Using SSL/TLS
+
+Set `sslContextParameters` on the endpoint, or `useGlobalSslContextParameters`
on the component, to use SSL/TLS with
+the TCP protocol. The trust store, key store, protocols and cipher suites are
configured with the
+xref:manual::camel-configuration-utilities.adoc[Camel JSSE Configuration
Utility].
+
+When Camel opens the connection (the producer, or the consumer with
`clientMode=true`), it checks that the certificate
+of the server matches the `host` of the endpoint, with the same rules as an
HTTPS client. A connection to an IP address
+needs a certificate that lists that address as a subject alternative name. Set
`hostnameVerification=false` to turn
+this check off; the certificate chain is still validated against the trust
store.
+
+MINA keeps a failed handshake in its SSL handler instead of passing the error
on, so a certificate that does not match
+shows up as a timeout of the producer (after `writeTimeout`, or `timeout`
while waiting for a reply) rather than as an
+SSL error. The handshake error is logged at `ERROR` level by
`org.apache.mina.filter.ssl.SslHandler`: when a producer
+times out after you enable SSL, check that log and the subject alternative
names of the certificate.
+
== Examples
=== Example with sync=false
diff --git
a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaClientSslFilter.java
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaClientSslFilter.java
new file mode 100644
index 000000000000..c8beb2808666
--- /dev/null
+++
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaClientSslFilter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.mina;
+
+import java.net.InetSocketAddress;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.ssl.SslFilter;
+
+/**
+ * The {@link SslFilter} of a connection that Camel opens as a client, which
checks that the certificate of the server
+ * matches the host Camel connects to, unless hostname verification is
disabled.
+ */
+final class MinaClientSslFilter extends SslFilter {
+
+ private final boolean hostnameVerification;
+
+ MinaClientSslFilter(SSLContext sslContext, boolean hostnameVerification) {
+ super(sslContext);
+ this.hostnameVerification = hostnameVerification;
+ if (hostnameVerification) {
+ setEndpointIdentificationAlgorithm("HTTPS");
+ }
+ }
+
+ @Override
+ protected SSLEngine createEngine(IoSession session, InetSocketAddress
addr) {
+ InetSocketAddress peer = addr;
+ if (hostnameVerification && addr != null) {
+ // check the host as it was given: MINA takes
InetSocketAddress.getHostName(), which looks up a host name
+ // for an IP address
+ peer = InetSocketAddress.createUnresolved(addr.getHostString(),
addr.getPort());
+ }
+ return super.createEngine(session, peer);
+ }
+}
diff --git
a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConfiguration.java
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConfiguration.java
index f94aa6705328..e7fcf225b175 100644
---
a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConfiguration.java
+++
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConfiguration.java
@@ -83,6 +83,8 @@ public class MinaConfiguration implements Cloneable {
private LoggingLevel noReplyLogLevel = LoggingLevel.WARN;
@UriParam(label = "security")
private SSLContextParameters sslContextParameters;
+ @UriParam(label = "security", defaultValue = "true", security =
"insecure:ssl", insecureValue = "false")
+ private boolean hostnameVerification = true;
@UriParam(label = "advanced", defaultValue = "16")
private int maximumPoolSize = 16; // 16 is the default mina setting
@UriParam(label = "advanced", defaultValue = "true")
@@ -386,6 +388,19 @@ public class MinaConfiguration implements Cloneable {
this.sslContextParameters = sslContextParameters;
}
+ public boolean isHostnameVerification() {
+ return hostnameVerification;
+ }
+
+ /**
+ * Whether to check that the certificate of the server matches the host
Camel connects to, when SSL is used by the
+ * producer, or by the consumer in client mode. When disabled, any
certificate accepted by the trust store is
+ * accepted, whatever host it was issued for.
+ */
+ public void setHostnameVerification(boolean hostnameVerification) {
+ this.hostnameVerification = hostnameVerification;
+ }
+
public int getMaximumPoolSize() {
return maximumPoolSize;
}
diff --git
a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java
index a34161d6d11e..2573fe8ec14c 100644
---
a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java
+++
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java
@@ -234,8 +234,9 @@ public class MinaConsumer extends DefaultConsumer {
}
appendIoFiltersToChain(filters, connector.getFilterChain());
if (configuration.getSslContextParameters() != null) {
- SslFilter filter = new SslFilter(
-
configuration.getSslContextParameters().createSSLContext(getEndpoint().getCamelContext()));
+ SslFilter filter = new MinaClientSslFilter(
+
configuration.getSslContextParameters().createSSLContext(getEndpoint().getCamelContext()),
+ configuration.isHostnameVerification());
connector.getFilterChain().addFirst("sslFilter", filter);
}
configureCodecFactory("MinaConsumer", connector, configuration);
diff --git
a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaProducer.java
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaProducer.java
index 8b560615eba7..ac00c7197fef 100644
---
a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaProducer.java
+++
b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaProducer.java
@@ -336,8 +336,9 @@ public class MinaProducer extends DefaultProducer {
}
appendIoFiltersToChain(filters, connector.getFilterChain());
if (configuration.getSslContextParameters() != null) {
- SslFilter filter = new SslFilter(
-
configuration.getSslContextParameters().createSSLContext(getEndpoint().getCamelContext()));
+ SslFilter filter = new MinaClientSslFilter(
+
configuration.getSslContextParameters().createSSLContext(getEndpoint().getCamelContext()),
+ configuration.isHostnameVerification());
connector.getFilterChain().addFirst("sslFilter", filter);
}
configureCodecFactory("MinaProducer", connector);
diff --git
a/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaClientSslFilterTest.java
b/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaClientSslFilterTest.java
new file mode 100644
index 000000000000..1532eb3fdbf0
--- /dev/null
+++
b/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaClientSslFilterTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.mina;
+
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.security.KeyStore;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.mina.core.session.DummySession;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The SSL filter used by the producer and by the consumer in client mode.
+ * <p>
+ * The certificate in jsse/localhost.p12 lists only DNS:localhost as subject
alternative name, so it matches "localhost"
+ * but not "127.0.0.1".
+ */
+class MinaClientSslFilterTest {
+
+ private static final char[] PASSWORD = "changeit".toCharArray();
+
+ @Test
+ void checksTheIpAddressAsGivenWhenHostnameVerificationIsEnabled() throws
Exception {
+ MinaClientSslFilter filter = new
MinaClientSslFilter(defaultSslContext(), true);
+
+ SSLEngine engine = filter.createEngine(new DummySession(), new
InetSocketAddress("127.0.0.1", 9999));
+
+ assertEquals("HTTPS",
engine.getSSLParameters().getEndpointIdentificationAlgorithm());
+ assertEquals("127.0.0.1", engine.getPeerHost());
+ }
+
+ @Test
+ void checksTheHostNameAsGivenWhenHostnameVerificationIsEnabled() throws
Exception {
+ MinaClientSslFilter filter = new
MinaClientSslFilter(defaultSslContext(), true);
+
+ SSLEngine engine = filter.createEngine(new DummySession(), new
InetSocketAddress("localhost", 9999));
+
+ assertEquals("HTTPS",
engine.getSSLParameters().getEndpointIdentificationAlgorithm());
+ assertEquals("localhost", engine.getPeerHost());
+ }
+
+ @Test
+ void doesNotCheckTheHostWhenHostnameVerificationIsDisabled() throws
Exception {
+ MinaClientSslFilter filter = new
MinaClientSslFilter(defaultSslContext(), false);
+
+ SSLEngine engine = filter.createEngine(new DummySession(), new
InetSocketAddress("localhost", 9999));
+
+
assertNull(engine.getSSLParameters().getEndpointIdentificationAlgorithm());
+ }
+
+ @Test
+ void handshakeFailsWhenTheCertificateDoesNotMatchTheHost() throws
Exception {
+ SSLEngine client = clientEngine(true, "127.0.0.1");
+ SSLEngine server = serverEngine();
+
+ SSLHandshakeException e = assertThrows(SSLHandshakeException.class, ()
-> handshake(client, server));
+
+ assertTrue(e.getMessage().contains("127.0.0.1"), e.getMessage());
+ }
+
+ @Test
+ void handshakeSucceedsWhenTheCertificateMatchesTheHost() throws Exception {
+ handshake(clientEngine(true, "localhost"), serverEngine());
+ }
+
+ @Test
+ void
handshakeSucceedsWithAHostTheCertificateDoesNotListWhenHostnameVerificationIsDisabled()
throws Exception {
+ handshake(clientEngine(false, "127.0.0.1"), serverEngine());
+ }
+
+ private static SSLContext defaultSslContext() throws Exception {
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, null, null);
+ return sslContext;
+ }
+
+ private static SSLEngine clientEngine(boolean hostnameVerification, String
host) throws Exception {
+ TrustManagerFactory trustManagerFactory
+ =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(keyStore());
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
+
+ SSLEngine engine = new MinaClientSslFilter(sslContext,
hostnameVerification)
+ .createEngine(new DummySession(), new InetSocketAddress(host,
9999));
+ // a DummySession belongs to an acceptor, so MINA created the engine
in server mode
+ engine.setUseClientMode(true);
+ return engine;
+ }
+
+ private static SSLEngine serverEngine() throws Exception {
+ KeyManagerFactory keyManagerFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(keyStore(), PASSWORD);
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
+
+ SSLEngine engine = sslContext.createSSLEngine();
+ engine.setUseClientMode(false);
+ return engine;
+ }
+
+ private static KeyStore keyStore() throws Exception {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ try (InputStream in =
MinaClientSslFilterTest.class.getClassLoader().getResourceAsStream("jsse/localhost.p12"))
{
+ keyStore.load(in, PASSWORD);
+ }
+ return keyStore;
+ }
+
+ /**
+ * Runs a TLS handshake between the two engines in memory.
+ */
+ private static void handshake(SSLEngine client, SSLEngine server) throws
SSLException {
+ ByteBuffer clientToServer = ByteBuffer.allocate(65536);
+ ByteBuffer serverToClient = ByteBuffer.allocate(65536);
+ client.beginHandshake();
+ server.beginHandshake();
+ for (int i = 0; i < 100 && !(isDone(client) && isDone(server)); i++) {
+ step(client, serverToClient, clientToServer);
+ step(server, clientToServer, serverToClient);
+ }
+ assertTrue(isDone(client) && isDone(server), "The handshake should
complete");
+ }
+
+ private static boolean isDone(SSLEngine engine) {
+ HandshakeStatus status = engine.getHandshakeStatus();
+ return status == HandshakeStatus.FINISHED || status ==
HandshakeStatus.NOT_HANDSHAKING;
+ }
+
+ /**
+ * Reads what the peer sent from {@code in}, then writes what the engine
has to send to {@code out}.
+ */
+ private static void step(SSLEngine engine, ByteBuffer in, ByteBuffer out)
throws SSLException {
+ ByteBuffer application = ByteBuffer.allocate(65536);
+ in.flip();
+ while (in.hasRemaining() && engine.getHandshakeStatus() ==
HandshakeStatus.NEED_UNWRAP) {
+ SSLEngineResult result = engine.unwrap(in, application);
+ runTasks(engine);
+ if (result.getStatus() != SSLEngineResult.Status.OK) {
+ break;
+ }
+ }
+ in.compact();
+ runTasks(engine);
+ while (engine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
+ SSLEngineResult result = engine.wrap(ByteBuffer.allocate(0), out);
+ runTasks(engine);
+ if (result.getStatus() != SSLEngineResult.Status.OK) {
+ break;
+ }
+ }
+ }
+
+ private static void runTasks(SSLEngine engine) {
+ Runnable task = engine.getDelegatedTask();
+ while (task != null) {
+ task.run();
+ task = engine.getDelegatedTask();
+ }
+ }
+}
diff --git
a/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaSslContextParametersHostnameVerificationTest.java
b/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaSslContextParametersHostnameVerificationTest.java
new file mode 100644
index 000000000000..6ff8c8a45b32
--- /dev/null
+++
b/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaSslContextParametersHostnameVerificationTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.mina;
+
+import org.apache.camel.CamelExchangeException;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The producer checks that the certificate of the server matches the host it
connects to.
+ * <p>
+ * The certificate in jsse/localhost.p12 lists only DNS:localhost as subject
alternative name, so it matches "localhost"
+ * but not "127.0.0.1".
+ */
+class MinaSslContextParametersHostnameVerificationTest extends BaseMinaTest {
+
+ @Test
+ void sendsWhenTheCertificateMatchesTheHost() {
+ Object reply = template.requestBody(producerUri("localhost", ""),
"Hello");
+
+ assertEquals("Bye Hello", reply);
+ }
+
+ @Test
+ void failsWhenTheCertificateDoesNotMatchTheHost() throws Exception {
+ MockEndpoint result = getMockEndpoint("mock:result");
+ result.expectedMessageCount(0);
+
+ // MINA keeps the handshake error in its SslHandler, so the producer
fails when the write does not complete:
+ // short timeouts keep the test fast
+ CamelExecutionException e = assertThrows(CamelExecutionException.class,
+ () -> template.requestBody(producerUri("127.0.0.1",
"&writeTimeout=2000&timeout=2000"), "Hello"));
+
+ // connected, but the message was never written
(MinaClientSslFilterTest checks the handshake error itself)
+ CamelExchangeException cause =
assertInstanceOf(CamelExchangeException.class, e.getCause());
+ assertTrue(cause.getMessage().startsWith("Cannot write body"),
cause.getMessage());
+ result.assertIsSatisfied();
+ }
+
+ @Test
+ void
sendsToAHostTheCertificateDoesNotListWhenHostnameVerificationIsDisabled() {
+ Object reply = template.requestBody(producerUri("127.0.0.1",
"&hostnameVerification=false"), "Hello");
+
+ assertEquals("Bye Hello", reply);
+ }
+
+ private String producerUri(String host, String options) {
+ return "mina:tcp://" + host + ":" + getPort() +
"?sync=true&textline=true&sslContextParameters=#sslContextParameters"
+ + options;
+ }
+
+ @Override
+ protected boolean isUseSslContext() {
+ return true;
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ // 0.0.0.0, so the producer can connect with a host name or
with an IP address
+
fromF("mina:tcp://0.0.0.0:%d?sync=true&textline=true&sslContextParameters=#sslContextParameters",
getPort())
+ .to("mock:result")
+ .transform(body().prepend("Bye "));
+ }
+ };
+ }
+}
diff --git
a/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpComponentConfigurer.java
b/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpComponentConfigurer.java
index e65d211696a1..d66351d94ae7 100644
---
a/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpComponentConfigurer.java
+++
b/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpComponentConfigurer.java
@@ -54,6 +54,8 @@ public class MllpComponentConfigurer extends
PropertyConfigurerSupport implement
case "exchangePattern":
getOrCreateConfiguration(target).setExchangePattern(property(camelContext,
org.apache.camel.ExchangePattern.class, value)); return true;
case "hl7headers":
case "hl7Headers":
getOrCreateConfiguration(target).setHl7Headers(property(camelContext,
boolean.class, value)); return true;
+ case "hostnameverification":
+ case "hostnameVerification":
getOrCreateConfiguration(target).setHostnameVerification(property(camelContext,
boolean.class, value)); return true;
case "idletimeout":
case "idleTimeout":
getOrCreateConfiguration(target).setIdleTimeout(property(camelContext,
java.lang.Integer.class, value)); return true;
case "idletimeoutstrategy":
@@ -127,6 +129,8 @@ public class MllpComponentConfigurer extends
PropertyConfigurerSupport implement
case "exchangePattern": return org.apache.camel.ExchangePattern.class;
case "hl7headers":
case "hl7Headers": return boolean.class;
+ case "hostnameverification":
+ case "hostnameVerification": return boolean.class;
case "idletimeout":
case "idleTimeout": return java.lang.Integer.class;
case "idletimeoutstrategy":
@@ -201,6 +205,8 @@ public class MllpComponentConfigurer extends
PropertyConfigurerSupport implement
case "exchangePattern": return
getOrCreateConfiguration(target).getExchangePattern();
case "hl7headers":
case "hl7Headers": return
getOrCreateConfiguration(target).isHl7Headers();
+ case "hostnameverification":
+ case "hostnameVerification": return
getOrCreateConfiguration(target).isHostnameVerification();
case "idletimeout":
case "idleTimeout": return
getOrCreateConfiguration(target).getIdleTimeout();
case "idletimeoutstrategy":
diff --git
a/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointConfigurer.java
b/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointConfigurer.java
index f4a0418d52e9..051a08394832 100644
---
a/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointConfigurer.java
+++
b/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointConfigurer.java
@@ -44,6 +44,8 @@ public class MllpEndpointConfigurer extends
PropertyConfigurerSupport implements
case "exchangePattern":
target.getConfiguration().setExchangePattern(property(camelContext,
org.apache.camel.ExchangePattern.class, value)); return true;
case "hl7headers":
case "hl7Headers":
target.getConfiguration().setHl7Headers(property(camelContext, boolean.class,
value)); return true;
+ case "hostnameverification":
+ case "hostnameVerification":
target.getConfiguration().setHostnameVerification(property(camelContext,
boolean.class, value)); return true;
case "idletimeout":
case "idleTimeout":
target.getConfiguration().setIdleTimeout(property(camelContext,
java.lang.Integer.class, value)); return true;
case "idletimeoutstrategy":
@@ -108,6 +110,8 @@ public class MllpEndpointConfigurer extends
PropertyConfigurerSupport implements
case "exchangePattern": return org.apache.camel.ExchangePattern.class;
case "hl7headers":
case "hl7Headers": return boolean.class;
+ case "hostnameverification":
+ case "hostnameVerification": return boolean.class;
case "idletimeout":
case "idleTimeout": return java.lang.Integer.class;
case "idletimeoutstrategy":
@@ -173,6 +177,8 @@ public class MllpEndpointConfigurer extends
PropertyConfigurerSupport implements
case "exchangePattern": return
target.getConfiguration().getExchangePattern();
case "hl7headers":
case "hl7Headers": return target.getConfiguration().isHl7Headers();
+ case "hostnameverification":
+ case "hostnameVerification": return
target.getConfiguration().isHostnameVerification();
case "idletimeout":
case "idleTimeout": return target.getConfiguration().getIdleTimeout();
case "idletimeoutstrategy":
diff --git
a/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointUriFactory.java
b/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointUriFactory.java
index bed3784d301d..f7db84aeecf7 100644
---
a/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointUriFactory.java
+++
b/components/camel-mllp/src/generated/java/org/apache/camel/component/mllp/MllpEndpointUriFactory.java
@@ -24,7 +24,7 @@ public class MllpEndpointUriFactory extends
org.apache.camel.support.component.E
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(31);
+ Set<String> props = new HashSet<>(32);
props.add("acceptTimeout");
props.add("autoAck");
props.add("backlog");
@@ -37,6 +37,7 @@ public class MllpEndpointUriFactory extends
org.apache.camel.support.component.E
props.add("exchangePattern");
props.add("hl7Headers");
props.add("hostname");
+ props.add("hostnameVerification");
props.add("idleTimeout");
props.add("idleTimeoutStrategy");
props.add("keepAlive");
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 b6b4035441c1..d3e2f7e8d80b 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
@@ -55,9 +55,10 @@
"receiveBufferSize": { "index": 28, "kind": "property", "displayName":
"Receive Buffer Size", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_RCVBUF
option to the specified value (in bytes)" },
"receiveTimeout": { "index": 29, "kind": "property", "displayName":
"Receive Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 15000, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The SO_TIMEOUT value (in milliseconds) used
when waiting for the start of an MLLP frame" },
"sendBufferSize": { "index": 30, "kind": "property", "displayName": "Send
Buffer Size", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_SNDBUF
option to the specified value (in bytes)" },
- "sslContextParameters": { "index": 31, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connecti [...]
- "useGlobalSslContextParameters": { "index": 32, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." },
- "idleTimeout": { "index": 33, "kind": "property", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value l [...]
+ "hostnameVerification": { "index": 31, "kind": "property", "displayName":
"Hostname Verification", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Whether the p [...]
+ "sslContextParameters": { "index": 32, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connecti [...]
+ "useGlobalSslContextParameters": { "index": 33, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." },
+ "idleTimeout": { "index": 34, "kind": "property", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value l [...]
},
"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" },
@@ -114,7 +115,8 @@
"receiveBufferSize": { "index": 26, "kind": "parameter", "displayName":
"Receive Buffer Size", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_RCVBUF
option to the specified value (in bytes)" },
"receiveTimeout": { "index": 27, "kind": "parameter", "displayName":
"Receive Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 15000, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The SO_TIMEOUT value (in milliseconds) used
when waiting for the start of an MLLP frame" },
"sendBufferSize": { "index": 28, "kind": "parameter", "displayName": "Send
Buffer Size", "group": "advanced", "label": "advanced", "required": false,
"type": "integer", "javaType": "java.lang.Integer", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 8192,
"configurationClass": "org.apache.camel.component.mllp.MllpConfiguration",
"configurationField": "configuration", "description": "Sets the SO_SNDBUF
option to the specified value (in bytes)" },
- "sslContextParameters": { "index": 29, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connect [...]
- "idleTimeout": { "index": 30, "kind": "parameter", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value [...]
+ "hostnameVerification": { "index": 29, "kind": "parameter", "displayName":
"Hostname Verification", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:ssl",
"insecureValue": "false", "defaultValue": true, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Whether the [...]
+ "sslContextParameters": { "index": 30, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "Sets the SSLContextParameters for securing TCP
connect [...]
+ "idleTimeout": { "index": 31, "kind": "parameter", "displayName": "Idle
Timeout", "group": "tcp", "label": "advanced,tcp", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.mllp.MllpConfiguration", "configurationField":
"configuration", "description": "The approximate idle time allowed before the
Client TCP Connection will be reset. A null value or a value [...]
}
}
diff --git a/components/camel-mllp/src/main/docs/mllp-component.adoc
b/components/camel-mllp/src/main/docs/mllp-component.adoc
index 8c1a8db9211e..06ff16298cb8 100644
--- a/components/camel-mllp/src/main/docs/mllp-component.adoc
+++ b/components/camel-mllp/src/main/docs/mllp-component.adoc
@@ -109,3 +109,14 @@ The state of the TCP Socket can be controlled by these
properties on the Camel e
|`CamelMllpCloseConnectionAfterSend` | `Boolean` | If true, the Socket will be
closed immediately after sending data
|`CamelMllpResetConnectionAfterSend` | `Boolean` | If true, the Socket will be
reset immediately after sending any data
|====================================
+
+=== Using TLS
+
+Set `sslContextParameters` on the endpoint, or `useGlobalSslContextParameters`
on the component, to secure the
+connections of the consumer and the producer with TLS. The trust store, key
store, protocols and cipher suites are
+configured with the xref:manual::camel-configuration-utilities.adoc[Camel JSSE
Configuration Utility].
+
+The producer checks that the certificate of the server matches the `hostname`
of the endpoint, with the same rules as
+an HTTPS client. A producer that connects by IP address needs a certificate
that lists that address as a subject
+alternative name, and a producer URI without a host name (such as
`mllp://8888`) cannot pass the check. Set
+`hostnameVerification=false` to turn this check off; the certificate chain is
still validated against the trust store.
diff --git
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConfiguration.java
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConfiguration.java
index 820b104145d1..172116b68eba 100644
---
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConfiguration.java
+++
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConfiguration.java
@@ -114,6 +114,9 @@ public class MllpConfiguration implements Cloneable {
@UriParam(label = "security")
private SSLContextParameters sslContextParameters;
+ @UriParam(label = "producer,security", defaultValue = "true", security =
"insecure:ssl", insecureValue = "false")
+ boolean hostnameVerification = true;
+
public MllpConfiguration() {
}
@@ -150,6 +153,7 @@ public class MllpConfiguration implements Cloneable {
target.charsetName = source.charsetName;
target.maxConcurrentConsumers = source.maxConcurrentConsumers;
target.sslContextParameters = source.sslContextParameters;
+ target.hostnameVerification = source.hostnameVerification;
}
}
@@ -586,6 +590,18 @@ public class MllpConfiguration implements Cloneable {
this.sslContextParameters = sslContextParameters;
}
+ public boolean isHostnameVerification() {
+ return hostnameVerification;
+ }
+
+ /**
+ * Whether the producer checks that the certificate of the server matches
the host it connects to, when SSL/TLS is
+ * used. When disabled, any certificate accepted by the trust store is
accepted, whatever host it was issued for.
+ */
+ public void setHostnameVerification(boolean hostnameVerification) {
+ this.hostnameVerification = hostnameVerification;
+ }
+
@Override
public int hashCode() {
return Objects.hash(bridgeErrorHandler,
@@ -613,7 +629,8 @@ public class MllpConfiguration implements Cloneable {
charsetName,
minBufferSize,
maxBufferSize,
- sslContextParameters);
+ sslContextParameters,
+ hostnameVerification);
}
@Override
@@ -644,6 +661,7 @@ public class MllpConfiguration implements Cloneable {
&& idleTimeoutStrategy == rhs.idleTimeoutStrategy
&& minBufferSize == rhs.minBufferSize
&& maxBufferSize == rhs.maxBufferSize
+ && hostnameVerification == rhs.hostnameVerification
&& Objects.equals(backlog, rhs.backlog)
&& Objects.equals(maxConcurrentConsumers,
rhs.maxConcurrentConsumers)
&& Objects.equals(idleTimeout, rhs.idleTimeout)
@@ -685,6 +703,7 @@ public class MllpConfiguration implements Cloneable {
+ ", maxBufferSize=" + maxBufferSize
+ ", charsetName='" + charsetName + '\''
+ ", sslContextParameters=" + sslContextParameters
+ + ", hostnameVerification=" + hostnameVerification
+ '}';
}
}
diff --git
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
index 4bbeb147f130..736baea8551b 100644
---
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
+++
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
@@ -333,6 +333,14 @@ public class MllpEndpoint extends DefaultEndpoint
implements EndpointServiceLoca
public SSLContextParameters getSslContextParameters() {
return configuration.getSslContextParameters();
}
+
+ public void setHostnameVerification(boolean hostnameVerification) {
+ configuration.setHostnameVerification(hostnameVerification);
+ }
+
+ public boolean isHostnameVerification() {
+ return configuration.isHostnameVerification();
+ }
// Utility methods for producers and consumers
public boolean checkBeforeSendProperties(Exchange exchange, Socket socket,
Logger log) {
diff --git
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
index 7f3393a00132..9eb3c2c69c5c 100644
---
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
+++
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
@@ -29,6 +29,8 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.apache.camel.Exchange;
@@ -527,6 +529,12 @@ public class MllpTcpClientProducer extends DefaultProducer
implements Runnable {
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// NOTE: the socket must be closed by the client of this factory
method.
newSocket = sslSocketFactory.createSocket(); // NOSONAR
+ if (getConfiguration().isHostnameVerification() && newSocket
instanceof SSLSocket sslSocket) {
+ // check that the certificate of the server matches the host
we connect to
+ SSLParameters sslParameters = sslSocket.getSSLParameters();
+ sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
+ sslSocket.setSSLParameters(sslParameters);
+ }
} else {
log.debug("Creating plain socket without SSLContextParameters");
// NOTE: the socket must be closed by the client of this factory
method.
diff --git
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerHostnameVerificationTest.java
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerHostnameVerificationTest.java
new file mode 100644
index 000000000000..d70bcce2c1b1
--- /dev/null
+++
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerHostnameVerificationTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.security.cert.CertificateException;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.support.jsse.KeyManagersParameters;
+import org.apache.camel.support.jsse.KeyStoreParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The MLLP producer checks that the certificate of the server matches the
host it connects to.
+ * <p>
+ * The certificate in keystore.jks lists only DNS:localhost as subject
alternative name, so it matches "localhost" but
+ * not "127.0.0.1".
+ */
+class MllpTcpClientProducerHostnameVerificationTest extends CamelTestSupport {
+
+ 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";
+
+ @RegisterExtension
+ AvailablePortFinder.Port port = AvailablePortFinder.find();
+
+ @EndpointInject("mock://result")
+ MockEndpoint result;
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+ context.getRegistry().bind("sslContextParameters",
createSslContextParameters());
+ return context;
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ // no host, so the consumer listens on every address and the
producer can use a name or an IP address
+ fromF("mllp://%d?sslContextParameters=#sslContextParameters",
port.getPort())
+ .to(result);
+ }
+ };
+ }
+
+ @Test
+ void sendsWhenTheCertificateMatchesTheHost() throws Exception {
+ result.expectedBodiesReceived(TEST_PAYLOAD);
+
+ template.sendBody(producerUri("localhost", ""), TEST_PAYLOAD);
+
+ result.assertIsSatisfied();
+ }
+
+ @Test
+ void failsWhenTheCertificateDoesNotMatchTheHost() throws Exception {
+ result.expectedMessageCount(0);
+
+ CamelExecutionException e = assertThrows(CamelExecutionException.class,
+ () -> template.sendBody(producerUri("127.0.0.1", ""),
TEST_PAYLOAD));
+
+ assertNotNull(ObjectHelper.getException(SSLHandshakeException.class,
e), "The TLS handshake should fail");
+ CertificateException rejection =
ObjectHelper.getException(CertificateException.class, e);
+ assertNotNull(rejection, "The certificate of the server should be
rejected");
+ assertTrue(rejection.getMessage().contains("127.0.0.1"),
rejection.getMessage());
+ result.assertIsSatisfied();
+ }
+
+ @Test
+ void
sendsToAHostTheCertificateDoesNotListWhenHostnameVerificationIsDisabled()
throws Exception {
+ result.expectedBodiesReceived(TEST_PAYLOAD);
+
+ template.sendBody(producerUri("127.0.0.1",
"&hostnameVerification=false"), TEST_PAYLOAD);
+
+ result.assertIsSatisfied();
+ }
+
+ private String producerUri(String host, String options) {
+ return
String.format("mllp://%s:%d?sslContextParameters=#sslContextParameters%s",
host, port.getPort(), options);
+ }
+
+ private SSLContextParameters createSslContextParameters() {
+ 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);
+ return sslContextParameters;
+ }
+}
diff --git a/components/camel-mllp/src/test/resources/keystore.jks
b/components/camel-mllp/src/test/resources/keystore.jks
index 49b70def00fa..456e517208c1 100644
Binary files a/components/camel-mllp/src/test/resources/keystore.jks and
b/components/camel-mllp/src/test/resources/keystore.jks differ
diff --git
a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
index f1d220fab87c..fb63bfb301cc 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
@@ -159,6 +159,8 @@ public final class SecurityUtils {
"component:opa",
"component:openfga"));
owners.put("hostnameverification", Set.of(
+ "component:mina",
+ "component:mllp",
"component:netty",
"component:nettyhttp",
"component:smpp",
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 8401ad2ae1d2..3a4a8f50cf7d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -373,6 +373,18 @@ silently can use the `upsert` operation, or handle the
exception, for example wi
The producer also closes the Kudu session of each operation. The sessions
stayed registered with the Kudu client until
the client was closed, one more for every exchange.
+=== camel-mllp - the producer verifies the host name of the server over TLS
+
+When `sslContextParameters` is set (on the endpoint, or with
`useGlobalSslContextParameters` on the component), the
+MLLP producer now checks that the certificate of the server matches the host
it connects to, with the same rules as an
+HTTPS client. Before, it accepted any certificate trusted by the trust store,
whatever host the certificate was issued
+for.
+
+A producer that connects with a host name or an IP address that the
certificate does not list now fails the TLS
+handshake; an IP address must be listed as a subject alternative name of the
certificate, and a producer URI without a
+host name (such as `mllp://8888`) cannot pass the check. Use a certificate
that matches the host of the endpoint, or set
+the new `hostnameVerification` option to `false` to keep the previous
behaviour.
+
=== camel-atom - sortEntries sorts by the updated date and routes the oldest
entry first
With `sortEntries=true` the `atom` consumer sorted the entries of a feed by
their published date and routed them from
@@ -405,6 +417,22 @@ In both cases the objects are no longer kept in the
`inProgressRepository`; befo
the same key) was skipped by all later polls until the endpoint was restarted.
With the `fileName` option, a failed
get still fails the poll.
+=== camel-mina - the host name of the server is verified over SSL
+
+When `sslContextParameters` is set (on the endpoint, or with
`useGlobalSslContextParameters` on the component), the
+producer, and the consumer with `clientMode=true`, now check that the
certificate of the server matches the `host` of
+the endpoint, with the same rules as an HTTPS client. Before, any certificate
trusted by the trust store was accepted,
+whatever host the certificate was issued for.
+
+A connection to a host name or an IP address that the certificate does not
list now fails the SSL handshake; an IP
+address must be listed as a subject alternative name of the certificate. Use a
certificate that matches the host of the
+endpoint, or set the new `hostnameVerification` option to `false` to keep the
previous behaviour.
+
+MINA does not pass a failed handshake on as an error: the producer fails with
a timeout (after `writeTimeout`, or
+`timeout` while waiting for a reply), and the handshake error is logged at
`ERROR` level by
+`org.apache.mina.filter.ssl.SslHandler`. A producer that starts timing out
after the upgrade should be checked for a
+certificate that does not list the host.
+
=== camel-aws2-kinesis - the consumer continues after the last record when a
shard iterator expired
When a cached shard iterator has expired (an iterator is valid for 5 minutes,
so after a route was suspended for
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MinaComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MinaComponentBuilderFactory.java
index 6f41ced85b0c..11c6a2de2d5f 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MinaComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MinaComponentBuilderFactory.java
@@ -566,6 +566,26 @@ public interface MinaComponentBuilderFactory {
return this;
}
+
+ /**
+ * Whether to check that the certificate of the server matches the host
+ * Camel connects to, when SSL is used by the producer, or by the
+ * consumer in client mode. When disabled, any certificate accepted by
+ * the trust store is accepted, whatever host it was issued for.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MinaComponentBuilder hostnameVerification(boolean
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
+
/**
* To configure SSL security.
*
@@ -646,6 +666,7 @@ public interface MinaComponentBuilderFactory {
case "objectCodecPattern":
getOrCreateConfiguration((MinaComponent)
component).setObjectCodecPattern((java.lang.String) value); return true;
case "textline": getOrCreateConfiguration((MinaComponent)
component).setTextline((boolean) value); return true;
case "textlineDelimiter": getOrCreateConfiguration((MinaComponent)
component).setTextlineDelimiter((org.apache.camel.component.mina.MinaTextLineDelimiter)
value); return true;
+ case "hostnameVerification":
getOrCreateConfiguration((MinaComponent)
component).setHostnameVerification((boolean) value); return true;
case "sslContextParameters":
getOrCreateConfiguration((MinaComponent)
component).setSslContextParameters((org.apache.camel.support.jsse.SSLContextParameters)
value); return true;
case "useGlobalSslContextParameters": ((MinaComponent)
component).setUseGlobalSslContextParameters((boolean) value); return true;
default: return false;
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MllpComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MllpComponentBuilderFactory.java
index 9f5ef2ae9155..0bb43a33c97d 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MllpComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/MllpComponentBuilderFactory.java
@@ -630,6 +630,26 @@ public interface MllpComponentBuilderFactory {
return this;
}
+
+ /**
+ * Whether the producer checks that the certificate of the server
+ * matches the host it connects to, when SSL/TLS is used. When
disabled,
+ * any certificate accepted by the trust store is accepted, whatever
+ * host it was issued for.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MllpComponentBuilder hostnameVerification(boolean
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
+
/**
* Sets the SSLContextParameters for securing TCP connections. If set,
* the MLLP component will use SSL/TLS for securing both producer and
@@ -735,6 +755,7 @@ public interface MllpComponentBuilderFactory {
case "receiveBufferSize": getOrCreateConfiguration((MllpComponent)
component).setReceiveBufferSize((java.lang.Integer) value); return true;
case "receiveTimeout": getOrCreateConfiguration((MllpComponent)
component).setReceiveTimeout((int) value); return true;
case "sendBufferSize": getOrCreateConfiguration((MllpComponent)
component).setSendBufferSize((java.lang.Integer) value); return true;
+ case "hostnameVerification":
getOrCreateConfiguration((MllpComponent)
component).setHostnameVerification((boolean) value); return true;
case "sslContextParameters":
getOrCreateConfiguration((MllpComponent)
component).setSslContextParameters((org.apache.camel.support.jsse.SSLContextParameters)
value); return true;
case "useGlobalSslContextParameters": ((MllpComponent)
component).setUseGlobalSslContextParameters((boolean) value); return true;
case "idleTimeout": getOrCreateConfiguration((MllpComponent)
component).setIdleTimeout((java.lang.Integer) value); return true;
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MinaEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MinaEndpointBuilderFactory.java
index 60b596e2dac9..5fa02aa8a6d4 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MinaEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/MinaEndpointBuilderFactory.java
@@ -540,6 +540,42 @@ public interface MinaEndpointBuilderFactory {
doSetProperty("textlineDelimiter", textlineDelimiter);
return this;
}
+ /**
+ * Whether to check that the certificate of the server matches the host
+ * Camel connects to, when SSL is used by the producer, or by the
+ * consumer in client mode. When disabled, any certificate accepted by
+ * the trust store is accepted, whatever host it was issued for.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MinaEndpointConsumerBuilder hostnameVerification(boolean
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
+ /**
+ * Whether to check that the certificate of the server matches the host
+ * Camel connects to, when SSL is used by the producer, or by the
+ * consumer in client mode. When disabled, any certificate accepted by
+ * the trust store is accepted, whatever host it was issued for.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MinaEndpointConsumerBuilder hostnameVerification(String
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
/**
* To configure SSL security.
*
@@ -1312,6 +1348,42 @@ public interface MinaEndpointBuilderFactory {
doSetProperty("textlineDelimiter", textlineDelimiter);
return this;
}
+ /**
+ * Whether to check that the certificate of the server matches the host
+ * Camel connects to, when SSL is used by the producer, or by the
+ * consumer in client mode. When disabled, any certificate accepted by
+ * the trust store is accepted, whatever host it was issued for.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MinaEndpointProducerBuilder hostnameVerification(boolean
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
+ /**
+ * Whether to check that the certificate of the server matches the host
+ * Camel connects to, when SSL is used by the producer, or by the
+ * consumer in client mode. When disabled, any certificate accepted by
+ * the trust store is accepted, whatever host it was issued for.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MinaEndpointProducerBuilder hostnameVerification(String
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
/**
* To configure SSL security.
*
@@ -2044,6 +2116,42 @@ public interface MinaEndpointBuilderFactory {
doSetProperty("textlineDelimiter", textlineDelimiter);
return this;
}
+ /**
+ * Whether to check that the certificate of the server matches the host
+ * Camel connects to, when SSL is used by the producer, or by the
+ * consumer in client mode. When disabled, any certificate accepted by
+ * the trust store is accepted, whatever host it was issued for.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MinaEndpointBuilder hostnameVerification(boolean
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
+ /**
+ * Whether to check that the certificate of the server matches the host
+ * Camel connects to, when SSL is used by the producer, or by the
+ * consumer in client mode. When disabled, any certificate accepted by
+ * the trust store is accepted, whatever host it was issued for.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MinaEndpointBuilder hostnameVerification(String
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
/**
* To configure SSL security.
*
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 a269e3402fcb..6e630e41f0ee 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
@@ -1062,6 +1062,42 @@ public interface MllpEndpointBuilderFactory {
doSetProperty("validatePayload", validatePayload);
return this;
}
+ /**
+ * Whether the producer checks that the certificate of the server
+ * matches the host it connects to, when SSL/TLS is used. When
disabled,
+ * any certificate accepted by the trust store is accepted, whatever
+ * host it was issued for.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MllpEndpointProducerBuilder hostnameVerification(boolean
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
+ /**
+ * Whether the producer checks that the certificate of the server
+ * matches the host it connects to, when SSL/TLS is used. When
disabled,
+ * any certificate accepted by the trust store is accepted, whatever
+ * host it was issued for.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: security
+ *
+ * @param hostnameVerification the value to set
+ * @return the dsl builder
+ */
+ default MllpEndpointProducerBuilder hostnameVerification(String
hostnameVerification) {
+ doSetProperty("hostnameVerification", hostnameVerification);
+ return this;
+ }
/**
* Sets the SSLContextParameters for securing TCP connections. If set,
* the MLLP component will use SSL/TLS for securing both producer and