This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/main by this push:
     new 5626afdfc9 Enforce quarkus.tls transport policy on bridged 
SSLContextParameters
5626afdfc9 is described below

commit 5626afdfc9c4eadcce8dc1928ce68d5e4ca21fbe
Author: James Netherton <[email protected]>
AuthorDate: Mon Sep 7 07:08:04 2026 +0100

    Enforce quarkus.tls transport policy on bridged SSLContextParameters
    
    The conversion to SSLContextParameters carried over only key and trust 
material.
    Quarkus keeps protocols, cipher suites and key exchange groups on the Vert.x
    SSLOptions and never applies them to the SSLContext, so Camel components 
using a
    registered bean negotiated with JVM defaults and nothing warned. Decorate 
the context
    the way SSLContextParameters.createSSLContext does, and copy the policy 
onto the
    parameters.
    
    Warn about the configured options that cannot be carried over and that 
weaken
    verification if the operator assumes otherwise: a certificate revocation 
list, which
    leaves a bridged bean accepting certificates the rest of the application 
rejects, and
    the hostname verification algorithm.
    
    Fixes #9113
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 .../modules/ROOT/pages/migration-guide/3.40.0.adoc |  47 ++++++++
 .../pages/reference/extensions/tls-registry.adoc   |  45 ++++++++
 .../tls-registry/runtime/src/main/doc/usage.adoc   |  43 ++++++++
 .../core/tls/TlsConfigurationConverter.java        | 100 ++++++++++++++++-
 .../quarkus/core/tls/it/TlsRegistryResource.java   |  24 +++++
 .../core/tls/it/TlsRegistryTransportPolicyIT.java  |  23 ++++
 .../tls/it/TlsRegistryTransportPolicyTest.java     | 118 +++++++++++++++++++++
 7 files changed, 397 insertions(+), 3 deletions(-)

diff --git a/docs/modules/ROOT/pages/migration-guide/3.40.0.adoc 
b/docs/modules/ROOT/pages/migration-guide/3.40.0.adoc
index ac95c7f270..e5cd536d82 100644
--- a/docs/modules/ROOT/pages/migration-guide/3.40.0.adoc
+++ b/docs/modules/ROOT/pages/migration-guide/3.40.0.adoc
@@ -49,3 +49,50 @@ The option is now unset by default and has three states:
 Setting the option to `false` therefore now bounds what the native image is 
able to deserialize, at the cost of breaking any component that depends on Java 
serialization. A build that requests the veto while extensions ask for 
serialization logs a warning.
 
 Applications that set the option to `false` while relying on one of the 
