This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new a8c52fe Revert "CAMEL-14344 camel-milo - Upgrade to newer milo version (#3539)" (#3545) a8c52fe is described below commit a8c52fec223eca7152c12bd54a071fc9838d69ec Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Feb 5 05:06:03 2020 +0100 Revert "CAMEL-14344 camel-milo - Upgrade to newer milo version (#3539)" (#3545) This reverts commit 13fc9143ef6dfee9d8e1d297fd305c2a644594d4. --- components/camel-milo/pom.xml | 6 - .../src/main/docs/milo-client-component.adoc | 8 +- .../src/main/docs/milo-server-component.adoc | 8 +- .../milo/client/MiloClientConfiguration.java | 4 +- .../component/milo/client/MiloClientConsumer.java | 1 + .../milo/client/internal/SubscriptionManager.java | 22 +- .../component/milo/server/MiloServerComponent.java | 297 +++++++-------------- .../component/milo/server/internal/CallMethod.java | 73 ----- .../milo/server/internal/CamelNamespace.java | 163 ++++++++--- .../milo/server/internal/CamelServerItem.java | 7 +- .../component/milo/AbstractMiloServerTest.java | 27 +- .../milo/MonitorItemMultiConnectionsCertTest.java | 12 +- .../milo/MonitorItemMultiConnectionsTest.java | 6 +- .../camel/component/milo/MonitorItemTest.java | 6 +- .../camel/component/milo/WriteClientTest.java | 4 +- .../camel/component/milo/call/CallClientTest.java | 135 +++------- .../apache/camel/component/milo/call/MockCall.java | 71 +++++ .../camel/component/milo/call/MockCallMethod.java | 77 ------ .../component/milo/call/MockCamelNamespace.java | 141 ---------- .../camel/component/milo/call/MockNamespace.java | 176 ++++++++++++ .../server/ServerSetCertificateManagerTest.java | 2 +- .../camel-milo/src/test/resources/ca/cacert.pem | 32 --- .../camel-milo/src/test/resources/cert/Makefile | 16 ++ .../camel-milo/src/test/resources/cert/cert.ini | 13 + .../camel-milo/src/test/resources/cert/cert.p12 | Bin 0 -> 2461 bytes .../src/test/resources/cert/certificate.crt | 20 ++ .../src/test/resources/cert/certificate.der | Bin 0 -> 856 bytes .../src/test/resources/cert/privateKey.key | 28 ++ components/camel-milo/src/test/resources/keystore | Bin 3990 -> 0 bytes .../camel-milo/src/test/resources/openssl-ca.cnf | 80 ------ .../src/test/resources/openssl-server.cnf | 39 --- components/camel-milo/src/test/resources/run.sh | 21 -- .../modules/ROOT/pages/milo-client-component.adoc | 9 +- .../modules/ROOT/pages/milo-server-component.adoc | 6 +- .../modules/ROOT/pages/camel-3x-upgrade-guide.adoc | 21 -- parent/pom.xml | 5 +- .../karaf/features/src/main/resources/features.xml | 23 +- .../apache/camel/itest/karaf/CamelMiloTest.java | 28 -- 38 files changed, 636 insertions(+), 951 deletions(-) diff --git a/components/camel-milo/pom.xml b/components/camel-milo/pom.xml index 3149be6..807ea5f 100644 --- a/components/camel-milo/pom.xml +++ b/components/camel-milo/pom.xml @@ -55,12 +55,6 @@ <version>${milo-version}</version> </dependency> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - <version>${milo-guava-version}</version> - </dependency> - <!-- testing --> <dependency> <groupId>org.apache.camel</groupId> diff --git a/components/camel-milo/src/main/docs/milo-client-component.adoc b/components/camel-milo/src/main/docs/milo-client-component.adoc index d30640b..705750a 100644 --- a/components/camel-milo/src/main/docs/milo-client-component.adoc +++ b/components/camel-milo/src/main/docs/milo-client-component.adoc @@ -10,8 +10,6 @@ The Milo Client component provides access to OPC UA servers using the http://eclipse.org/milo[Eclipse Milo™] implementation. -*Java 9+*: This component requires Java 9+ at runtime. - Maven users will need to add the following dependency to their `pom.xml` for this component: @@ -54,13 +52,13 @@ The URI syntax of the endpoint is: [source] ------------------------ -milo-client:opc.tcp://[user:password@]host:port/path/to/service?node=RAW(nsu=urn:foo:bar;s=item-1) +milo-client:tcp://[user:password@]host:port/path/to/service?node=RAW(nsu=urn:foo:bar;s=item-1) ------------------------ If the server does not use a path, then it is possible to simply omit it: ------------------------ -milo-client:opc.tcp://[user:password@]host:port?node=RAW(nsu=urn:foo:bar;s=item-1) +milo-client:tcp://[user:password@]host:port?node=RAW(nsu=urn:foo:bar;s=item-1) ------------------------ If no user credentials are provided the client will switch to anonymous mode. @@ -241,7 +239,7 @@ As the values generated by the syntax cannot be transparently encoded into a URI However Camel allows to wrap the actual value inside `RAW(…)`, which makes escaping unnecessary. For example: ------------------------ -milo-client:opc.tcp://user:password@localhost:12345?node=RAW(nsu=http://foo.bar;s=foo/bar) +milo-client:tcp://user:password@localhost:12345?node=RAW(nsu=http://foo.bar;s=foo/bar) ------------------------ === Method ID diff --git a/components/camel-milo/src/main/docs/milo-server-component.adoc b/components/camel-milo/src/main/docs/milo-server-component.adoc index bf62602..d70a8ae 100644 --- a/components/camel-milo/src/main/docs/milo-server-component.adoc +++ b/components/camel-milo/src/main/docs/milo-server-component.adoc @@ -10,7 +10,7 @@ The Milo Server component provides an OPC UA server using the http://eclipse.org/milo[Eclipse Milo™] implementation. -*Java 9+*: This component requires Java 9+ at runtime. +*Java 8*: This component requires Java 8 at runtime. Maven users will need to add the following dependency to their `pom.xml` for this component: @@ -30,7 +30,7 @@ Value write requests from OPC UA Client will trigger messages which are sent int // component options: START -The OPC UA Server component supports 20 options, which are listed below. +The OPC UA Server component supports 22 options, which are listed below. @@ -39,10 +39,12 @@ The OPC UA Server component supports 20 options, which are listed below. | Name | Description | Default | Type | *namespaceUri* (common) | The URI of the namespace, defaults to urn:org:apache:camel | | String | *applicationName* (common) | The application name | | String -| *path* (common) | The path to be appended to the end of the endpoint url. (doesn't need to start with '/') | | String | *applicationUri* (common) | The application URI | | String | *productUri* (common) | The product URI | | String | *bindPort* (common) | The TCP port the server binds to | | int +| *strictEndpointUrlsEnabled* (common) | Set whether strict endpoint URLs are enforced | false | boolean +| *serverName* (common) | Server name | | String +| *hostname* (common) | Server hostname | | String | *securityPolicies* (common) | Security policies | | Set | *securityPoliciesById* (common) | Security policies by URI or name | | Collection | *userAuthenticationCredentials* (common) | Set user password combinations in the form of user1:pwd1,user2:pwd2 Usernames and passwords will be URL decoded | | String diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java index 687a88a..a532657 100644 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConfiguration.java @@ -353,12 +353,12 @@ public class MiloClientConfiguration implements Cloneable { String adding = null; try { - adding = SecurityPolicy.fromUri(policy).getUri(); + adding = SecurityPolicy.fromUri(policy).getSecurityPolicyUri(); } catch (Exception e) { } if (adding == null) { try { - adding = SecurityPolicy.valueOf(policy).getUri(); + adding = SecurityPolicy.valueOf(policy).getSecurityPolicyUri(); } catch (Exception e) { } } diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java index 03023da..515fa4b 100644 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java @@ -28,6 +28,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import static java.util.Objects.requireNonNull; public class MiloClientConsumer extends DefaultConsumer { diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java index 786854f..0a13dbd 100644 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java @@ -45,7 +45,7 @@ import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider; import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaMonitoredItem; import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription; import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscriptionManager.SubscriptionListener; -import org.eclipse.milo.opcua.stack.client.DiscoveryClient; +import org.eclipse.milo.opcua.stack.client.UaTcpStackClient; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.Identifiers; import org.eclipse.milo.opcua.stack.core.StatusCodes; @@ -427,18 +427,10 @@ public class SubscriptionManager { // eval enpoint - String discoveryUri = getEndpointDiscoveryUri(); - - final URI uri = URI.create(getEndpointDiscoveryUri()); - - //milo library doesn't allow user info as a part of the uri, it has to be removed before sending to milo - final String user = uri.getUserInfo(); - if (user != null && !user.isEmpty()) { - discoveryUri = discoveryUri.replaceFirst(user + "@", ""); - } + final String discoveryUri = getEndpointDiscoveryUri(); LOG.debug("Discovering endpoints from: {}", discoveryUri); - final EndpointDescription endpoint = DiscoveryClient.getEndpoints(discoveryUri).thenApply(endpoints -> { + final EndpointDescription endpoint = UaTcpStackClient.getEndpoints(discoveryUri).thenApply(endpoints -> { if (LOG.isDebugEnabled()) { LOG.debug("Found enpoints:"); for (final EndpointDescription ep : endpoints) { @@ -455,9 +447,13 @@ public class SubscriptionManager { LOG.debug("Selected endpoint: {}", endpoint); + final URI uri = URI.create(getEndpointDiscoveryUri()); + // set identity providers + final List<IdentityProvider> providers = new LinkedList<>(); + final String user = uri.getUserInfo(); if (user != null && !user.isEmpty()) { final String[] creds = user.split(":", 2); if (creds != null && creds.length == 2) { @@ -474,7 +470,7 @@ public class SubscriptionManager { // create client - final OpcUaClient client = OpcUaClient.create(cfg.build()); + final OpcUaClient client = new OpcUaClient(cfg.build()); client.connect().get(); try { @@ -534,7 +530,7 @@ public class SubscriptionManager { } } - private EndpointDescription findEndpoint(final List<EndpointDescription> endpoints) throws URISyntaxException { + private EndpointDescription findEndpoint(final EndpointDescription[] endpoints) throws URISyntaxException { final Predicate<String> allowed; final Set<String> uris = this.configuration.getAllowedSecurityPolicies(); 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 3e8ce5a..ccbbebf 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 @@ -23,12 +23,12 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.security.KeyPair; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -47,28 +47,23 @@ import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfigBuilder; import org.eclipse.milo.opcua.sdk.server.identity.AnonymousIdentityValidator; import org.eclipse.milo.opcua.sdk.server.identity.IdentityValidator; import org.eclipse.milo.opcua.sdk.server.identity.UsernameIdentityValidator; -import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.security.CertificateManager; -import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; -import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager; -import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateValidator; -import org.eclipse.milo.opcua.stack.core.security.DefaultTrustListManager; +import org.eclipse.milo.opcua.stack.core.application.CertificateManager; +import org.eclipse.milo.opcua.stack.core.application.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.application.DefaultCertificateManager; +import org.eclipse.milo.opcua.stack.core.application.DefaultCertificateValidator; 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.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo; import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import static java.util.Collections.singletonList; import static org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS; -import static org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig.USER_TOKEN_POLICY_USERNAME; -import static org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig.USER_TOKEN_POLICY_X509; /** * OPC UA Server based component @@ -80,25 +75,54 @@ public class MiloServerComponent extends DefaultComponent { private static final Logger LOG = LoggerFactory.getLogger(MiloServerComponent.class); private static final String URL_CHARSET = "UTF-8"; + private static final OpcUaServerConfig DEFAULT_SERVER_CONFIG; + + static { + final OpcUaServerConfigBuilder cfg = OpcUaServerConfig.builder(); + + cfg.setCertificateManager(new DefaultCertificateManager()); + cfg.setCertificateValidator(DenyAllCertificateValidator.INSTANCE); + cfg.setSecurityPolicies(EnumSet.allOf(SecurityPolicy.class)); + cfg.setApplicationName(LocalizedText.english("Apache Camel Milo Server")); + cfg.setApplicationUri("urn:org:apache:camel:milo:server"); + cfg.setProductUri("urn:org:apache:camel:milo"); + + if (Boolean.getBoolean("org.apache.camel.milo.server.default.enableAnonymous")) { + cfg.setUserTokenPolicies(singletonList(USER_TOKEN_POLICY_ANONYMOUS)); + cfg.setIdentityValidator(AnonymousIdentityValidator.INSTANCE); + } + + DEFAULT_SERVER_CONFIG = cfg.build(); + } - private int port; + private static final class DenyAllCertificateValidator implements CertificateValidator { + public static final CertificateValidator INSTANCE = new DenyAllCertificateValidator(); + + private DenyAllCertificateValidator() { + } + + @Override + public void validate(final X509Certificate certificate) throws UaException { + throw new UaException(StatusCodes.Bad_CertificateUseNotAllowed); + } + + @Override + public void verifyTrustChain(List<X509Certificate> certificateChain) throws UaException { + throw new UaException(StatusCodes.Bad_CertificateUseNotAllowed); + } + } private String namespaceUri = DEFAULT_NAMESPACE_URI; - private OpcUaServerConfigBuilder opcServerConfig; + private final OpcUaServerConfigBuilder serverConfig; private OpcUaServer server; - private CamelNamespace namespace; private final Map<String, MiloServerEndpoint> endpoints = new HashMap<>(); private Boolean enableAnonymousAuthentication; - private CertificateManager certificateManager; - - private Set<SecurityPolicy> securityPolicies; - private Map<String, String> userMap; private String usernameSecurityPolicyUri = OpcUaServerConfig.USER_TOKEN_POLICY_USERNAME.getSecurityPolicyUri(); @@ -109,33 +133,19 @@ public class MiloServerComponent extends DefaultComponent { private final List<Runnable> runOnStop = new LinkedList<>(); - private X509Certificate certificate; - - private String productUri; - - private String applicationUri; - - private String applicationName; - - private String path; - - private BuildInfo buildInfo; - public MiloServerComponent() { - this.opcServerConfig = null; + this(DEFAULT_SERVER_CONFIG); } public MiloServerComponent(final OpcUaServerConfig serverConfig) { - this.opcServerConfig = OpcUaServerConfig.copy(serverConfig); - + this.serverConfig = OpcUaServerConfig.copy(serverConfig != null ? serverConfig : DEFAULT_SERVER_CONFIG); } @Override protected void doStart() throws Exception { this.server = new OpcUaServer(buildServerConfig()); - this.namespace = new CamelNamespace(this.namespaceUri, this.server); - this.namespace.startup(); + this.namespace = this.server.getNamespaceManager().registerAndAdd(this.namespaceUri, index -> new CamelNamespace(index, this.namespaceUri, this.server)); super.doStart(); this.server.startup(); @@ -147,7 +157,6 @@ public class MiloServerComponent extends DefaultComponent { * @return the new server configuration, never returns {@code null} */ private OpcUaServerConfig buildServerConfig() { - OpcUaServerConfigBuilder serverConfig = this.opcServerConfig != null ? this.opcServerConfig : createDefaultConfiguration(); if (this.userMap != null || this.enableAnonymousAuthentication != null) { // set identity validator @@ -161,7 +170,7 @@ public class MiloServerComponent extends DefaultComponent { } return pwd.equals(challenge.getPassword()); }); - serverConfig.setIdentityValidator(identityValidator); + this.serverConfig.setIdentityValidator(identityValidator); // add token policies @@ -172,9 +181,11 @@ public class MiloServerComponent extends DefaultComponent { if (userMap != null) { tokenPolicies.add(getUsernamePolicy()); } - serverConfig.setEndpoints(createEndpointConfigurations(tokenPolicies)); - } else { - serverConfig.setEndpoints(createEndpointConfigurations(null, securityPolicies)); + this.serverConfig.setUserTokenPolicies(tokenPolicies); + } + + if (this.bindAddresses != null) { + this.serverConfig.setBindAddresses(new ArrayList<>(this.bindAddresses)); } if (this.certificateValidator != null) { @@ -190,151 +201,12 @@ public class MiloServerComponent extends DefaultComponent { } }); } - serverConfig.setCertificateValidator(validator); + this.serverConfig.setCertificateValidator(validator); } // build final configuration - return serverConfig.build(); - } - - private OpcUaServerConfigBuilder createDefaultConfiguration() { - final OpcUaServerConfigBuilder cfg = OpcUaServerConfig.builder(); - - cfg.setCertificateManager(new DefaultCertificateManager()); - cfg.setCertificateValidator(DenyAllCertificateValidator.INSTANCE); - cfg.setEndpoints(createEndpointConfigurations(null)); - cfg.setApplicationName(LocalizedText.english(applicationName == null ? "Apache Camel Milo Server" : applicationName)); - cfg.setApplicationUri("urn:org:apache:camel:milo:server"); - cfg.setProductUri("urn:org:apache:camel:milo"); - cfg.setCertificateManager(certificateManager); - if (productUri != null) { - cfg.setProductUri(productUri); - } - if (applicationUri != null) { - cfg.setApplicationUri(applicationUri); - } - if (buildInfo != null) { - cfg.setBuildInfo(buildInfo); - } - - if (Boolean.getBoolean("org.apache.camel.milo.server.default.enableAnonymous")) { - cfg.setIdentityValidator(AnonymousIdentityValidator.INSTANCE); - } - - return cfg; - } - - private Set<EndpointConfiguration> createEndpointConfigurations(List<UserTokenPolicy> userTokenPolicies) { - return createEndpointConfigurations(userTokenPolicies, this.securityPolicies); - } - - private Set<EndpointConfiguration> createEndpointConfigurations(List<UserTokenPolicy> userTokenPolicies, Set<SecurityPolicy> securityPolicies) { - Set<EndpointConfiguration> endpointConfigurations = new LinkedHashSet<>(); - - //if address is not defined, return empty set - if (bindAddresses == null) { - return Collections.emptySet(); - } - - for (String bindAddress : bindAddresses) { - Set<String> hostnames = new LinkedHashSet<>(); - hostnames.add(HostnameUtil.getHostname()); - hostnames.addAll(HostnameUtil.getHostnames(bindAddress)); - - boolean anonymous = (this.enableAnonymousAuthentication != null && this.enableAnonymousAuthentication) - || Boolean.getBoolean("org.apache.camel.milo.server.default.enableAnonymous"); - - UserTokenPolicy[] tokenPolicies = - userTokenPolicies != null ? userTokenPolicies.toArray(new UserTokenPolicy[userTokenPolicies.size()]) - : anonymous - ? new UserTokenPolicy[] {USER_TOKEN_POLICY_ANONYMOUS, USER_TOKEN_POLICY_USERNAME, USER_TOKEN_POLICY_X509} - : new UserTokenPolicy[] {USER_TOKEN_POLICY_USERNAME, USER_TOKEN_POLICY_X509}; - - for (String hostname : hostnames) { - EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder() - .setBindAddress(bindAddress) - .setHostname(hostname) - .setCertificate(certificate) - .setPath(this.path == null ? "" : this.path) - .addTokenPolicies(tokenPolicies); - - - if (securityPolicies == null || securityPolicies.contains(SecurityPolicy.None)) { - EndpointConfiguration.Builder noSecurityBuilder = builder.copy() - .setSecurityPolicy(SecurityPolicy.None) - .setSecurityMode(MessageSecurityMode.None); - - endpointConfigurations.add(buildTcpEndpoint(noSecurityBuilder)); - endpointConfigurations.add(buildHttpsEndpoint(noSecurityBuilder)); - } else if (securityPolicies.contains(SecurityPolicy.Basic256Sha256)) { - - // TCP Basic256Sha256 / SignAndEncrypt - endpointConfigurations.add(buildTcpEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic256Sha256) - .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) - ); - } else if (securityPolicies.contains(SecurityPolicy.Basic256Sha256)) { - // HTTPS Basic256Sha256 / Sign (SignAndEncrypt not allowed for HTTPS) - endpointConfigurations.add(buildHttpsEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic256Sha256) - .setSecurityMode(MessageSecurityMode.Sign)) - ); - } - - /* - * It's good practice to provide a discovery-specific endpoint with no security. - * It's required practice if all regular endpoints have security configured. - * - * Usage of the "/discovery" suffix is defined by OPC UA Part 6: - * - * Each OPC UA Server Application implements the Discovery Service Set. If the OPC UA Server requires a - * different address for this Endpoint it shall create the address by appending the path "/discovery" to - * its base address. - */ - EndpointConfiguration.Builder discoveryBuilder = builder.copy() - .setPath("/discovery") - .setSecurityPolicy(SecurityPolicy.None) - .setSecurityMode(MessageSecurityMode.None); - - endpointConfigurations.add(buildTcpEndpoint(discoveryBuilder)); - endpointConfigurations.add(buildHttpsEndpoint(discoveryBuilder)); - } - } - - return endpointConfigurations; - } - private EndpointConfiguration buildTcpEndpoint(EndpointConfiguration.Builder base) { - return base.copy() - .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) - .setBindPort(this.port) - .build(); - } - - private EndpointConfiguration buildHttpsEndpoint(EndpointConfiguration.Builder base) { - return base.copy() - .setTransportProfile(TransportProfile.HTTPS_UABINARY) - .setBindPort(this.port) - .build(); - } - - private static final class DenyAllCertificateValidator implements CertificateValidator { - public static final CertificateValidator INSTANCE = new DenyAllCertificateValidator(); - - private DenyAllCertificateValidator() { - } - - @Override - public void validate(final X509Certificate certificate) throws UaException { - throw new UaException(StatusCodes.Bad_CertificateUseNotAllowed); - } - - @Override - public void verifyTrustChain(List<X509Certificate> certificateChain) throws UaException { - throw new UaException(StatusCodes.Bad_CertificateUseNotAllowed); - } + return this.serverConfig.build(); } /** @@ -399,15 +271,7 @@ public class MiloServerComponent extends DefaultComponent { */ public void setApplicationName(final String applicationName) { Objects.requireNonNull(applicationName); - this.applicationName = applicationName; - } - - /** - * The path to be appended to the end of the endpoint url. (doesn't need to start with '/') - */ - public void setPath(final String path) { - Objects.requireNonNull(path); - this.path = path; + this.serverConfig.setApplicationName(LocalizedText.english(applicationName)); } /** @@ -415,7 +279,7 @@ public class MiloServerComponent extends DefaultComponent { */ public void setApplicationUri(final String applicationUri) { Objects.requireNonNull(applicationUri); - this.applicationUri = applicationUri; + this.serverConfig.setApplicationUri(applicationUri); } /** @@ -423,14 +287,35 @@ public class MiloServerComponent extends DefaultComponent { */ public void setProductUri(final String productUri) { Objects.requireNonNull(productUri); - this.productUri = productUri; + this.serverConfig.setProductUri(productUri); } /** * The TCP port the server binds to */ public void setBindPort(final int port) { - this.port = port; + this.serverConfig.setBindPort(port); + } + + /** + * Set whether strict endpoint URLs are enforced + */ + public void setStrictEndpointUrlsEnabled(final boolean strictEndpointUrlsEnforced) { + this.serverConfig.setStrictEndpointUrlsEnabled(strictEndpointUrlsEnforced); + } + + /** + * Server name + */ + public void setServerName(final String serverName) { + this.serverConfig.setServerName(serverName); + } + + /** + * Server hostname + */ + public void setHostname(final String hostname) { + this.serverConfig.setServerName(hostname); } /** @@ -438,9 +323,9 @@ public class MiloServerComponent extends DefaultComponent { */ public void setSecurityPolicies(final Set<SecurityPolicy> securityPolicies) { if (securityPolicies == null || securityPolicies.isEmpty()) { - this.securityPolicies = EnumSet.noneOf(SecurityPolicy.class); + this.serverConfig.setSecurityPolicies(EnumSet.noneOf(SecurityPolicy.class)); } else { - this.securityPolicies = EnumSet.copyOf(securityPolicies); + this.serverConfig.setSecurityPolicies(EnumSet.copyOf(securityPolicies)); } } @@ -457,7 +342,7 @@ public class MiloServerComponent extends DefaultComponent { } } - this.securityPolicies = policies; + this.serverConfig.setSecurityPolicies(policies); } /** @@ -507,7 +392,7 @@ public class MiloServerComponent extends DefaultComponent { * Set the {@link UserTokenPolicy} used when */ public void setUsernameSecurityPolicyUri(final SecurityPolicy usernameSecurityPolicy) { - this.usernameSecurityPolicyUri = usernameSecurityPolicy.getUri(); + this.usernameSecurityPolicyUri = usernameSecurityPolicy.getSecurityPolicyUri(); } /** @@ -532,7 +417,7 @@ public class MiloServerComponent extends DefaultComponent { * Server build info */ public void setBuildInfo(final BuildInfo buildInfo) { - this.buildInfo = buildInfo; + this.serverConfig.setBuildInfo(buildInfo); } /** @@ -555,7 +440,6 @@ public class MiloServerComponent extends DefaultComponent { * Server certificate */ public void setServerCertificate(final KeyPair keyPair, final X509Certificate certificate) { - this.certificate = certificate; setCertificateManager(new DefaultCertificateManager(keyPair, certificate)); } @@ -563,7 +447,11 @@ public class MiloServerComponent extends DefaultComponent { * Server certificate manager */ public void setCertificateManager(final CertificateManager certificateManager) { - this.certificateManager = certificateManager != null ? certificateManager : new DefaultCertificateManager(); + if (certificateManager != null) { + this.serverConfig.setCertificateManager(certificateManager); + } else { + this.serverConfig.setCertificateManager(new DefaultCertificateManager()); + } } /** @@ -577,11 +465,6 @@ public class MiloServerComponent extends DefaultComponent { * Validator for client certificates using default file based approach */ public void setDefaultCertificateValidator(final File certificatesBaseDir) { - try { - DefaultTrustListManager trustListManager = new DefaultTrustListManager(certificatesBaseDir); - this.certificateValidator = () -> new DefaultCertificateValidator(trustListManager); - } catch (IOException e) { - LOG.error("Failed to construct certificateValidator.", e); - } + this.certificateValidator = () -> new DefaultCertificateValidator(certificatesBaseDir); } } diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CallMethod.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CallMethod.java deleted file mode 100644 index c190280..0000000 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CallMethod.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.milo.server.internal; - -import org.eclipse.milo.opcua.sdk.core.ValueRanks; -import org.eclipse.milo.opcua.sdk.server.api.methods.AbstractMethodInvocationHandler; -import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; -import org.eclipse.milo.opcua.stack.core.Identifiers; -import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; -import org.eclipse.milo.opcua.stack.core.types.structured.Argument; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CallMethod extends AbstractMethodInvocationHandler { - - public static final Argument IN = new Argument( - "in", - Identifiers.String, - ValueRanks.Scalar, - null, - new LocalizedText("A value.") - ); - - public static final Argument OUT = new Argument( - "out", - Identifiers.String, - ValueRanks.Scalar, - null, - new LocalizedText("A value.") - ); - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - public CallMethod(UaMethodNode node) { - super(node); - } - - @Override - public Argument[] getInputArguments() { - return new Argument[]{IN}; - } - - @Override - public Argument[] getOutputArguments() { - return new Argument[]{OUT}; - } - - @Override - protected Variant[] invoke(InvocationContext invocationContext, Variant[] inputValues) { - logger.debug("Invoking sqrt() method of objectId={}", invocationContext.getObjectId()); - - String in = (String) inputValues[0].getValue(); - - return new Variant[]{new Variant("out-" + in)}; - } - -} diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelNamespace.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelNamespace.java index 7a166cf..7fdd2a9 100644 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelNamespace.java +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelNamespace.java @@ -19,78 +19,157 @@ package org.apache.camel.component.milo.server.internal; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; +import com.google.common.collect.Lists; +import org.apache.camel.component.milo.client.MiloClientConsumer; import org.eclipse.milo.opcua.sdk.core.Reference; import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.api.AccessContext; import org.eclipse.milo.opcua.sdk.server.api.DataItem; -import org.eclipse.milo.opcua.sdk.server.api.ManagedNamespace; import org.eclipse.milo.opcua.sdk.server.api.MonitoredItem; +import org.eclipse.milo.opcua.sdk.server.api.Namespace; +import org.eclipse.milo.opcua.sdk.server.api.ServerNodeMap; +import org.eclipse.milo.opcua.sdk.server.nodes.AttributeContext; +import org.eclipse.milo.opcua.sdk.server.nodes.ServerNode; import org.eclipse.milo.opcua.sdk.server.nodes.UaFolderNode; import org.eclipse.milo.opcua.sdk.server.nodes.UaObjectNode; import org.eclipse.milo.opcua.sdk.server.util.SubscriptionModel; import org.eclipse.milo.opcua.stack.core.Identifiers; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class CamelNamespace extends ManagedNamespace { +public class CamelNamespace implements Namespace { - private final SubscriptionModel subscriptionModel; + private static final Logger LOG = LoggerFactory.getLogger(MiloClientConsumer.class); + + private final UShort namespaceIndex; - private UaObjectNode itemsObject; - private UaFolderNode folder; + private final String namespaceUri; + private final ServerNodeMap nodeManager; + private final SubscriptionModel subscriptionModel; + + private final UaFolderNode folder; + private final UaObjectNode itemsObject; private final Map<String, CamelServerItem> itemMap = new HashMap<>(); - public CamelNamespace(final String namespaceUri, final OpcUaServer server) { - super(server, namespaceUri); + public CamelNamespace(final UShort namespaceIndex, final String namespaceUri, final OpcUaServer server) { + this.namespaceIndex = namespaceIndex; + this.namespaceUri = namespaceUri; + this.nodeManager = server.getNodeMap(); this.subscriptionModel = new SubscriptionModel(server, this); + + // create structure + + { + final NodeId nodeId = new NodeId(namespaceIndex, "camel"); + final QualifiedName name = new QualifiedName(namespaceIndex, "camel"); + final LocalizedText displayName = LocalizedText.english("Camel"); + + this.folder = new UaFolderNode(this.nodeManager, nodeId, name, displayName); + this.nodeManager.addNode(this.folder); + } + + { + final NodeId nodeId = new NodeId(namespaceIndex, "items"); + final QualifiedName name = new QualifiedName(namespaceIndex, "items"); + final LocalizedText displayName = LocalizedText.english("Items"); + this.itemsObject = new UaObjectNode(this.nodeManager, nodeId, name, displayName); + this.folder.addComponent(this.itemsObject); + } + + // register reference to structure + + try { + server.getUaNamespace().addReference(Identifiers.ObjectsFolder, Identifiers.Organizes, true, this.folder.getNodeId().expanded(), NodeClass.Object); + } catch (final UaException e) { + throw new RuntimeException("Failed to register folder", e); + } } @Override - protected void onStartup() { - super.onStartup(); - // create structure + public UShort getNamespaceIndex() { + return this.namespaceIndex; + } - final NodeId nodeId = newNodeId("camel"); - final QualifiedName name = newQualifiedName("camel"); - final LocalizedText displayName = LocalizedText.english("Camel"); + @Override + public String getNamespaceUri() { + return this.namespaceUri; + } - this.folder = new UaFolderNode(getNodeContext(), nodeId, name, displayName); - getNodeManager().addNode(this.folder); + @Override + public CompletableFuture<List<Reference>> browse(final AccessContext context, final NodeId nodeId) { + final ServerNode node = this.nodeManager.get(nodeId); + + if (node != null) { + return CompletableFuture.completedFuture(node.getReferences()); + } else { + final CompletableFuture<List<Reference>> f = new CompletableFuture<>(); + f.completeExceptionally(new UaException(StatusCodes.Bad_NodeIdUnknown)); + return f; + } + } - final NodeId nodeId2 = newNodeId("items"); - final QualifiedName name2 = newQualifiedName("items"); - final LocalizedText displayName2 = LocalizedText.english("Items"); + @Override + public void read(final ReadContext context, final Double maxAge, final TimestampsToReturn timestamps, final List<ReadValueId> readValueIds) { + final List<DataValue> results = Lists.newArrayListWithCapacity(readValueIds.size()); - this.itemsObject = UaObjectNode.builder(getNodeContext()) - .setNodeId(nodeId2) - .setBrowseName(name2) - .setDisplayName(displayName2) - .setTypeDefinition(Identifiers.FolderType) - .build(); - this.folder.addComponent(this.itemsObject); - this.itemsObject.addComponent(this.folder); - this.getNodeManager().addNode(this.itemsObject); + for (final ReadValueId id : readValueIds) { + final ServerNode node = this.nodeManager.get(id.getNodeId()); + final DataValue value; - // register reference to structure + if (node != null) { + value = node.readAttribute(new AttributeContext(context), id.getAttributeId(), timestamps, id.getIndexRange(), null); + } else { + value = new DataValue(StatusCodes.Bad_NodeIdUnknown); + } + + results.add(value); + } + + context.complete(results); + } + + @Override + public void write(final WriteContext context, final List<WriteValue> writeValues) { + final List<StatusCode> results = Lists.newArrayListWithCapacity(writeValues.size()); + + for (final WriteValue writeValue : writeValues) { + try { + final ServerNode node = this.nodeManager.getNode(writeValue.getNodeId()).orElseThrow(() -> new UaException(StatusCodes.Bad_NodeIdUnknown)); + + node.writeAttribute(new AttributeContext(context), writeValue.getAttributeId(), writeValue.getValue(), writeValue.getIndexRange()); + + if (LOG.isTraceEnabled()) { + final Variant variant = writeValue.getValue().getValue(); + final Object o = variant != null ? variant.getValue() : null; + LOG.trace("Wrote value={} to attributeId={} of {}", o, writeValue.getAttributeId(), writeValue.getNodeId()); + } + + results.add(StatusCode.GOOD); + } catch (final UaException e) { + results.add(e.getStatusCode()); + } + } - folder.addReference(new Reference( - folder.getNodeId(), - Identifiers.Organizes, - Identifiers.ObjectsFolder.expanded(), - false - )); - - itemsObject.addReference(new Reference( - nodeId, - Identifiers.HasComponent, - Identifiers.ObjectNode.expanded(), - Reference.Direction.INVERSE - )); + context.complete(results); } @Override @@ -117,7 +196,7 @@ public class CamelNamespace extends ManagedNamespace { synchronized (this) { CamelServerItem item = this.itemMap.get(itemId); if (item == null) { - item = new CamelServerItem(itemId, getNodeContext(), getNamespaceIndex(), this.itemsObject); + item = new CamelServerItem(itemId, this.nodeManager, this.namespaceIndex, this.itemsObject); this.itemMap.put(itemId, item); } return item; diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelServerItem.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelServerItem.java index fa74c02..c1db1eb 100644 --- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelServerItem.java +++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CamelServerItem.java @@ -23,7 +23,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Consumer; import org.eclipse.milo.opcua.sdk.core.AccessLevel; -import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.sdk.server.api.ServerNodeMap; import org.eclipse.milo.opcua.sdk.server.nodes.UaObjectNode; import org.eclipse.milo.opcua.sdk.server.nodes.UaVariableNode; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; @@ -49,7 +49,7 @@ public class CamelServerItem { private final Set<Consumer<DataValue>> listeners = new CopyOnWriteArraySet<>(); private DataValue value = new DataValue(StatusCode.BAD); - public CamelServerItem(final String itemId, final UaNodeContext nodeContext, final UShort namespaceIndex, final UaObjectNode baseNode) { + public CamelServerItem(final String itemId, final ServerNodeMap nodeManager, final UShort namespaceIndex, final UaObjectNode baseNode) { this.itemId = itemId; this.baseNode = baseNode; @@ -60,7 +60,7 @@ public class CamelServerItem { // create variable node - this.item = new UaVariableNode(nodeContext, nodeId, qname, displayName) { + this.item = new UaVariableNode(nodeManager, nodeId, qname, displayName) { @Override public synchronized DataValue getValue() { @@ -79,7 +79,6 @@ public class CamelServerItem { this.item.setUserAccessLevel(ubyte(AccessLevel.getMask(AccessLevel.READ_WRITE))); baseNode.addComponent(this.item); - nodeContext.getNodeManager().addNode(this.item); } public void dispose() { diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/AbstractMiloServerTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/AbstractMiloServerTest.java index ab12493..35902b0 100644 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/AbstractMiloServerTest.java +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/AbstractMiloServerTest.java @@ -27,7 +27,6 @@ import org.apache.camel.test.AvailablePortFinder; import org.apache.camel.test.junit4.CamelTestSupport; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; -import org.junit.Assume; public abstract class AbstractMiloServerTest extends CamelTestSupport { @@ -35,7 +34,6 @@ public abstract class AbstractMiloServerTest extends CamelTestSupport { @Override protected void doPreSetup() throws Exception { - Assume.assumeTrue("Requires java 9+", isJavaVersionSatisfied(9)); super.doPreSetup(); this.serverPort = AvailablePortFinder.getNextAvailable(); } @@ -114,10 +112,9 @@ public abstract class AbstractMiloServerTest extends CamelTestSupport { try { final KeyStoreLoader loader = new KeyStoreLoader(); - loader.setUrl("file:src/test/resources/keystore"); - loader.setKeyStorePassword("testtest"); - - loader.setKeyPassword("test"); + loader.setUrl("file:src/test/resources/cert/cert.p12"); + loader.setKeyStorePassword("pwd1"); + loader.setKeyPassword("pwd1"); return loader.load(); } catch (final GeneralSecurityException | IOException e) { throw new RuntimeException(e); @@ -125,22 +122,4 @@ public abstract class AbstractMiloServerTest extends CamelTestSupport { } - /** - * Return true, if java version (defined by method getRequiredJavaVersion()) is satisfied. - * Works for java versions 9+ - */ - boolean isJavaVersionSatisfied(int requiredVersion) { - String version = System.getProperty("java.version"); - if (!version.startsWith("1.")) { - int dot = version.indexOf("."); - if (dot != -1) { - version = version.substring(0, dot); - } - if (Integer.parseInt(version) >= requiredVersion) { - return true; - } - } - return false; - } - } diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsCertTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsCertTest.java index 5b3bcfcf..1c10522 100644 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsCertTest.java +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsCertTest.java @@ -43,18 +43,18 @@ public class MonitorItemMultiConnectionsCertTest extends AbstractMiloServerTest private static final String MILO_SERVER_ITEM_1 = "milo-server:myitem1"; // with key - private static final String MILO_CLIENT_ITEM_C1_1 = "milo-client:opc.tcp://foo:bar@localhost:@@port@@?node=" + private static final String MILO_CLIENT_ITEM_C1_1 = "milo-client:tcp://foo:bar@localhost:@@port@@?node=" + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") - + "&keyStoreUrl=file:src/test/resources/keystore&keyStorePassword=testtest&keyPassword=test&keyAlias=test" + + "&keyStoreUrl=file:src/test/resources/cert/cert.p12&keyStorePassword=pwd1&keyPassword=pwd1" + "&discoveryEndpointSuffix=/discovery&overrideHost=true"; // with wrong password - private static final String MILO_CLIENT_ITEM_C2_1 = "milo-client:opc.tcp://foo:bar2@localhost:@@port@@?node=" + private static final String MILO_CLIENT_ITEM_C2_1 = "milo-client:tcp://foo:bar2@localhost:@@port@@?node=" + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") + "&discoveryEndpointSuffix=/discovery&overrideHost=true"; // without key, clientId=1 - private static final String MILO_CLIENT_ITEM_C3_1 = "milo-client:opc.tcp://foo:bar@localhost:@@port@@?clientId=1&node=" + private static final String MILO_CLIENT_ITEM_C3_1 = "milo-client:tcp://foo:bar@localhost:@@port@@?clientId=1&node=" + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") + "&discoveryEndpointSuffix=/discovery&overrideHost=true"; @@ -79,10 +79,10 @@ public class MonitorItemMultiConnectionsCertTest extends AbstractMiloServerTest super.configureMiloServer(server); final Path baseDir = Paths.get("target/testing/cert/default"); - final Path trusted = baseDir.resolve("trusted/certs"); + final Path trusted = baseDir.resolve("trusted"); Files.createDirectories(trusted); - Files.copy(Paths.get("src/test/resources/ca/cacert.pem"), trusted.resolve("cacert.pem"), REPLACE_EXISTING); + Files.copy(Paths.get("src/test/resources/cert/certificate.der"), trusted.resolve("certificate.der"), REPLACE_EXISTING); server.setServerCertificate(loadDefaultTestKey()); server.setDefaultCertificateValidator(baseDir.toFile()); diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsTest.java index 116cf98..dcccaf9 100644 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsTest.java +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemMultiConnectionsTest.java @@ -34,13 +34,13 @@ public class MonitorItemMultiConnectionsTest extends AbstractMiloServerTest { private static final String MILO_SERVER_ITEM_1 = "milo-server:myitem1"; - private static final String MILO_CLIENT_ITEM_C1_1 = "milo-client:opc.tcp://foo:bar@localhost:@@port@@?node=" + private static final String MILO_CLIENT_ITEM_C1_1 = "milo-client:tcp://foo:bar@localhost:@@port@@?node=" + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") + "&overrideHost=true"; - private static final String MILO_CLIENT_ITEM_C2_1 = "milo-client:opc.tcp://foo:bar2@localhost:@@port@@?node=" + private static final String MILO_CLIENT_ITEM_C2_1 = "milo-client:tcp://foo:bar2@localhost:@@port@@?node=" + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") + "&overrideHost=true"; - private static final String MILO_CLIENT_ITEM_C3_1 = "milo-client:opc.tcp://foo2:bar@localhost:@@port@@?node=" + private static final String MILO_CLIENT_ITEM_C3_1 = "milo-client:tcp://foo2:bar@localhost:@@port@@?node=" + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") + "&overrideHost=true"; private static final String MOCK_TEST_1 = "mock:test1"; diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemTest.java index 3b3ba6d..b4d9b3e 100644 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemTest.java +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/MonitorItemTest.java @@ -34,9 +34,9 @@ public class MonitorItemTest extends AbstractMiloServerTest { private static final String MILO_SERVER_ITEM_1 = "milo-server:myitem1"; - private static final String MILO_CLIENT_ITEM_C1_1 = "milo-client:opc.tcp://foo:bar@localhost:@@port@@?node=" - + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") - + "&allowedSecurityPolicies=None&overrideHost=true"; + private static final String MILO_CLIENT_ITEM_C1_1 = "milo-client:tcp://foo:bar@localhost:@@port@@?node=" + + NodeIds.nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") + + "&allowedSecurityPolicies=None&overrideHost=true"; private static final String MOCK_TEST_1 = "mock:test1"; diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/WriteClientTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/WriteClientTest.java index 9a0942c..43214b3 100644 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/WriteClientTest.java +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/WriteClientTest.java @@ -41,8 +41,8 @@ public class WriteClientTest extends AbstractMiloServerTest { private static final String MILO_SERVER_ITEM_1 = "milo-server:myitem1"; private static final String MILO_SERVER_ITEM_2 = "milo-server:myitem2"; - private static final String MILO_CLIENT_BASE_C1 = "milo-client:opc.tcp://foo:bar@localhost:@@port@@"; - private static final String MILO_CLIENT_BASE_C2 = "milo-client:opc.tcp://foo2:bar2@localhost:@@port@@"; + private static final String MILO_CLIENT_BASE_C1 = "milo-client:tcp://foo:bar@localhost:@@port@@"; + private static final String MILO_CLIENT_BASE_C2 = "milo-client:tcp://foo2:bar2@localhost:@@port@@"; private static final String MILO_CLIENT_ITEM_C1_1 = MILO_CLIENT_BASE_C1 + "?node=" + nodeValue(MiloServerComponent.DEFAULT_NAMESPACE_URI, "items-myitem1") + "&overrideHost=true"; diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/CallClientTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/CallClientTest.java index db70850..56ef9ee 100644 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/CallClientTest.java +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/CallClientTest.java @@ -18,34 +18,29 @@ package org.apache.camel.component.milo.call; import java.util.Arrays; import java.util.EnumSet; -import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; -import java.util.Set; import org.apache.camel.Produce; import org.apache.camel.ProducerTemplate; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.milo.AbstractMiloServerTest; -import org.apache.camel.component.milo.NodeIds; +import org.apache.camel.component.milo.call.MockCall.Call1; import org.eclipse.milo.opcua.sdk.server.OpcUaServer; import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig; import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfigBuilder; -import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil; -import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager; -import org.eclipse.milo.opcua.stack.core.security.InsecureCertificateValidator; +import org.eclipse.milo.opcua.sdk.server.identity.AnonymousIdentityValidator; +import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; +import org.eclipse.milo.opcua.stack.core.application.DefaultCertificateManager; +import org.eclipse.milo.opcua.stack.core.application.InsecureCertificateValidator; 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.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; -import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import static org.apache.camel.component.milo.NodeIds.nodeValue; -import static org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS; /** * Unit tests for calling from the client side @@ -54,27 +49,17 @@ public class CallClientTest extends AbstractMiloServerTest { private static final String DIRECT_START_1 = "direct:start1"; - private static final String MILO_CLIENT_BASE_C1 = "milo-client:opc.tcp://localhost:@@port@@"; + private static final String MILO_CLIENT_BASE_C1 = "milo-client:tcp://localhost:@@port@@"; - private static final String MILO_CLIENT_ITEM_C1_1 = MILO_CLIENT_BASE_C1 + "?node=" + NodeIds.nodeValue(MockCamelNamespace.URI, MockCamelNamespace.FOLDER_ID) - + "&method=" + nodeValue(MockCamelNamespace.URI, MockCamelNamespace.CALL_ID) + "&overrideHost=true"; - - private OpcUaServer server; - private MockCamelNamespace namespace; - private MockCallMethod callMethod; + private static final String MILO_CLIENT_ITEM_C1_1 = MILO_CLIENT_BASE_C1 + "?node=" + nodeValue(MockNamespace.URI, MockNamespace.FOLDER_ID) + "&method=" + + nodeValue(MockNamespace.URI, "id1") + "&overrideHost=true"; @Produce(DIRECT_START_1) - private ProducerTemplate producer1; + protected ProducerTemplate producer1; - @Override - protected RoutesBuilder createRouteBuilder() throws Exception { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - from(DIRECT_START_1).to(resolve(MILO_CLIENT_ITEM_C1_1)); - } - }; - } + private OpcUaServer server; + + private Call1 call1; @Override protected boolean isAddServer() { @@ -83,75 +68,43 @@ public class CallClientTest extends AbstractMiloServerTest { @Before public void start() throws Exception { - final OpcUaServerConfigBuilder cfg = OpcUaServerConfig.builder(); - - cfg.setCertificateManager(new DefaultCertificateManager()); - cfg.setEndpoints(createEndpointConfigurations(Arrays.asList(OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS), EnumSet.of(SecurityPolicy.None))); - cfg.setApplicationName(LocalizedText.english("Apache Camel Milo Server")); - cfg.setApplicationUri("urn:mock:namespace"); - cfg.setProductUri("urn:org:apache:camel:milo"); - cfg.setCertificateManager(new DefaultCertificateManager()); - cfg.setCertificateValidator(new InsecureCertificateValidator()); - - this.server = new OpcUaServer(cfg.build()); + final OpcUaServerConfigBuilder config = new OpcUaServerConfigBuilder(); + config.setBindAddresses(Arrays.asList("localhost")); + config.setBindPort(getServerPort()); + config.setIdentityValidator(AnonymousIdentityValidator.INSTANCE); + config.setUserTokenPolicies(Arrays.asList(OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS)); + config.setSecurityPolicies(EnumSet.of(SecurityPolicy.None)); + config.setCertificateManager(new DefaultCertificateManager()); + config.setCertificateValidator(new InsecureCertificateValidator()); - this.namespace = new MockCamelNamespace(this.server, node -> callMethod = new MockCallMethod(node)); - this.namespace.startup(); - this.server.startup().get(); - } + this.server = new OpcUaServer(config.build()); - private Set<EndpointConfiguration> createEndpointConfigurations(List<UserTokenPolicy> userTokenPolicies, Set<SecurityPolicy> securityPolicies) { - Set<EndpointConfiguration> endpointConfigurations = new LinkedHashSet<>(); + this.call1 = new MockCall.Call1(); - String bindAddress = "0.0.0.0"; - Set<String> hostnames = new LinkedHashSet<>(); - hostnames.add(HostnameUtil.getHostname()); - hostnames.addAll(HostnameUtil.getHostnames(bindAddress)); + this.server.getNamespaceManager().registerAndAdd(MockNamespace.URI, index -> { - UserTokenPolicy[] tokenPolicies = new UserTokenPolicy[] {USER_TOKEN_POLICY_ANONYMOUS}; + final List<UaMethodNode> methods = new LinkedList<>(); + methods.add(MockCall.fromNode(index, this.server.getNodeMap(), "id1", "name1", this.call1)); - for (String hostname : hostnames) { - EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder() - .setBindAddress(bindAddress) - .setHostname(hostname) - .setCertificate(() -> null) - .addTokenPolicies(tokenPolicies); + return new MockNamespace(index, this.server, methods); + }); + this.server.startup().get(); + } - if (securityPolicies == null || securityPolicies.contains(SecurityPolicy.None)) { - EndpointConfiguration.Builder noSecurityBuilder = builder.copy() - .setSecurityPolicy(SecurityPolicy.None) - .setSecurityMode(MessageSecurityMode.None); - - endpointConfigurations.add(buildTcpEndpoint(noSecurityBuilder)); - } - /* - * It's good practice to provide a discovery-specific endpoint with no security. - * It's required practice if all regular endpoints have security configured. - * - * Usage of the "/discovery" suffix is defined by OPC UA Part 6: - * - * Each OPC UA Server Application implements the Discovery Service Set. If the OPC UA Server requires a - * different address for this Endpoint it shall create the address by appending the path "/discovery" to - * its base address. - */ - - EndpointConfiguration.Builder discoveryBuilder = builder.copy() - .setPath("/discovery") - .setSecurityPolicy(SecurityPolicy.None) - .setSecurityMode(MessageSecurityMode.None); - - endpointConfigurations.add(buildTcpEndpoint(discoveryBuilder)); - } - - return endpointConfigurations; + @After + public void stop() { + this.server.shutdown(); } - private EndpointConfiguration buildTcpEndpoint(EndpointConfiguration.Builder base) { - return base.copy() - .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) - .setBindPort(getServerPort()) - .build(); + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from(DIRECT_START_1).to(resolve(MILO_CLIENT_ITEM_C1_1)); + } + }; } @Test @@ -162,8 +115,8 @@ public class CallClientTest extends AbstractMiloServerTest { doCall(this.producer1, "bar"); // assert - Assert.assertNotNull(this.callMethod); - Assert.assertArrayEquals(new Object[] {"out-foo", "out-bar"}, this.callMethod.getCalls().toArray()); + + Assert.assertArrayEquals(new Object[] {"foo", "bar"}, this.call1.calls.toArray()); } private static void doCall(final ProducerTemplate producerTemplate, final Object input) { diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCall.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCall.java new file mode 100644 index 0000000..51408c2 --- /dev/null +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCall.java @@ -0,0 +1,71 @@ +/* + * 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.milo.call; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.milo.opcua.sdk.server.annotations.UaInputArgument; +import org.eclipse.milo.opcua.sdk.server.annotations.UaMethod; +import org.eclipse.milo.opcua.sdk.server.annotations.UaOutputArgument; +import org.eclipse.milo.opcua.sdk.server.api.ServerNodeMap; +import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; +import org.eclipse.milo.opcua.sdk.server.util.AnnotationBasedInvocationHandler; +import org.eclipse.milo.opcua.sdk.server.util.AnnotationBasedInvocationHandler.InvocationContext; +import org.eclipse.milo.opcua.sdk.server.util.AnnotationBasedInvocationHandler.Out; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; + +import static org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText.english; + +public final class MockCall { + + private MockCall() { + } + + // in: str1[String], out: out1[String] + public static class Call1 { + + public List<String> calls = new LinkedList<>(); + + @UaMethod + public void call(final InvocationContext context, @UaInputArgument(name = "in1") + final String in1, @UaOutputArgument(name = "out1") + final Out<String> out1) { + this.calls.add(in1); + out1.set("out-" + in1); + } + } + + public static UaMethodNode fromNode(final UShort index, final ServerNodeMap nodeMap, final String nodeId, final String name, final Object methodObject) { + + try { + final UaMethodNode method = new UaMethodNode(nodeMap, new NodeId(index, nodeId), new QualifiedName(index, name), english(name), english(nodeId), UInteger.MIN, + UInteger.MIN, true, true); + + final AnnotationBasedInvocationHandler handler = AnnotationBasedInvocationHandler.fromAnnotatedObject(nodeMap, methodObject); + method.setInputArguments(handler.getInputArguments()); + method.setOutputArguments(handler.getOutputArguments()); + method.setInvocationHandler(handler); + return method; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCallMethod.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCallMethod.java deleted file mode 100644 index fe52c8c..0000000 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCallMethod.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.milo.call; - -import java.util.LinkedList; -import java.util.List; - -import org.eclipse.milo.opcua.sdk.core.ValueRanks; -import org.eclipse.milo.opcua.sdk.server.api.methods.AbstractMethodInvocationHandler; -import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; -import org.eclipse.milo.opcua.stack.core.Identifiers; -import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; -import org.eclipse.milo.opcua.stack.core.types.structured.Argument; - -public class MockCallMethod extends AbstractMethodInvocationHandler { - - public static final Argument IN = new Argument( - "in", - Identifiers.String, - ValueRanks.Scalar, - null, - new LocalizedText("A value.") - ); - - public static final Argument OUT = new Argument( - "out", - Identifiers.String, - ValueRanks.Scalar, - null, - new LocalizedText("A value.") - ); - - public List<String> calls = new LinkedList<>(); - - public MockCallMethod(UaMethodNode node) { - super(node); - } - - @Override - public Argument[] getInputArguments() { - return new Argument[]{IN}; - } - - @Override - public Argument[] getOutputArguments() { - return new Argument[]{OUT}; - } - - @Override - protected Variant[] invoke(InvocationContext invocationContext, Variant[] inputValues) { - String in = (String) inputValues[0].getValue(); - - calls.add("out-" + in); - - return new Variant[]{new Variant("out-" + in)}; - } - - public List<String> getCalls() { - return calls; - } -} diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCamelNamespace.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCamelNamespace.java deleted file mode 100644 index 3197485..0000000 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCamelNamespace.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.milo.call; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import org.apache.camel.component.milo.client.MiloClientConsumer; -import org.apache.camel.component.milo.server.internal.CamelServerItem; -import org.eclipse.milo.opcua.sdk.core.Reference; -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.api.DataItem; -import org.eclipse.milo.opcua.sdk.server.api.ManagedNamespace; -import org.eclipse.milo.opcua.sdk.server.api.MonitoredItem; -import org.eclipse.milo.opcua.sdk.server.api.methods.AbstractMethodInvocationHandler; -import org.eclipse.milo.opcua.sdk.server.nodes.UaFolderNode; -import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; -import org.eclipse.milo.opcua.sdk.server.util.SubscriptionModel; -import org.eclipse.milo.opcua.stack.core.Identifiers; -import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; -import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MockCamelNamespace extends ManagedNamespace { - - public static final String URI = "urn:org:apache:camel:mock"; - public static final int FOLDER_ID = 1; - public static final int CALL_ID = 2; - - private static final Logger LOG = LoggerFactory.getLogger(MiloClientConsumer.class); - - private final SubscriptionModel subscriptionModel; - - private final Function<UaMethodNode, AbstractMethodInvocationHandler> callMethodCreator; - - private UaFolderNode folder; - - private final Map<String, CamelServerItem> itemMap = new HashMap<>(); - - public MockCamelNamespace(final OpcUaServer server, Function<UaMethodNode, AbstractMethodInvocationHandler> callMethodCreator) { - super(server, URI); - - this.subscriptionModel = new SubscriptionModel(server, this); - this.callMethodCreator = callMethodCreator; - } - - @Override - protected void onStartup() { - super.onStartup(); - // create structure - - final NodeId nodeId = newNodeId(FOLDER_ID); - final QualifiedName name = newQualifiedName("camel"); - final LocalizedText displayName = LocalizedText.english("Camel"); - - this.folder = new UaFolderNode(getNodeContext(), nodeId, name, displayName); - getNodeManager().addNode(this.folder); - - // register reference to structure - - folder.addReference(new Reference( - folder.getNodeId(), - Identifiers.Organizes, - Identifiers.ObjectsFolder.expanded(), - false - )); - - addCallMethod(folder); - } - - private void addCallMethod(UaFolderNode folderNode) { - UaMethodNode methodNode = UaMethodNode.builder(getNodeContext()) - .setNodeId(new NodeId(getNamespaceIndex(), CALL_ID)) - .setBrowseName(newQualifiedName("call")) - .setDisplayName(new LocalizedText(null, "call")) - .setDescription( - LocalizedText.english("Returns the \"out-\"+entry parameter")) - .build(); - - AbstractMethodInvocationHandler callMethod = callMethodCreator.apply(methodNode); - methodNode.setProperty(UaMethodNode.InputArguments, callMethod.getInputArguments()); - methodNode.setProperty(UaMethodNode.OutputArguments, callMethod.getOutputArguments()); - methodNode.setInvocationHandler(callMethod); - - getNodeManager().addNode(methodNode); - - methodNode.addReference(new Reference( - methodNode.getNodeId(), - Identifiers.HasComponent, - folderNode.getNodeId().expanded(), - false - )); - - methodNode.addReference(new Reference( - methodNode.getNodeId(), - Identifiers.HasComponent, - folderNode.getNodeId().expanded(), - folderNode.getNodeClass(), - false - )); - } - - - @Override - public void onDataItemsCreated(final List<DataItem> dataItems) { - this.subscriptionModel.onDataItemsCreated(dataItems); - } - - @Override - public void onDataItemsModified(final List<DataItem> dataItems) { - this.subscriptionModel.onDataItemsModified(dataItems); - } - - @Override - public void onDataItemsDeleted(final List<DataItem> dataItems) { - this.subscriptionModel.onDataItemsDeleted(dataItems); - } - - @Override - public void onMonitoringModeChanged(final List<MonitoredItem> monitoredItems) { - this.subscriptionModel.onMonitoringModeChanged(monitoredItems); - } -} diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockNamespace.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockNamespace.java new file mode 100644 index 0000000..1acd8de --- /dev/null +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockNamespace.java @@ -0,0 +1,176 @@ +/* + * 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.milo.call; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.core.Reference; +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.api.AccessContext; +import org.eclipse.milo.opcua.sdk.server.api.DataItem; +import org.eclipse.milo.opcua.sdk.server.api.MethodInvocationHandler; +import org.eclipse.milo.opcua.sdk.server.api.MonitoredItem; +import org.eclipse.milo.opcua.sdk.server.api.Namespace; +import org.eclipse.milo.opcua.sdk.server.api.ServerNodeMap; +import org.eclipse.milo.opcua.sdk.server.model.nodes.objects.FolderNode; +import org.eclipse.milo.opcua.sdk.server.nodes.AttributeContext; +import org.eclipse.milo.opcua.sdk.server.nodes.ServerNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaFolderNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; +import org.eclipse.milo.opcua.sdk.server.util.SubscriptionModel; +import org.eclipse.milo.opcua.stack.core.Identifiers; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; +import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; + +import static java.util.stream.Collectors.toList; + +public class MockNamespace implements Namespace { + + public static final int FOLDER_ID = 1; + + public static final String URI = "urn:mock:namespace"; + + private final UShort index; + + private final ServerNodeMap nodeMap; + private final SubscriptionModel subscriptionModel; + + public MockNamespace(final UShort index, final OpcUaServer server, List<UaMethodNode> methods) { + this.index = index; + this.nodeMap = server.getNodeMap(); + this.subscriptionModel = new SubscriptionModel(server, this); + + registerItems(methods); + } + + private void registerItems(List<UaMethodNode> methods) { + + // create a folder + + final UaFolderNode folder = new UaFolderNode(this.nodeMap, new NodeId(this.index, FOLDER_ID), new QualifiedName(this.index, "FooBarFolder"), + LocalizedText.english("Foo Bar Folder")); + + // add our folder to the objects folder + + this.nodeMap.getNode(Identifiers.ObjectsFolder).ifPresent(node -> { + ((FolderNode)node).addComponent(folder); + }); + + // add method calls + + methods.forEach(folder::addComponent); + } + + // default method implementations follow + + @Override + public void read(final ReadContext context, final Double maxAge, final TimestampsToReturn timestamps, final List<ReadValueId> readValueIds) { + + final List<DataValue> results = new ArrayList<>(readValueIds.size()); + + for (final ReadValueId id : readValueIds) { + final ServerNode node = this.nodeMap.get(id.getNodeId()); + + final DataValue value = node != null ? node.readAttribute(new AttributeContext(context), id.getAttributeId()) : new DataValue(StatusCodes.Bad_NodeIdUnknown); + + results.add(value); + } + + // report back with result + + context.complete(results); + } + + @Override + public void write(final WriteContext context, final List<WriteValue> writeValues) { + + final List<StatusCode> results = writeValues.stream().map(value -> { + if (this.nodeMap.containsKey(value.getNodeId())) { + return new StatusCode(StatusCodes.Bad_NotWritable); + } else { + return new StatusCode(StatusCodes.Bad_NodeIdUnknown); + } + }).collect(toList()); + + // report back with result + + context.complete(results); + } + + @Override + public CompletableFuture<List<Reference>> browse(final AccessContext context, final NodeId nodeId) { + final ServerNode node = this.nodeMap.get(nodeId); + + if (node != null) { + return CompletableFuture.completedFuture(node.getReferences()); + } else { + final CompletableFuture<List<Reference>> f = new CompletableFuture<>(); + f.completeExceptionally(new UaException(StatusCodes.Bad_NodeIdUnknown)); + return f; + } + } + + @Override + public Optional<MethodInvocationHandler> getInvocationHandler(final NodeId methodId) { + return Optional.ofNullable(this.nodeMap.get(methodId)).filter(n -> n instanceof UaMethodNode).flatMap(n -> { + final UaMethodNode m = (UaMethodNode)n; + return m.getInvocationHandler(); + }); + } + + @Override + public void onDataItemsCreated(final List<DataItem> dataItems) { + this.subscriptionModel.onDataItemsCreated(dataItems); + } + + @Override + public void onDataItemsModified(final List<DataItem> dataItems) { + this.subscriptionModel.onDataItemsModified(dataItems); + } + + @Override + public void onDataItemsDeleted(final List<DataItem> dataItems) { + this.subscriptionModel.onDataItemsDeleted(dataItems); + } + + @Override + public void onMonitoringModeChanged(final List<MonitoredItem> monitoredItems) { + this.subscriptionModel.onMonitoringModeChanged(monitoredItems); + } + + @Override + public UShort getNamespaceIndex() { + return this.index; + } + + @Override + public String getNamespaceUri() { + return URI; + } +} diff --git a/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetCertificateManagerTest.java b/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetCertificateManagerTest.java index f4ea7f4..fe58263 100644 --- a/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetCertificateManagerTest.java +++ b/components/camel-milo/src/test/java/org/apache/camel/component/milo/server/ServerSetCertificateManagerTest.java @@ -38,7 +38,7 @@ public class ServerSetCertificateManagerTest extends AbstractMiloServerTest { final Path trusted = baseDir.resolve("trusted"); Files.createDirectories(trusted); - Files.copy(Paths.get("src/test/resources/ca/cacert.pem"), trusted.resolve("cacert.pem"), REPLACE_EXISTING); + Files.copy(Paths.get("src/test/resources/cert/certificate.der"), trusted.resolve("certificate.der"), REPLACE_EXISTING); server.setServerCertificate(loadDefaultTestKey()); server.setDefaultCertificateValidator(baseDir.toFile()); diff --git a/components/camel-milo/src/test/resources/ca/cacert.pem b/components/camel-milo/src/test/resources/ca/cacert.pem deleted file mode 100644 index f23452c..0000000 --- a/components/camel-milo/src/test/resources/ca/cacert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFeTCCA2GgAwIBAgIJAIoc1wRX1g4hMA0GCSqGSIb3DQEBCwUAMEsxCzAJBgNV -BAYTAlJIMQswCQYDVQQIDAJSSDELMAkGA1UEBwwCUkgxEDAOBgNVBAoMB1Rlc3Qg -Q0ExEDAOBgNVBAMMB1Rlc3QgQ0EwHhcNMjAwMTI4MTYxNTA0WhcNMjAwMjI3MTYx -NTA0WjBLMQswCQYDVQQGEwJSSDELMAkGA1UECAwCUkgxCzAJBgNVBAcMAlJIMRAw -DgYDVQQKDAdUZXN0IENBMRAwDgYDVQQDDAdUZXN0IENBMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAvk1N3IMWVqJIlMuFkD2XiPiEPk5m7ToriB0ThNyY -IUKVayEoFOyU82ciycERJHVgo64BxQ3e4BqBakyarI4ssbiI6hm8onWzjCBPy5U+ -RQxK/oDoK3vn1uCQRKbdjkJvbbmbTVlWrpTGmNBflw+OlTGSswcWxc3q0KrKYmm0 -eGcvL6ZNy+ciTPXRyE7ccHR87yP+CIs8l4O4j5QavcIYH6PSHtMU6XUFIZGpj9vI -6PbKu2MPK1+QRL+zevf5Q3l5tdjHavh0NDW8QcCa/te7qc7gQvYttFzYMuzvNqeZ -OL3iCWJVKG5Atxo9JvSsb0IbDXqnGQrRqYoHwk64bT2Hs3G5pwBLSoO+HrKqfaS3 -c5KINGrfCVcfrKIHyA3l/RLIhlhzkxj1Mvq2sP8Jt0IfZNpXjBiXw6zH76Biozgq -gdTNypOz3an1OkfQRcsXjjaI/EKLxcTAV5DQR2++OI6eFfalVjbdmWCvOBOXa3tN -UtxACL/kNbjAegRzZTZyTy/uA1nj3E2FdDDGqUnxiNtXBVQ40s4xoi2w0sdWQ3ZL -ntLQ3NhLJw8UCCUMMQZEwghAeyXGqS7GuAszoPDBzjkJyI456sR8E5mapjwwVbMz -nCGfeEgNoRSMuAteJwS/nw2M9ApxgqYan+683cV2pIU8wGtkRzYxvRXMswKIBx83 -ksUCAwEAAaNgMF4wHQYDVR0OBBYEFOS5A19qy9nHzu0q5pXrpdT4vGXbMB8GA1Ud -IwQYMBaAFOS5A19qy9nHzu0q5pXrpdT4vGXbMA8GA1UdEwEB/wQFMAMBAf8wCwYD -VR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQBr3dLjF8MLJTGW92UejISaCLft -jqyXonrHLi3snrC2rW6OkGD35Mk+ylpuYHSzCl258P5W8J9A9snRgzL6pqXw2ZPB -GLjGyge4PKvzH25O8kCgAuvyNBPPDKMdhhMzaL1qsr8zveUIYxMtJMVZuzpYFD8u -2/MZQ6yf8PVVsnEPlrjg2ByUEiSBNAnmqC3zFnR90Zv2F8jQyhCZyZf/57lGDS4c -5ap8mFhwxY6gZbzv/LW8r13hT7QbGkgl6yildg1/+Ozn8RkRoYNcZ6r7Nl0Z6TL3 -Vs4vab0cuketxIdpzld5FW3b+DBjzpR1pdzGtnm3ultSBHD75vxBeKI3//K1Ar1G -U8NAuWIKEEOirhsm23XBowmwEcbKD8AlHjfZVDGs1kWvhdu09RY1BHYt0YBIbirE -g+F537+MUr5l934eQxIpOiHyJmiqNnfC4l9e4tUIKfX64yWoqu5davEIBI0x9mKe -Ug8uofPCm6U78S6jANauze6X9r8T8bDm56y9yztQXVf1mZxTgoHRspX6wt89YQVJ -VZzrWyRsMvPDGWevH809CHJaOFMjS23ffF5KML9Gzf/XShRQWCNkE85T55W8FgS0 -Kt0m9ZRPWEGulbsO85ETjssatI1xKKwRNOQIWdk625sci42PSgK/q8Avufe0rRbH -398+r4PDI8gaMQKG4A== ------END CERTIFICATE----- diff --git a/components/camel-milo/src/test/resources/cert/Makefile b/components/camel-milo/src/test/resources/cert/Makefile new file mode 100644 index 0000000..b44c850 --- /dev/null +++ b/components/camel-milo/src/test/resources/cert/Makefile @@ -0,0 +1,16 @@ +.PHONY: clean all show + +all: + openssl req -batch -x509 -sha256 -nodes -days 36500 \ + -subj '/C=XX/L=End of the universe/O=Milliways' \ + -config cert.ini \ + -newkey rsa:2048 -keyout privateKey.key -out certificate.crt + openssl pkcs12 -password pass:pwd1 -export -out cert.p12 -inkey privateKey.key -in certificate.crt + openssl x509 -outform der -in certificate.crt -out certificate.der + +show: + openssl x509 -in certificate.crt -text -noout + +clean: + @-rm privateKey.key certificate.crt cert.p12 certificate.der + diff --git a/components/camel-milo/src/test/resources/cert/cert.ini b/components/camel-milo/src/test/resources/cert/cert.ini new file mode 100644 index 0000000..7eaaed2 --- /dev/null +++ b/components/camel-milo/src/test/resources/cert/cert.ini @@ -0,0 +1,13 @@ +[req] +x509_extensions = v3_req +distinguished_name = req_distinguished_name + +[req_distinguished_name] + +[v3_req] +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment +subjectAltName = @alt_names + +[alt_names] +URI.1 = http://camel.apache.org/EclipseMilo/Client diff --git a/components/camel-milo/src/test/resources/cert/cert.p12 b/components/camel-milo/src/test/resources/cert/cert.p12 new file mode 100644 index 0000000..8a2eed9 Binary files /dev/null and b/components/camel-milo/src/test/resources/cert/cert.p12 differ diff --git a/components/camel-milo/src/test/resources/cert/certificate.crt b/components/camel-milo/src/test/resources/cert/certificate.crt new file mode 100644 index 0000000..8b7c784 --- /dev/null +++ b/components/camel-milo/src/test/resources/cert/certificate.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIJAKvxBeV3q1AsMA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV +BAYTAlhYMRwwGgYDVQQHExNFbmQgb2YgdGhlIHVuaXZlcnNlMRIwEAYDVQQKEwlN +aWxsaXdheXMwIBcNMTYwNzIxMTMyODAwWhgPMjExNjA2MjcxMzI4MDBaMD8xCzAJ +BgNVBAYTAlhYMRwwGgYDVQQHExNFbmQgb2YgdGhlIHVuaXZlcnNlMRIwEAYDVQQK +EwlNaWxsaXdheXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDYISUG +ggjH/3KuUHLjUvDWNomCDzMqTA4QrlK0cxt0VZq0DmzP1xEtAhXJ6eXVsBsfbvzW +F/AK1otAP67wsGz52edbzchW0TVvKd3CAKBH8LFgycu7k6bYdc+0crgyxeM1NUmC +x1nxbfTMWSC1CWOzjZXOVlqyUIHY8HJetPpJpS0GizAfa+eCHaRXOyC89dUX0cS8 +370NbcqfrYvbd8LOosHLYqJ/x7P7YIxOkw/wn5m2OAeSfItqfNCLbR2+oiCrLLv0 +MXQVCiiYfPLoEePFb288/AkgI/1go4Lsh6/vBnTU03r/YKM1QHVxygax3+I/9cXp +wNmV8HyDNo5Lu98bAgMBAAGjUTBPMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMDUG +A1UdEQQuMCyGKmh0dHA6Ly9jYW1lbC5hcGFjaGUub3JnL0VjbGlwc2VNaWxvL0Ns +aWVudDANBgkqhkiG9w0BAQsFAAOCAQEAWplx3EQyl69Xrn73v55sPa8mlBKMjjJ3 +FmloVkUoYO8k8xciPDRHSVaeKYwU3dO4NBwPnbo0JMZWEaYr9SsVWbLRsfqu3pGt +ScHp7n1GB8gkstoX3cuqzVF0UQCkSsfUNXGCfQVQbQwJg8hBU77WTflDbcrGMbxf +PgTkwOv8qfNjPawu4j05/9SKoauKoNVQ1nHS7D3tkzoPxh+0efOhrhOPXtB/C9yH +QKIMFzsh0uLlzNZiMURjTZo/asZ9RdCplUzd3ciQDZk6QxW8DIrOfySUMuWU1UDa +1/qA0w7xg+1azBRl3oiUwNxOmHHVeWqonhbvYlG+GG/MjQHcg62NHg== +-----END CERTIFICATE----- diff --git a/components/camel-milo/src/test/resources/cert/certificate.der b/components/camel-milo/src/test/resources/cert/certificate.der new file mode 100644 index 0000000..37abde7 Binary files /dev/null and b/components/camel-milo/src/test/resources/cert/certificate.der differ diff --git a/components/camel-milo/src/test/resources/cert/privateKey.key b/components/camel-milo/src/test/resources/cert/privateKey.key new file mode 100644 index 0000000..5900120 --- /dev/null +++ b/components/camel-milo/src/test/resources/cert/privateKey.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDYISUGggjH/3Ku +UHLjUvDWNomCDzMqTA4QrlK0cxt0VZq0DmzP1xEtAhXJ6eXVsBsfbvzWF/AK1otA +P67wsGz52edbzchW0TVvKd3CAKBH8LFgycu7k6bYdc+0crgyxeM1NUmCx1nxbfTM +WSC1CWOzjZXOVlqyUIHY8HJetPpJpS0GizAfa+eCHaRXOyC89dUX0cS8370Nbcqf +rYvbd8LOosHLYqJ/x7P7YIxOkw/wn5m2OAeSfItqfNCLbR2+oiCrLLv0MXQVCiiY +fPLoEePFb288/AkgI/1go4Lsh6/vBnTU03r/YKM1QHVxygax3+I/9cXpwNmV8HyD +No5Lu98bAgMBAAECggEBAJdMLJUvtmH7axan7qVATKRIrV5EsbasYzQ+NFtqMQ/x +VUkyx+1/SuDNEt+0Q1ah33rTwV9Ghp2vru+dJSQM/VyytAlKNzK/Zb6Z+klzEsEJ +t8JfwaVgKW5imrJhlJzGdtWqpflNAKPIK5RZ2FGjbw4k0XgOb5NgVGW/fPDblFK0 +ar1Yc/FLWOYFWFfNoZhni+ZH4U2KmEjZlkIL+d4KgewrjSPJ9w6XJijxMD5eDc5+ +r1ZfaSz5RNM/5LWokqLajCuxBxohRXldgF3Y3UtuQipeok1RPmQb0UcPSz7zndHF +BV90c3o09v0/aqp2USlzCABIHO0l5Qru9m5wtvI+L/ECgYEA+TaweFBy6vGLa1jU +hr8vaED880KNu6bIfHfmT580cG8ZXdz/+JHup+lERQmjuEX9Jc6QO2AUVsn1bZ8P +oxs/4kNKL3cYZ/r66cBSSu0xihXsFAvDm4rrwSI5IAzOioMxBVs65sicpaceunHP +l+c7Ma2cEUnlwYVuRAXhy1jjVhcCgYEA3gPR6q1lYgYsm8alOUzy/Eexp8PMbpgE +t6c5eyT4Swau9XkNxp5R/tLCMvuZxwplZauChpE7O1TTiu88vrqRVVl4fZVkIlnx +/xzzQFuAny/Qx+FOU18gNhFCRn4aAs5k+wdOncCIonz3IhMcusruseorBw57DLil +TNlLZtQPZZ0CgYEAtUiEHDEhNyiX63GFv7MpUCQeHPJn2X4cTvaFEZxU8AjRIgdW +KEI3oes8nx/A+ZXn7O2S264rfWqR3rkbDeIPmY6rU1XF6jWW+hzNf/WE2NbTkU1x +cB8hGa/EcD0ArZ97NFNFyIVb9eBYqPWLNgudcqjAY48m05w1NsQ0mNBDJucCgYAP +JWWRxAiRmmg6rF+jPBurmFyHXHU66kYQHWlvfEMwIyGWf46wCScA4nH7Nmz0RkJK +oFvEQG4xCwVvigiz3liB4Ru2PZXaPhajV99EebmZopJ0wGsuhuPUrHLACmRN4rTC +52m2m2b25t2ZRoKEP8nu+1G6JoPAh2xHhN9/AWKXhQKBgQDFmIUZwFmb3+oYgEN5 +QVmiwHgy9+AX+atZ76N3oajF42w3SFTLO9yQ5dlb9nBfwzpraZn2T9fAyiP0a9iU +A9Y5MUFWlqMfgeOK/HEprcA7/Wth8ou3iu6Ojn85Iy2VqmqA4OYUYQTsS6izus4W +Eel2uEuwhoIseSX1F0tqMlwxVg== +-----END PRIVATE KEY----- diff --git a/components/camel-milo/src/test/resources/keystore b/components/camel-milo/src/test/resources/keystore deleted file mode 100644 index ef6d68f..0000000 Binary files a/components/camel-milo/src/test/resources/keystore and /dev/null differ diff --git a/components/camel-milo/src/test/resources/openssl-ca.cnf b/components/camel-milo/src/test/resources/openssl-ca.cnf deleted file mode 100644 index bd29e0e..0000000 --- a/components/camel-milo/src/test/resources/openssl-ca.cnf +++ /dev/null @@ -1,80 +0,0 @@ -HOME = . -RANDFILE = $ENV::HOME/.rnd - -#################################################################### -[ ca ] -default_ca = CA_default # The default ca section - -[ CA_default ] - -default_days = 1000 # How long to certify for -default_crl_days = 30 # How long before next CRL -default_md = sha256 # Use public key default MD -preserve = no # Keep passed DN ordering - -x509_extensions = ca_extensions # The extensions to add to the cert - -email_in_dn = no # Don't concat the email in the DN -copy_extensions = copy # Required to copy SANs from CSR to cert - -base_dir = . -certificate = $base_dir/ca/cacert.pem # The CA certifcate -private_key = $base_dir/ca/cakey.pem # The CA private key -new_certs_dir = $base_dir/cert # Location for new certs after signing -database = $base_dir/ca/index.txt # Database index file -serial = $base_dir/ca/serial.txt # The current serial number - -unique_subject = no # Set to 'no' to allow creation of - # several certificates with same subject. - -#################################################################### -[ req ] -default_bits = 4096 -default_keyfile = ca/cakey.pem -distinguished_name = ca_distinguished_name -x509_extensions = ca_extensions -string_mask = utf8only - -#################################################################### -[ ca_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = RH - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = RH - -localityName = Locality Name (eg, city) -localityName_default = RH - -organizationName = Organization Name (eg, company) -organizationName_default = Test CA - -commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_default = Test CA - -#################################################################### -[ ca_extensions ] - -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always, issuer -basicConstraints = critical, CA:true -keyUsage = keyCertSign, cRLSign - -#################################################################### -[ signing_policy ] -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -#################################################################### -[ signing_req ] -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment - -#openssl pkcs12 -export -in servercert.pem -inkey serverkey.pem -certfile cacert.pem -name "test" -out keystore.p12 -passout pass:test diff --git a/components/camel-milo/src/test/resources/openssl-server.cnf b/components/camel-milo/src/test/resources/openssl-server.cnf deleted file mode 100644 index dd3cd0e..0000000 --- a/components/camel-milo/src/test/resources/openssl-server.cnf +++ /dev/null @@ -1,39 +0,0 @@ -HOME = . -RANDFILE = $ENV::HOME/.rnd - -#################################################################### -[ req ] -default_bits = 2048 -default_keyfile = cert/serverkey.pem -distinguished_name = server_distinguished_name -req_extensions = server_req_extensions -string_mask = utf8only - -#################################################################### -[ server_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = RH - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = RH - -localityName = Locality Name (eg, city) -localityName_default = RH - -commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_default = milo-test - - -#################################################################### -[ server_req_extensions ] - -subjectKeyIdentifier = hash -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment -subjectAltName = @alternate_names -nsComment = "OpenSSL Generated Certificate" - -#################################################################### -[ alternate_names ] - -URI.1 = http://camel.apache.org/EclipseMilo/Client diff --git a/components/camel-milo/src/test/resources/run.sh b/components/camel-milo/src/test/resources/run.sh deleted file mode 100755 index a6d1620..0000000 --- a/components/camel-milo/src/test/resources/run.sh +++ /dev/null @@ -1,21 +0,0 @@ -# script which prepares all needed certificates and keystore -# properties of certificates has to be confirmed -# password to be filled in the last step has to be 'test' - -mkdir cert -mkdir ca - -#generate ca certificate and key -openssl req -x509 -config openssl-ca.cnf -newkey rsa:4096 -sha256 -nodes -out ca/cacert.pem -outform PEM - -#generate csr -openssl req -config openssl-server.cnf -newkey rsa:2048 -sha256 -nodes -out cert/servercert.csr -outform PEM - -#sign -touch ca/index.txt -echo '01' > ca/serial.txt -openssl ca -config openssl-ca.cnf -policy signing_policy -extensions signing_req -out cert/servercert.pem -infiles cert/servercert.csr - -#import into keystore -openssl pkcs12 -export -in cert/servercert.pem -inkey cert/serverkey.pem -certfile ca/cacert.pem -name "test" -out keystore.p12 -passout pass:test -keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore -deststoretype JKS -storepass testtest diff --git a/docs/components/modules/ROOT/pages/milo-client-component.adoc b/docs/components/modules/ROOT/pages/milo-client-component.adoc index 3517f7e..634f914 100644 --- a/docs/components/modules/ROOT/pages/milo-client-component.adoc +++ b/docs/components/modules/ROOT/pages/milo-client-component.adoc @@ -11,9 +11,6 @@ The Milo Client component provides access to OPC UA servers using the http://eclipse.org/milo[Eclipse Milo™] implementation. -*Important*: To successfully use certificates for secured communication, -JCE Jurisdiction Policy File Default has to be *Unlimited* (which is by default since jdk 9+). - Maven users will need to add the following dependency to their `pom.xml` for this component: @@ -56,13 +53,13 @@ The URI syntax of the endpoint is: [source] ------------------------ -milo-client:opc.tcp://[user:password@]host:port/path/to/service?node=RAW(nsu=urn:foo:bar;s=item-1) +milo-client:tcp://[user:password@]host:port/path/to/service?node=RAW(nsu=urn:foo:bar;s=item-1) ------------------------ If the server does not use a path, then it is possible to simply omit it: ------------------------ -milo-client:opc.tcp://[user:password@]host:port?node=RAW(nsu=urn:foo:bar;s=item-1) +milo-client:tcp://[user:password@]host:port?node=RAW(nsu=urn:foo:bar;s=item-1) ------------------------ If no user credentials are provided the client will switch to anonymous mode. @@ -243,7 +240,7 @@ As the values generated by the syntax cannot be transparently encoded into a URI However Camel allows to wrap the actual value inside `RAW(…)`, which makes escaping unnecessary. For example: ------------------------ -milo-client:opc.tcp://user:password@localhost:12345?node=RAW(nsu=http://foo.bar;s=foo/bar) +milo-client:tcp://user:password@localhost:12345?node=RAW(nsu=http://foo.bar;s=foo/bar) ------------------------ === Method ID diff --git a/docs/components/modules/ROOT/pages/milo-server-component.adoc b/docs/components/modules/ROOT/pages/milo-server-component.adoc index 072675e..861c31c 100644 --- a/docs/components/modules/ROOT/pages/milo-server-component.adoc +++ b/docs/components/modules/ROOT/pages/milo-server-component.adoc @@ -31,7 +31,7 @@ Value write requests from OPC UA Client will trigger messages which are sent int // component options: START -The OPC UA Server component supports 20 options, which are listed below. +The OPC UA Server component supports 22 options, which are listed below. @@ -40,10 +40,12 @@ The OPC UA Server component supports 20 options, which are listed below. | Name | Description | Default | Type | *namespaceUri* (common) | The URI of the namespace, defaults to urn:org:apache:camel | | String | *applicationName* (common) | The application name | | String -| *path* (common) | The path to be appended to the end of the endpoint url. (doesn't need to start with '/') | | String | *applicationUri* (common) | The application URI | | String | *productUri* (common) | The product URI | | String | *bindPort* (common) | The TCP port the server binds to | | int +| *strictEndpointUrlsEnabled* (common) | Set whether strict endpoint URLs are enforced | false | boolean +| *serverName* (common) | Server name | | String +| *hostname* (common) | Server hostname | | String | *securityPolicies* (common) | Security policies | | Set | *securityPoliciesById* (common) | Security policies by URI or name | | Collection | *userAuthenticationCredentials* (common) | Set user password combinations in the form of user1:pwd1,user2:pwd2 Usernames and passwords will be URL decoded | | String diff --git a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc index 4f75f8b..33abb55 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc @@ -41,27 +41,6 @@ The `camel-irc` component has changed its endpoint syntax and removed option #ro irc:nick@host[:port]?[options] ---- -=== camel-milo - -The `camel-milo` client component has changed its endpoint syntax from `milo-client:tcp` to `milo-client:opc.tcp`. -For example before - -[source,text] ----- -milo-client:tcp://foo:bar@localhost:1234 ----- - -Should be changed to ----- -milo-client:opc.tcp://foo:bar@localhost:1234 ----- - -The `camel-milo` server component requires Java 9 at runtime. -Property `strictEndpointUrlsEnabled` is no longer supported. -Properties`hostName` and `serverName` are replaced by `path`. -To successfully use certificates for secured communication, JCE Jurisdiction Policy File Default -has to be *Unlimited* (which is by default since Java 9+). - === camel-nats The `camel-nats` component has changed its endpoint syntax from `nats:servers` to `nats:topic`. diff --git a/parent/pom.xml b/parent/pom.xml index 1cb3e58..c86d053 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -164,8 +164,6 @@ <derby-version>10.14.2.0</derby-version> <digitalocean-api-client-version>2.17</digitalocean-api-client-version> <digitalocean-api-client-bundle-version>2.17_1</digitalocean-api-client-bundle-version> - <digitalpetri-fsm-client>0.2</digitalpetri-fsm-client> - <digitalpetri-netty-client>0.3</digitalpetri-netty-client> <directory-watcher-version>0.9.9</directory-watcher-version> <disruptor-version>3.4.2</disruptor-version> <dnsjava-version>2.1.9</dnsjava-version> @@ -460,8 +458,7 @@ <microprofile-config-version>1.3</microprofile-config-version> <microprofile-metrics-version>2.2.1</microprofile-metrics-version> <microprofile-health-version>2.1</microprofile-health-version> - <milo-version>0.3.7</milo-version> - <milo-guava-version>26.0-jre</milo-guava-version> + <milo-version>0.2.5</milo-version> <mimepull-version>1.9.12</mimepull-version> <mina-version>2.1.3</mina-version> <minidns-version>0.3.4</minidns-version> diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml index ae3b5e9..a183476 100644 --- a/platforms/karaf/features/src/main/resources/features.xml +++ b/platforms/karaf/features/src/main/resources/features.xml @@ -1750,26 +1750,19 @@ <bundle dependency='true'>mvn:org.jooq/jool/${jool-version}</bundle> <bundle dependency='true'>mvn:com.google.code.findbugs/jsr305/${google-findbugs-jsr305-version}</bundle> <bundle dependency='true'>mvn:com.google.code.findbugs/annotations/${google-findbugs-annotations2-version}</bundle> - <bundle dependency='true'>mvn:org.bouncycastle/bcprov-jdk15on/${bouncycastle-version}</bundle> - <bundle dependency='true'>mvn:org.bouncycastle/bcpkix-jdk15on/${bouncycastle-version}</bundle> - <bundle dependency='true'>mvn:org.bouncycastle/bcmail-jdk15on/${bouncycastle-version}</bundle> - <bundle dependency='true'>mvn:io.netty/netty-common/${netty-version}</bundle> - <bundle dependency='true'>mvn:io.netty/netty-buffer/${netty-version}</bundle> - <bundle dependency='true'>mvn:io.netty/netty-resolver/${netty-version}</bundle> - <bundle dependency='true'>mvn:io.netty/netty-transport/${netty-version}</bundle> - <bundle dependency='true'>mvn:io.netty/netty-handler/${netty-version}</bundle> - <bundle dependency='true'>mvn:io.netty/netty-codec/${netty-version}</bundle> - <bundle dependency='true'>mvn:io.netty/netty-codec-http/${netty-version}</bundle> - <bundle dependency='true'>wrap:mvn:com.digitalpetri.fsm/strict-machine/${digitalpetri-fsm-client}</bundle> - <bundle dependency='true'>wrap:mvn:com.digitalpetri.netty/netty-channel-fsm/${digitalpetri-netty-client}</bundle> - <bundle dependency='true'>mvn:com.google.guava/guava/${milo-guava-version}</bundle> + <bundle dependency='true'>mvn:io.netty/netty-common/${netty40-version}</bundle> + <bundle dependency='true'>mvn:io.netty/netty-buffer/${netty40-version}</bundle> + <bundle dependency='true'>mvn:io.netty/netty-handler/${netty40-version}</bundle> + <bundle dependency='true'>mvn:io.netty/netty-transport/${netty40-version}</bundle> + <bundle dependency='true'>mvn:io.netty/netty-codec/${netty40-version}</bundle> + <bundle dependency='true'>mvn:com.google.guava/guava/${google-guava-version}</bundle> <bundle dependency='true'>mvn:org.eclipse.milo/stack-core/${milo-version}</bundle> <bundle dependency='true'>mvn:org.eclipse.milo/stack-server/${milo-version}</bundle> <bundle dependency='true'>mvn:org.eclipse.milo/stack-client/${milo-version}</bundle> <bundle dependency='true'>mvn:org.eclipse.milo/sdk-core/${milo-version}</bundle> - <bundle dependency='true'>mvn:org.eclipse.milo/sdk-server/${milo-version}</bundle> - <bundle dependency='true'>mvn:org.eclipse.milo/bsd-parser-core/${milo-version}</bundle> + <bundle dependency='true'>mvn:org.eclipse.milo/sdk-server/${milo-version}</bundle> <bundle dependency='true'>mvn:org.eclipse.milo/sdk-client/${milo-version}</bundle> + <bundle dependency='true'>mvn:org.eclipse.milo/bsd-parser-core/${milo-version}</bundle> <bundle dependency='true'>mvn:org.eclipse.milo/bsd-parser-gson/${milo-version}</bundle> <bundle>mvn:org.apache.camel/camel-milo/${project.version}</bundle> </feature> diff --git a/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelMiloTest.java b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelMiloTest.java index a66342c..60d881c 100644 --- a/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelMiloTest.java +++ b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelMiloTest.java @@ -16,22 +16,12 @@ */ package org.apache.camel.itest.karaf; -import org.junit.Assume; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.junit.PaxExam; @RunWith(PaxExam.class) public class CamelMiloTest extends BaseKarafTest { - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - Assume.assumeTrue("Requires java 9+", isJavaVersionSatisfied(9)); - } - @Test public void testClient() throws Exception { testComponent("milo", "milo-client"); @@ -40,22 +30,4 @@ public class CamelMiloTest extends BaseKarafTest { public void testServer() throws Exception { testComponent("milo", "milo-server"); } - - /** - * Return true, if java version (defined by method getRequiredJavaVersion()) is satisfied. - * Works for java versions 9+ - */ - boolean isJavaVersionSatisfied(int requiredVersion) { - String version = System.getProperty("java.version"); - if (!version.startsWith("1.")) { - int dot = version.indexOf("."); - if (dot != -1) { - version = version.substring(0, dot); - } - if (Integer.parseInt(version) >= requiredVersion) { - return true; - } - } - return false; - } }