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 2d86ba00ff5f camel-milo: create the HTTPS endpoint for Basic256Sha256
(#29674)
2d86ba00ff5f is described below
commit 2d86ba00ff5fbd2a00d9c46e669114b88fd48d43
Author: dhairya05 <[email protected]>
AuthorDate: Thu Nov 12 17:32:53 2026 +0530
camel-milo: create the HTTPS endpoint for Basic256Sha256 (#29674)
* camel-milo: create the HTTPS endpoint for Basic256Sha256
createEndpointConfigs built the endpoint list with an if/else-if chain whose
last two branches test the same condition:
} else if (securityPolicies.contains(SecurityPolicy.Basic256Sha256)) {
// TCP Basic256Sha256 / SignAndEncrypt
...
} else if (securityPolicies.contains(SecurityPolicy.Basic256Sha256)) {
// HTTPS Basic256Sha256 / Sign (SignAndEncrypt not allowed for
HTTPS)
...
}
The second branch can never be reached, so a server configured with
Basic256Sha256 only ever got the TCP endpoint and never the HTTPS one, even
though the None branch above it registers both transports.
The two branches are merged into one, which registers both endpoints.
The chain also made the policies mutually exclusive, although
securityPolicies
is a Set: configuring None and Basic256Sha256 together gave only the
unsecured endpoints. The None and Basic256Sha256 blocks are now independent
ifs, so each configured policy gets its endpoints. A single-policy
configuration behaves as before.
* camel-milo: give the endpoint-config tests a server certificate
EndpointConfig.Builder.build() rejects a secured policy whose certificate
supplier yields null ("security requires certificate"), so both new tests
threw before reaching an assertion. They now load the module's test
keystore,
the same one AbstractMiloServerTest uses.
---
.../component/milo/server/MiloServerComponent.java | 8 ++-
.../milo/server/ServerSetSecurityPoliciesTest.java | 76 ++++++++++++++++++++++
2 files changed, 81 insertions(+), 3 deletions(-)
diff --git
a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerComponent.java
b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerComponent.java
index a04274e6fbe1..b43baa0f280e 100644
---
a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerComponent.java
+++
b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerComponent.java
@@ -255,7 +255,8 @@ public class MiloServerComponent extends DefaultComponent {
return createEndpointConfigs(userTokenPolicies, securityPolicies);
}
- private Set<EndpointConfig> createEndpointConfigs(
+ // package private for testing
+ Set<EndpointConfig> createEndpointConfigs(
List<UserTokenPolicy> userTokenPolicies, Set<SecurityPolicy>
securityPolicies) {
Set<EndpointConfig> endpointConfigs = new LinkedHashSet<>();
@@ -298,14 +299,15 @@ public class MiloServerComponent extends DefaultComponent
{
endpointConfigs.add(buildTcpEndpoint(noSecurityBuilder));
endpointConfigs.add(buildHttpsEndpoint(noSecurityBuilder));
- } else if
(securityPolicies.contains(SecurityPolicy.Basic256Sha256)) {
+ }
+ if (securityPolicies != null &&
securityPolicies.contains(SecurityPolicy.Basic256Sha256)) {
// TCP Basic256Sha256 / SignAndEncrypt
endpointConfigs.add(buildTcpEndpoint(
builder.copy()
.setSecurityPolicy(SecurityPolicy.Basic256Sha256)
.setSecurityMode(MessageSecurityMode.SignAndEncrypt)));
- } else if
(securityPolicies.contains(SecurityPolicy.Basic256Sha256)) {
+
// HTTPS Basic256Sha256 / Sign (SignAndEncrypt not allowed
for HTTPS)
endpointConfigs.add(buildHttpsEndpoint(
builder.copy()
diff --git
a/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetSecurityPoliciesTest.java
b/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetSecurityPoliciesTest.java
index 97bab3eacb9c..e7a99837d1d8 100644
---
a/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetSecurityPoliciesTest.java
+++
b/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetSecurityPoliciesTest.java
@@ -17,8 +17,15 @@
package org.apache.camel.component.milo.server;
import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.Set;
+import org.apache.camel.component.milo.KeyStoreLoader;
import org.apache.camel.test.junit6.CamelTestSupport;
+import org.eclipse.milo.opcua.sdk.server.EndpointConfig;
+import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
+import org.eclipse.milo.opcua.stack.core.transport.TransportProfile;
+import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -64,4 +71,73 @@ public class ServerSetSecurityPoliciesTest extends
CamelTestSupport {
}
}
+ @Test
+ public void testBasic256Sha256HasBothATcpAndAnHttpsEndpoint() throws
Exception {
+ try (final MiloServerComponent component = new MiloServerComponent()) {
+ // a secured policy cannot be built without one:
EndpointConfig.Builder.build() rejects it
+ component.setCertificate(loadTestCertificate());
+
+ final Set<EndpointConfig> endpoints
+ = component.createEndpointConfigs(null,
Set.of(SecurityPolicy.Basic256Sha256));
+
+ Assertions.assertTrue(
+ hasEndpoint(endpoints, TransportProfile.TCP_UASC_UABINARY,
SecurityPolicy.Basic256Sha256,
+ MessageSecurityMode.SignAndEncrypt),
+ "expected a TCP endpoint with Basic256Sha256 /
SignAndEncrypt");
+ Assertions.assertTrue(
+ hasEndpoint(endpoints, TransportProfile.HTTPS_UABINARY,
SecurityPolicy.Basic256Sha256,
+ MessageSecurityMode.Sign),
+ "expected an HTTPS endpoint with Basic256Sha256 / Sign");
+ }
+ }
+
+ @Test
+ public void testNoneAndBasic256Sha256HaveEndpointsForBothPolicies() throws
Exception {
+ try (final MiloServerComponent component = new MiloServerComponent()) {
+ component.setCertificate(loadTestCertificate());
+
+ final Set<EndpointConfig> endpoints
+ = component.createEndpointConfigs(null,
Set.of(SecurityPolicy.None, SecurityPolicy.Basic256Sha256));
+
+ Assertions.assertTrue(
+ hasEndpoint(endpoints, TransportProfile.TCP_UASC_UABINARY,
SecurityPolicy.None,
+ MessageSecurityMode.None),
+ "expected a TCP endpoint with no security");
+ Assertions.assertTrue(
+ hasEndpoint(endpoints, TransportProfile.HTTPS_UABINARY,
SecurityPolicy.None,
+ MessageSecurityMode.None),
+ "expected an HTTPS endpoint with no security");
+ Assertions.assertTrue(
+ hasEndpoint(endpoints, TransportProfile.TCP_UASC_UABINARY,
SecurityPolicy.Basic256Sha256,
+ MessageSecurityMode.SignAndEncrypt),
+ "expected a TCP endpoint with Basic256Sha256 /
SignAndEncrypt");
+ Assertions.assertTrue(
+ hasEndpoint(endpoints, TransportProfile.HTTPS_UABINARY,
SecurityPolicy.Basic256Sha256,
+ MessageSecurityMode.Sign),
+ "expected an HTTPS endpoint with Basic256Sha256 / Sign");
+ }
+ }
+
+ private static X509Certificate loadTestCertificate() throws Exception {
+ final KeyStoreLoader loader = new KeyStoreLoader();
+ loader.setUrl("file:src/test/resources/keystore");
+ loader.setKeyStorePassword("testtest");
+ loader.setKeyPassword("test");
+ return loader.load().getCertificate();
+ }
+
+ /**
+ * Whether one of the regular (non-discovery) endpoints uses the given
transport, policy and security mode. The
+ * discovery endpoints are skipped: they always carry no security,
whatever the configured policies are.
+ */
+ private static boolean hasEndpoint(
+ Set<EndpointConfig> endpoints, TransportProfile transportProfile,
SecurityPolicy securityPolicy,
+ MessageSecurityMode securityMode) {
+ return endpoints.stream()
+ .filter(endpoint -> !"/discovery".equals(endpoint.getPath()))
+ .anyMatch(endpoint -> endpoint.getTransportProfile() ==
transportProfile
+ && endpoint.getSecurityPolicy() == securityPolicy
+ && endpoint.getSecurityMode() == securityMode);
+ }
+
}