extensions above must remove the setting to keep working. Applications that set 
it to `true`, or that never set it, are unaffected.
+
+== TLS Registry extension changes
+
+=== quarkus.tls transport policy is now enforced
+
+Converting a Quarkus TLS configuration to `SSLContextParameters` previously 
carried over only the key and trust material. `quarkus.tls.protocols`, 
`quarkus.tls.cipher-suites` and `quarkus.tls.key-exchange-groups` were dropped, 
so Camel components using a registered bean negotiated with the JVM defaults 
rather than the policy that had been configured for them. Quarkus keeps those 
alongside the Vert.x transport options and never applies them to the 
`SSLContext` itself, so nothing carried t [...]
+
+All three are now applied to every `SSLEngine` and socket factory Camel 
derives from a registered bean.
+
+`quarkus.tls.protocols` defaults to `TLSv1.3`, so a bean that previously 
offered whatever the JVM enabled now offers TLSv1.3 alone, matching every other 
consumer of the same TLS configuration. Where a route talks to an endpoint that 
does not support TLSv1.3, widen the property.
+
+[source,properties]
+----
+quarkus.tls.protocols=TLSv1.3,TLSv1.2
+----
+
+Note that this applies to the whole TLS configuration, not only to Camel. 
Define a named configuration for the endpoint that needs it if the rest of the 
application should stay on TLSv1.3.
+
+[source,properties]
+----
+quarkus.tls.legacy-endpoint.protocols=TLSv1.3,TLSv1.2
+quarkus.tls.legacy-endpoint.trust-store.p12.path=/etc/ssl/truststore.p12
+quarkus.tls.legacy-endpoint.trust-store.p12.password=changeit
+----
+
+=== Unrecognised protocol and cipher suite names now fail
+
+Camel applies a configured list verbatim rather than reducing it to what the 
JVM supports, so a name the JVM does not recognise now fails the creation of 
the SSL context instead of being ignored. Disabled but known names, such as 
`SSLv3`, are still accepted.
+
+This affects a configuration that sets `quarkus.tls.<name>.ssl-engine` to 
`openssl` and names cipher suites in OpenSSL style, which Vert.x accepts. Use 
the JSSE names for a configuration that Camel components consume.
+
+[source,properties]
+----
+# Rejected by the JVM
+# quarkus.tls.cipher-suites=ECDHE-RSA-AES128-GCM-SHA256
+quarkus.tls.cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+----
+
+Note also that a configured list takes precedence over Camel's own default 
exclusion filters. Because `quarkus.tls.protocols` always carries a value, 
those filters do not exclude the SSLv2 and SSLv3 protocols from a bridged 
configuration, and they exclude the `NULL`, `anon`, `EXPORT`, `DES`, `MD5` and 
`RC4` cipher suites only while `quarkus.tls.cipher-suites` is unset.
+
+=== Options that cannot be bridged are now reported
+
+`certificate-revocation-list`, `hostname-verification-algorithm`, 
`key-store.sni`, `alpn` and `pqc-enforcement-policy` have no equivalent in 
`SSLContextParameters` and are still not carried over. They remain the 
responsibility of the consuming Camel component or endpoint, and continue to 
apply to Quarkus's own TLS consumers as before.
+
+A warning is now logged at startup for the two that weaken verification if the 
operator assumes otherwise, instead of them being dropped silently. In 
particular, a Camel component using a bridged bean does not check certificate 
revocation, and so accepts a revoked certificate that the rest of the 
application rejects.
+
+Refer to the 
xref:reference/extensions/tls-registry.adoc#extensions-tls-registry-usage-protocols-and-cipher-suites[TLS
 Registry extension documentation] for details.
diff --git a/docs/modules/ROOT/pages/reference/extensions/tls-registry.adoc 
b/docs/modules/ROOT/pages/reference/extensions/tls-registry.adoc
index 185e79ef3e..482c941daa 100644
--- a/docs/modules/ROOT/pages/reference/extensions/tls-registry.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/tls-registry.adoc
@@ -125,6 +125,51 @@ from("timer:tick")
     .to("https://api.example.com?useGlobalSslContextParameters=true";);
 ----
 
+[id="extensions-tls-registry-usage-protocols-and-cipher-suites"]
+=== Protocols And Cipher Suites
+
+The protocols, cipher suites and key exchange groups set on a Quarkus TLS 
configuration are carried over to the `SSLContextParameters` bean and enforced 
on every `SSLEngine` and socket factory Camel derives from it:
+
+[source,properties]
+----
+quarkus.tls.protocols=TLSv1.3,TLSv1.2
+quarkus.tls.cipher-suites=TLS_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+quarkus.tls.key-exchange-groups=x25519,secp384r1
+----
+
+IMPORTANT: `quarkus.tls.protocols` defaults to `TLSv1.3`. Camel components 
consuming a bridged bean therefore negotiate TLSv1.3 only unless you widen the 
property, matching the behaviour of every other consumer of the same Quarkus 
TLS configuration. Set `quarkus.tls.protocols=TLSv1.3,TLSv1.2` if you need to 
talk to endpoints that do not support TLSv1.3.
+
+WARNING: Camel applies a configured list verbatim, in preference to its own 
default exclusion filters. Because `quarkus.tls.protocols` always carries a 
value, those filters never exclude the SSLv2 and SSLv3 protocols from a bridged 
configuration, and they exclude the `NULL`, `anon`, `EXPORT`, `DES`, `MD5` and 
`RC4` cipher suites only while `quarkus.tls.cipher-suites` is unset. A weak 
protocol or cipher suite that you configure explicitly is used as configured.
+
+A value that the JVM does not recognise is rejected rather than ignored, 
failing the creation of the SSL context. This includes OpenSSL style cipher 
suite names such as `ECDHE-RSA-AES128-GCM-SHA256`, which Vert.x accepts when 
`quarkus.tls.<name>.ssl-engine` is set to `openssl`. Use the JSSE names, for 
example `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`, for a configuration that Camel 
components consume.
+
+[id="extensions-tls-registry-usage-options-that-cannot-be-bridged"]
+==== Options That Cannot Be Bridged
+
+Some `quarkus.tls.*` options have no equivalent in `SSLContextParameters`, 
because they are applied by Vert.x rather than by the JSSE `SSLContext`:
+
+[cols="1,3"]
+|===
+|Option |Notes
+
+|`certificate-revocation-list`
+|Not carried over. Camel components using a bridged bean do not check 
certificate revocation and accept a revoked certificate that the rest of the 
application rejects. A warning is logged at startup when this option is set.
+
+|`hostname-verification-algorithm`
+|Not carried over. Configure hostname verification on the consuming Camel 
component or endpoint instead. A warning is logged at startup when this option 
is set.
+
+|`key-store.sni`
+|Not carried over. Server name indication is a Vert.x transport concern.
+
+|`alpn`
+|Not carried over. Protocol negotiation is handled by the consuming component.
+
+|`pqc-enforcement-policy`
+|Not carried over. Use `quarkus.tls.<name>.key-exchange-groups`, which is, to 
constrain the groups Camel offers.
+|===
+
+These options continue to apply to Quarkus's own TLS consumers as normal. Only 
the Camel bridge is affected.
+
 [id="extensions-tls-registry-usage-certificate-reload"]
 === Certificate Reload
 
diff --git a/extensions/tls-registry/runtime/src/main/doc/usage.adoc 
b/extensions/tls-registry/runtime/src/main/doc/usage.adoc
index 9cf61d22c1..aa7dd393ac 100644
--- a/extensions/tls-registry/runtime/src/main/doc/usage.adoc
+++ b/extensions/tls-registry/runtime/src/main/doc/usage.adoc
@@ -80,6 +80,49 @@ from("timer:tick")
     .to("https://api.example.com?useGlobalSslContextParameters=true";);
 ----
 
+=== Protocols And Cipher Suites
+
+The protocols, cipher suites and key exchange groups set on a Quarkus TLS 
configuration are carried over to the `SSLContextParameters` bean and enforced 
on every `SSLEngine` and socket factory Camel derives from it:
+
+[source,properties]
+----
+quarkus.tls.protocols=TLSv1.3,TLSv1.2
+quarkus.tls.cipher-suites=TLS_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+quarkus.tls.key-exchange-groups=x25519,secp384r1
+----
+
+IMPORTANT: `quarkus.tls.protocols` defaults to `TLSv1.3`. Camel components 
consuming a bridged bean therefore negotiate TLSv1.3 only unless you widen the 
property, matching the behaviour of every other consumer of the same Quarkus 
TLS configuration. Set `quarkus.tls.protocols=TLSv1.3,TLSv1.2` if you need to 
talk to endpoints that do not support TLSv1.3.
+
+WARNING: Camel applies a configured list verbatim, in preference to its own 
default exclusion filters. Because `quarkus.tls.protocols` always carries a 
value, those filters never exclude the SSLv2 and SSLv3 protocols from a bridged 
configuration, and they exclude the `NULL`, `anon`, `EXPORT`, `DES`, `MD5` and 
`RC4` cipher suites only while `quarkus.tls.cipher-suites` is unset. A weak 
protocol or cipher suite that you configure explicitly is used as configured.
+
+A value that the JVM does not recognise is rejected rather than ignored, 
failing the creation of the SSL context. This includes OpenSSL style cipher 
suite names such as `ECDHE-RSA-AES128-GCM-SHA256`, which Vert.x accepts when 
`quarkus.tls.<name>.ssl-engine` is set to `openssl`. Use the JSSE names, for 
example `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`, for a configuration that Camel 
components consume.
+
+==== Options That Cannot Be Bridged
+
+Some `quarkus.tls.*` options have no equivalent in `SSLContextParameters`, 
because they are applied by Vert.x rather than by the JSSE `SSLContext`:
+
+[cols="1,3"]
+|===
+|Option |Notes
+
+|`certificate-revocation-list`
+|Not carried over. Camel components using a bridged bean do not check 
certificate revocation and accept a revoked certificate that the rest of the 
application rejects. A warning is logged at startup when this option is set.
+
+|`hostname-verification-algorithm`
+|Not carried over. Configure hostname verification on the consuming Camel 
component or endpoint instead. A warning is logged at startup when this option 
is set.
+
+|`key-store.sni`
+|Not carried over. Server name indication is a Vert.x transport concern.
+
+|`alpn`
+|Not carried over. Protocol negotiation is handled by the consuming component.
+
+|`pqc-enforcement-policy`
+|Not carried over. Use `quarkus.tls.<name>.key-exchange-groups`, which is, to 
constrain the groups Camel offers.
+|===
+
+These options continue to apply to Quarkus's own TLS consumers as normal. Only 
the Camel bridge is affected.
+
 === Certificate Reload
 
 The extension automatically observes certificate reload events from Quarkus 
TLS registry.
diff --git 
a/extensions/tls-registry/runtime/src/main/java/org/apache/camel/quarkus/core/tls/TlsConfigurationConverter.java
 
b/extensions/tls-registry/runtime/src/main/java/org/apache/camel/quarkus/core/tls/TlsConfigurationConverter.java
index 83fa202fb1..e8fb3bf576 100644
--- 
a/extensions/tls-registry/runtime/src/main/java/org/apache/camel/quarkus/core/tls/TlsConfigurationConverter.java
+++ 
b/extensions/tls-registry/runtime/src/main/java/org/apache/camel/quarkus/core/tls/TlsConfigurationConverter.java
@@ -19,20 +19,31 @@ package org.apache.camel.quarkus.core.tls;
 import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
 
 import javax.net.ssl.SSLContext;
 
 import io.quarkus.tls.TlsConfiguration;
+import io.vertx.core.net.SSLOptions;
 import org.apache.camel.CamelContext;
+import org.apache.camel.support.jsse.CipherSuitesParameters;
 import org.apache.camel.support.jsse.KeyManagersParameters;
 import org.apache.camel.support.jsse.KeyStoreParameters;
+import org.apache.camel.support.jsse.NamedGroupsParameters;
 import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.SecureSocketProtocolsParameters;
 import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Converts Quarkus TlsConfiguration to Camel SSLContextParameters.
  */
 final class TlsConfigurationConverter {
+    private static final Logger LOG = 
LoggerFactory.getLogger(TlsConfigurationConverter.class);
+
     private TlsConfigurationConverter() {
         // Utility class
     }
@@ -48,23 +59,54 @@ final class TlsConfigurationConverter {
      *
      * - Loading keystores and truststores (JKS, PKCS12, PEM)
      * - Configuring key and trust managers
-     * - Setting cipher suites and protocols
      * - Handling certificate reloading
      *
+     * The {@code protocols}, {@code cipher-suites} and {@code 
key-exchange-groups} configured via
+     * {@code quarkus.tls.*} are copied onto the returned SSLContextParameters 
and enforced on every SSLEngine and
+     * socket factory derived from its SSLContext. Quarkus keeps them on the 
Vert.x {@link SSLOptions} side and
+     * never applies them to the SSLContext itself, so without this they would 
silently not apply to Camel
+     * components.
+     *
+     * Camel applies an explicitly configured list verbatim, in preference to 
its own default exclusion filters. Since
+     * {@code quarkus.tls.protocols} always carries a value, those default 
filters never constrain the protocols of a
+     * bridged configuration, and they constrain its cipher suites only while 
{@code quarkus.tls.cipher-suites} is
+     * unset. A value JSSE does not recognise is rejected rather than dropped.
+     *
+     * A certificate revocation list, {@code hostname-verification-algorithm}, 
SNI, ALPN and
+     * {@code pqc-enforcement-policy} have no equivalent in 
SSLContextParameters. They remain the responsibility of
+     * the consuming Camel component, and a warning is logged for the two that 
weaken verification.
+     *
      * @param  tlsConfig the Quarkus TLS configuration
      * @param  name      the configuration name (for logging)
      * @return           SSLContextParameters that delegates to Quarkus's TLS 
configuration
      */
     static SSLContextParameters convert(TlsConfiguration tlsConfig, String 
name) {
-        return new SSLContextParameters() {
+        SSLContextParameters parameters = new SSLContextParameters() {
             @Override
             public SSLContext createSSLContext(CamelContext camelContext) 
throws GeneralSecurityException, IOException {
+                final SSLContext delegate;
                 try {
-                    return tlsConfig.createSSLContext();
+                    delegate = tlsConfig.createSSLContext();
                 } catch (Exception e) {
                     throw new GeneralSecurityException(
                             "Failed to create SSLContext from Quarkus TLS 
configuration '" + name + "'", e);
                 }
+
+                if (camelContext != null) {
+                    setCamelContext(camelContext);
+                }
+                configureSSLContext(delegate);
+
+                // Quarkus builds the SSLContext from key and trust material 
only. Decorate it the same way
+                // SSLContextParameters.createSSLContext does, so that the 
transport policy carried by this instance
+                // is applied to every SSLEngine, SSLSocketFactory and 
SSLServerSocketFactory derived from it. A
+                // plain JSSE SSLContext cannot carry those pins on its own.
+                return new SSLContextDecorator(
+                        new SSLContextSpiDecorator(
+                                delegate,
+                                getSSLEngineConfigurers(delegate),
+                                getSSLSocketFactoryConfigurers(delegate),
+                                
getSSLServerSocketFactoryConfigurers(delegate)));
             }
 
             @Override
@@ -122,5 +164,57 @@ final class TlsConfigurationConverter {
                 return tmp;
             }
         };
+
+        applyTransportPolicy(parameters, tlsConfig, name);
+
+        return parameters;
+    }
+
+    /**
+     * Copy the transport policy from the Quarkus TLS configuration onto the 
Camel SSLContextParameters, so that it
+     * is enforced on contexts created from it and consumers reading the 
parameters directly observe the operator's
+     * policy. Warn about the configured options that cannot be carried over 
and that weaken verification if the
+     * operator assumes otherwise.
+     */
+    private static void applyTransportPolicy(SSLContextParameters parameters, 
TlsConfiguration tlsConfig, String name) {
+        SSLOptions sslOptions = tlsConfig.getSSLOptions();
+        if (sslOptions != null) {
+            Set<String> protocols = 
sslOptions.getEnabledSecureTransportProtocols();
+            if (protocols != null && !protocols.isEmpty()) {
+                SecureSocketProtocolsParameters protocolsParameters = new 
SecureSocketProtocolsParameters();
+                protocolsParameters.setSecureSocketProtocol(new 
ArrayList<>(protocols));
+                parameters.setSecureSocketProtocols(protocolsParameters);
+                LOG.debug("Quarkus TLS configuration '{}' restricts Camel to 
secure socket protocols {}", name, protocols);
+            }
+
+            Set<String> cipherSuites = sslOptions.getEnabledCipherSuites();
+            if (cipherSuites != null && !cipherSuites.isEmpty()) {
+                CipherSuitesParameters cipherSuitesParameters = new 
CipherSuitesParameters();
+                cipherSuitesParameters.setCipherSuite(new 
ArrayList<>(cipherSuites));
+                parameters.setCipherSuites(cipherSuitesParameters);
+                LOG.debug("Quarkus TLS configuration '{}' restricts Camel to 
cipher suites {}", name, cipherSuites);
+            }
+
+            List<String> keyExchangeGroups = sslOptions.getKeyExchangeGroups();
+            if (keyExchangeGroups != null && !keyExchangeGroups.isEmpty()) {
+                NamedGroupsParameters namedGroups = new 
NamedGroupsParameters();
+                namedGroups.setNamedGroup(new ArrayList<>(keyExchangeGroups));
+                parameters.setNamedGroups(namedGroups);
+                LOG.debug("Quarkus TLS configuration '{}' restricts Camel to 
key exchange groups {}", name,
+                        keyExchangeGroups);
+            }
+
+            if (!sslOptions.getCrlValues().isEmpty() || 
!sslOptions.getCrlPaths().isEmpty()) {
+                LOG.warn("Quarkus TLS configuration '{}' configures a 
certificate revocation list, which cannot be "
+                        + "carried over to Camel SSLContextParameters. Camel 
components using this configuration do "
+                        + "not check certificate revocation.", name);
+            }
+        }
+
+        tlsConfig.getHostnameVerificationAlgorithm().ifPresent(algorithm -> 
LOG.warn(
+                "Quarkus TLS configuration '{}' sets 
hostname-verification-algorithm={}, which cannot be carried over "
+                        + "to Camel SSLContextParameters. Hostname 
verification must be configured on the consuming "
+                        + "Camel component or endpoint.",
+                name, algorithm));
     }
 }
diff --git 
a/integration-tests/tls-registry/src/main/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryResource.java
 
b/integration-tests/tls-registry/src/main/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryResource.java
index 3fb04018ec..5a43662095 100644
--- 
a/integration-tests/tls-registry/src/main/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryResource.java
+++ 
b/integration-tests/tls-registry/src/main/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryResource.java
@@ -16,9 +16,12 @@
  */
 package org.apache.camel.quarkus.core.tls.it;
 
+import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import javax.net.ssl.SSLEngine;
+
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import jakarta.ws.rs.GET;
@@ -68,6 +71,27 @@ public class TlsRegistryResource {
         return context.getSSLContextParameters() != null;
     }
 
+    /**
+     * Exposes the protocol and cipher suite policy actually enforced on an 
SSLEngine derived from a registered
+     * SSLContextParameters bean. Without the SSLContext decoration applied by 
TlsConfigurationConverter these
+     * would be the JVM defaults rather than the quarkus.tls.* policy.
+     */
+    @Path("/ssl-policy/{beanName}")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Map<String, List<String>> sslPolicy(@PathParam("beanName") String 
beanName) throws Exception {
+        SSLContextParameters parameters = 
context.getRegistry().lookupByNameAndType(beanName, SSLContextParameters.class);
+        SSLEngine engine = 
parameters.createSSLContext(context).createSSLEngine();
+        // Named groups are read from the parameters rather than the engine: 
SSLParameters.getNamedGroups is Java 20+
+        // and this project compiles against 17. Camel applies them through 
the same engine configurers as the
+        // protocols and cipher suites asserted above.
+        return Map.of(
+                "protocols", List.of(engine.getEnabledProtocols()),
+                "cipherSuites", List.of(engine.getEnabledCipherSuites()),
+                "namedGroups", parameters.getNamedGroups() == null
+                        ? List.of() : 
parameters.getNamedGroups().getNamedGroup());
+    }
+
     @Path("/ping")
     @GET
     @Produces(MediaType.TEXT_PLAIN)
diff --git 
a/integration-tests/tls-registry/src/test/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryTransportPolicyIT.java
 
b/integration-tests/tls-registry/src/test/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryTransportPolicyIT.java
new file mode 100644
index 0000000000..23786b2aac
--- /dev/null
+++ 
b/integration-tests/tls-registry/src/test/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryTransportPolicyIT.java
@@ -0,0 +1,23 @@
+/*
+ * 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.quarkus.core.tls.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class TlsRegistryTransportPolicyIT extends TlsRegistryTransportPolicyTest {
+}
diff --git 
a/integration-tests/tls-registry/src/test/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryTransportPolicyTest.java
 
b/integration-tests/tls-registry/src/test/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryTransportPolicyTest.java
new file mode 100644
index 0000000000..250fa9e465
--- /dev/null
+++ 
b/integration-tests/tls-registry/src/test/java/org/apache/camel/quarkus/core/tls/it/TlsRegistryTransportPolicyTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.quarkus.core.tls.it;
+
+import java.util.List;
+import java.util.Map;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import io.restassured.common.mapper.TypeRef;
+import io.smallrye.certs.Format;
+import io.smallrye.certs.junit5.Certificate;
+import org.apache.camel.quarkus.test.support.certificate.TestCertificates;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Verifies that the protocol and cipher suite policy configured via {@code 
quarkus.tls.*} is enforced on
+ * SSLContextParameters beans produced by the TLS registry bridge. Quarkus 
keeps that policy on the Vert.x SSLOptions
+ * and never applies it to the SSLContext it builds, so the bridge has to 
carry it across itself.
+ */
+@TestCertificates(certificates = {
+        @Certificate(name = "tls-test", formats = { Format.PKCS12, Format.PEM 
}, password = "changeit")
+})
+@QuarkusTest
+@TestProfile(TlsRegistryTransportPolicyTest.TransportPolicyProfile.class)
+class TlsRegistryTransportPolicyTest {
+
+    private static final String TLS_12_CIPHER_SUITE = 
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+    private static final String KEY_EXCHANGE_GROUP = "secp384r1";
+
+    @Test
+    void configuredProtocolsAndCipherSuitesAreEnforced() {
+        Map<String, List<String>> policy = sslPolicy("restricted");
+
+        assertEquals(List.of("TLSv1.2"), policy.get("protocols"),
+                "Only the protocol configured via 
quarkus.tls.restricted.protocols should be enabled");
+        assertEquals(List.of(TLS_12_CIPHER_SUITE), policy.get("cipherSuites"),
+                "Only the cipher suite configured via 
quarkus.tls.restricted.cipher-suites should be enabled");
+    }
+
+    @Test
+    void quarkusProtocolDefaultIsApplied() {
+        Map<String, List<String>> policy = 
sslPolicy("defaultSslContextParameters");
+
+        // quarkus.tls.protocols defaults to TLSv1.3, so Camel consumers of 
the bridged bean negotiate exactly what
+        // the rest of the Quarkus application negotiates rather than the 
wider JVM default set
+        assertEquals(List.of("TLSv1.3"), policy.get("protocols"));
+    }
+
+    @Test
+    void configuredKeyExchangeGroupsAreCarriedOver() {
+        assertEquals(List.of(KEY_EXCHANGE_GROUP), 
sslPolicy("restricted").get("namedGroups"),
+                "quarkus.tls.restricted.key-exchange-groups should be carried 
over as Camel named groups");
+    }
+
+    /**
+     * Camel's default cipher suite exclusions only apply while no explicit 
list is configured, since an explicit list
+     * takes precedence over the filters. This covers that unset case; a 
configured list is applied verbatim.
+     */
+    @Test
+    void camelDefaultCipherSuiteFiltersApplyWhenNoListIsConfigured() {
+        List<String> cipherSuites = 
sslPolicy("defaultSslContextParameters").get("cipherSuites");
+
+        assertFalse(cipherSuites.isEmpty());
+        assertTrue(cipherSuites.stream().noneMatch(suite -> 
suite.contains("_NULL_")
+                || suite.contains("_anon_")
+                || suite.contains("_EXPORT_")
+                || suite.contains("_DES_")
+                || suite.endsWith("MD5")
+                || suite.contains("RC4")),
+                "Camel's default cipher suite exclusions should apply to 
bridged beans: " + cipherSuites);
+    }
+
+    private static Map<String, List<String>> sslPolicy(String beanName) {
+        return RestAssured.given()
+                .get("/tls-registry/ssl-policy/" + beanName)
+                .then()
+                .statusCode(200)
+                .extract().as(new TypeRef<Map<String, List<String>>>() {
+                });
+    }
+
+    public static class TransportPolicyProfile implements QuarkusTestProfile {
+        @Override
+        public Map<String, String> getConfigOverrides() {
+            return Map.ofEntries(
+                    Map.entry("quarkus.camel.tls-registry.enabled", "true"),
+                    
Map.entry("quarkus.camel.tls-registry.quarkus-default-as-global", "false"),
+                    Map.entry("quarkus.tls.key-store.p12.path", 
"target/certs/tls-test-keystore.p12"),
+                    Map.entry("quarkus.tls.key-store.p12.password", 
"changeit"),
+                    Map.entry("quarkus.tls.restricted.key-store.p12.path", 
"target/certs/tls-test-keystore.p12"),
+                    Map.entry("quarkus.tls.restricted.key-store.p12.password", 
"changeit"),
+                    Map.entry("quarkus.tls.restricted.protocols", "TLSv1.2"),
+                    Map.entry("quarkus.tls.restricted.cipher-suites", 
TLS_12_CIPHER_SUITE),
+                    Map.entry("quarkus.tls.restricted.key-exchange-groups", 
KEY_EXCHANGE_GROUP));
+        }
+    }
+}

Reply via email to