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 13fc914 CAMEL-14344 camel-milo - Upgrade to newer milo version (#3539)
13fc914 is described below
commit 13fc9143ef6dfee9d8e1d297fd305c2a644594d4
Author: JiriOndrusek <[email protected]>
AuthorDate: Wed Feb 5 04:37:20 2020 +0100
CAMEL-14344 camel-milo - Upgrade to newer milo version (#3539)
---
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 2461 -> 0 bytes
.../src/test/resources/cert/certificate.crt | 20 --
.../src/test/resources/cert/certificate.der | Bin 856 -> 0 bytes
.../src/test/resources/cert/privateKey.key | 28 --
components/camel-milo/src/test/resources/keystore | Bin 0 -> 3990 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, 951 insertions(+), 636 deletions(-)
diff --git a/components/camel-milo/pom.xml b/components/camel-milo/pom.xml
index 807ea5f..3149be6 100644
--- a/components/camel-milo/pom.xml
+++ b/components/camel-milo/pom.xml
@@ -55,6 +55,12 @@
<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 705750a..d30640b 100644
--- a/components/camel-milo/src/main/docs/milo-client-component.adoc
+++ b/components/camel-milo/src/main/docs/milo-client-component.adoc
@@ -10,6 +10,8 @@
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:
@@ -52,13 +54,13 @@ The URI syntax of the endpoint is:
[source]
------------------------
-milo-client:tcp://[user:password@]host:port/path/to/service?node=RAW(nsu=urn:foo:bar;s=item-1)
+milo-client:opc.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:tcp://[user:password@]host:port?node=RAW(nsu=urn:foo:bar;s=item-1)
+milo-client:opc.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.
@@ -239,7 +241,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:tcp://user:password@localhost:12345?node=RAW(nsu=http://foo.bar;s=foo/bar)
+milo-client:opc.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 d70a8ae..bf62602 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 8*: This component requires Java 8 at runtime.
+*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:
@@ -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 22 options, which are listed below.
+The OPC UA Server component supports 20 options, which are listed below.
@@ -39,12 +39,10 @@ The OPC UA Server component supports 22 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 a532657..687a88a 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).getSecurityPolicyUri();
+ adding = SecurityPolicy.fromUri(policy).getUri();
} catch (Exception e) {
}
if (adding == null) {
try {
- adding =
SecurityPolicy.valueOf(policy).getSecurityPolicyUri();
+ adding = SecurityPolicy.valueOf(policy).getUri();
} 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 515fa4b..03023da 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,7 +28,6 @@ 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 0a13dbd..786854f 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.UaTcpStackClient;
+import org.eclipse.milo.opcua.stack.client.DiscoveryClient;
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,10 +427,18 @@ public class SubscriptionManager {
// eval enpoint
- final String discoveryUri = getEndpointDiscoveryUri();
+ 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 + "@", "");
+ }
LOG.debug("Discovering endpoints from: {}", discoveryUri);
- final EndpointDescription endpoint =
UaTcpStackClient.getEndpoints(discoveryUri).thenApply(endpoints -> {
+ final EndpointDescription endpoint =
DiscoveryClient.getEndpoints(discoveryUri).thenApply(endpoints -> {
if (LOG.isDebugEnabled()) {
LOG.debug("Found enpoints:");
for (final EndpointDescription ep : endpoints) {
@@ -447,13 +455,9 @@ 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) {
@@ -470,7 +474,7 @@ public class SubscriptionManager {
// create client
- final OpcUaClient client = new OpcUaClient(cfg.build());
+ final OpcUaClient client = OpcUaClient.create(cfg.build());
client.connect().get();
try {
@@ -530,7 +534,7 @@ public class SubscriptionManager {
}
}
- private EndpointDescription findEndpoint(final EndpointDescription[]
endpoints) throws URISyntaxException {
+ private EndpointDescription findEndpoint(final List<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 ccbbebf..3e8ce5a 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,23 +47,28 @@ 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.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.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.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
@@ -75,54 +80,25 @@ 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 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 int port;
private String namespaceUri = DEFAULT_NAMESPACE_URI;
- private final OpcUaServerConfigBuilder serverConfig;
+ private OpcUaServerConfigBuilder opcServerConfig;
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();
@@ -133,19 +109,33 @@ 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(DEFAULT_SERVER_CONFIG);
+ this.opcServerConfig = null;
}
public MiloServerComponent(final OpcUaServerConfig serverConfig) {
- this.serverConfig = OpcUaServerConfig.copy(serverConfig != null ?
serverConfig : DEFAULT_SERVER_CONFIG);
+ this.opcServerConfig = OpcUaServerConfig.copy(serverConfig);
+
}
@Override
protected void doStart() throws Exception {
this.server = new OpcUaServer(buildServerConfig());
- this.namespace =
this.server.getNamespaceManager().registerAndAdd(this.namespaceUri, index ->
new CamelNamespace(index, this.namespaceUri, this.server));
+ this.namespace = new CamelNamespace(this.namespaceUri, this.server);
+ this.namespace.startup();
super.doStart();
this.server.startup();
@@ -157,6 +147,7 @@ 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
@@ -170,7 +161,7 @@ public class MiloServerComponent extends DefaultComponent {
}
return pwd.equals(challenge.getPassword());
});
- this.serverConfig.setIdentityValidator(identityValidator);
+ serverConfig.setIdentityValidator(identityValidator);
// add token policies
@@ -181,11 +172,9 @@ public class MiloServerComponent extends DefaultComponent {
if (userMap != null) {
tokenPolicies.add(getUsernamePolicy());
}
- this.serverConfig.setUserTokenPolicies(tokenPolicies);
- }
-
- if (this.bindAddresses != null) {
- this.serverConfig.setBindAddresses(new
ArrayList<>(this.bindAddresses));
+
serverConfig.setEndpoints(createEndpointConfigurations(tokenPolicies));
+ } else {
+ serverConfig.setEndpoints(createEndpointConfigurations(null,
securityPolicies));
}
if (this.certificateValidator != null) {
@@ -201,12 +190,151 @@ public class MiloServerComponent extends
DefaultComponent {
}
});
}
- this.serverConfig.setCertificateValidator(validator);
+ 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;
+ }
- return this.serverConfig.build();
+ 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);
+ }
}
/**
@@ -271,7 +399,15 @@ public class MiloServerComponent extends DefaultComponent {
*/
public void setApplicationName(final String applicationName) {
Objects.requireNonNull(applicationName);
-
this.serverConfig.setApplicationName(LocalizedText.english(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;
}
/**
@@ -279,7 +415,7 @@ public class MiloServerComponent extends DefaultComponent {
*/
public void setApplicationUri(final String applicationUri) {
Objects.requireNonNull(applicationUri);
- this.serverConfig.setApplicationUri(applicationUri);
+ this.applicationUri = applicationUri;
}
/**
@@ -287,35 +423,14 @@ public class MiloServerComponent extends DefaultComponent
{
*/
public void setProductUri(final String productUri) {
Objects.requireNonNull(productUri);
- this.serverConfig.setProductUri(productUri);
+ this.productUri = productUri;
}
/**
* The TCP port the server binds to
*/
public void setBindPort(final int 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);
+ this.port = port;
}
/**
@@ -323,9 +438,9 @@ public class MiloServerComponent extends DefaultComponent {
*/
public void setSecurityPolicies(final Set<SecurityPolicy>
securityPolicies) {
if (securityPolicies == null || securityPolicies.isEmpty()) {
-
this.serverConfig.setSecurityPolicies(EnumSet.noneOf(SecurityPolicy.class));
+ this.securityPolicies = EnumSet.noneOf(SecurityPolicy.class);
} else {
-
this.serverConfig.setSecurityPolicies(EnumSet.copyOf(securityPolicies));
+ this.securityPolicies = EnumSet.copyOf(securityPolicies);
}
}
@@ -342,7 +457,7 @@ public class MiloServerComponent extends DefaultComponent {
}
}
- this.serverConfig.setSecurityPolicies(policies);
+ this.securityPolicies = policies;
}
/**
@@ -392,7 +507,7 @@ public class MiloServerComponent extends DefaultComponent {
* Set the {@link UserTokenPolicy} used when
*/
public void setUsernameSecurityPolicyUri(final SecurityPolicy
usernameSecurityPolicy) {
- this.usernameSecurityPolicyUri =
usernameSecurityPolicy.getSecurityPolicyUri();
+ this.usernameSecurityPolicyUri = usernameSecurityPolicy.getUri();
}
/**
@@ -417,7 +532,7 @@ public class MiloServerComponent extends DefaultComponent {
* Server build info
*/
public void setBuildInfo(final BuildInfo buildInfo) {
- this.serverConfig.setBuildInfo(buildInfo);
+ this.buildInfo = buildInfo;
}
/**
@@ -440,6 +555,7 @@ public class MiloServerComponent extends DefaultComponent {
* Server certificate
*/
public void setServerCertificate(final KeyPair keyPair, final
X509Certificate certificate) {
+ this.certificate = certificate;
setCertificateManager(new DefaultCertificateManager(keyPair,
certificate));
}
@@ -447,11 +563,7 @@ public class MiloServerComponent extends DefaultComponent {
* Server certificate manager
*/
public void setCertificateManager(final CertificateManager
certificateManager) {
- if (certificateManager != null) {
- this.serverConfig.setCertificateManager(certificateManager);
- } else {
- this.serverConfig.setCertificateManager(new
DefaultCertificateManager());
- }
+ this.certificateManager = certificateManager != null ?
certificateManager : new DefaultCertificateManager();
}
/**
@@ -465,6 +577,11 @@ public class MiloServerComponent extends DefaultComponent {
* Validator for client certificates using default file based approach
*/
public void setDefaultCertificateValidator(final File certificatesBaseDir)
{
- this.certificateValidator = () -> new
DefaultCertificateValidator(certificatesBaseDir);
+ try {
+ DefaultTrustListManager trustListManager = new
DefaultTrustListManager(certificatesBaseDir);
+ this.certificateValidator = () -> new
DefaultCertificateValidator(trustListManager);
+ } catch (IOException e) {
+ LOG.error("Failed to construct certificateValidator.", e);
+ }
}
}
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
new file mode 100644
index 0000000..c190280
--- /dev/null
+++
b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/internal/CallMethod.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.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 7fdd2a9..7a166cf 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,157 +19,78 @@ 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 implements Namespace {
+public class CamelNamespace extends ManagedNamespace {
- private static final Logger LOG =
LoggerFactory.getLogger(MiloClientConsumer.class);
-
- private final UShort namespaceIndex;
-
- private final String namespaceUri;
-
- private final ServerNodeMap nodeManager;
private final SubscriptionModel subscriptionModel;
- private final UaFolderNode folder;
- private final UaObjectNode itemsObject;
+ private UaObjectNode itemsObject;
+ private UaFolderNode folder;
+
private final Map<String, CamelServerItem> itemMap = new HashMap<>();
- public CamelNamespace(final UShort namespaceIndex, final String
namespaceUri, final OpcUaServer server) {
- this.namespaceIndex = namespaceIndex;
- this.namespaceUri = namespaceUri;
+ public CamelNamespace(final String namespaceUri, final OpcUaServer server)
{
+ super(server, 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
- public UShort getNamespaceIndex() {
- return this.namespaceIndex;
- }
-
- @Override
- public String getNamespaceUri() {
- return this.namespaceUri;
- }
-
- @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;
- }
- }
-
- @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());
-
- for (final ReadValueId id : readValueIds) {
- final ServerNode node = this.nodeManager.get(id.getNodeId());
-
- final DataValue value;
-
- if (node != null) {
- value = node.readAttribute(new AttributeContext(context),
id.getAttributeId(), timestamps, id.getIndexRange(), null);
- } else {
- value = new DataValue(StatusCodes.Bad_NodeIdUnknown);
- }
+ protected void onStartup() {
+ super.onStartup();
+ // create structure
- results.add(value);
- }
+ final NodeId nodeId = newNodeId("camel");
+ final QualifiedName name = newQualifiedName("camel");
+ final LocalizedText displayName = LocalizedText.english("Camel");
- context.complete(results);
- }
+ this.folder = new UaFolderNode(getNodeContext(), nodeId, name,
displayName);
+ getNodeManager().addNode(this.folder);
- @Override
- public void write(final WriteContext context, final List<WriteValue>
writeValues) {
- final List<StatusCode> results =
Lists.newArrayListWithCapacity(writeValues.size());
+ final NodeId nodeId2 = newNodeId("items");
+ final QualifiedName name2 = newQualifiedName("items");
+ final LocalizedText displayName2 = LocalizedText.english("Items");
- for (final WriteValue writeValue : writeValues) {
- try {
- final ServerNode node =
this.nodeManager.getNode(writeValue.getNodeId()).orElseThrow(() -> new
UaException(StatusCodes.Bad_NodeIdUnknown));
+ 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);
- 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());
- }
- }
+ // register reference to structure
- context.complete(results);
+ 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
+ ));
}
@Override
@@ -196,7 +117,7 @@ public class CamelNamespace implements Namespace {
synchronized (this) {
CamelServerItem item = this.itemMap.get(itemId);
if (item == null) {
- item = new CamelServerItem(itemId, this.nodeManager,
this.namespaceIndex, this.itemsObject);
+ item = new CamelServerItem(itemId, getNodeContext(),
getNamespaceIndex(), 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 c1db1eb..fa74c02 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.api.ServerNodeMap;
+import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext;
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 ServerNodeMap
nodeManager, final UShort namespaceIndex, final UaObjectNode baseNode) {
+ public CamelServerItem(final String itemId, final UaNodeContext
nodeContext, 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(nodeManager, nodeId, qname,
displayName) {
+ this.item = new UaVariableNode(nodeContext, nodeId, qname,
displayName) {
@Override
public synchronized DataValue getValue() {
@@ -79,6 +79,7 @@ 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 35902b0..ab12493 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,6 +27,7 @@ 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 {
@@ -34,6 +35,7 @@ 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();
}
@@ -112,9 +114,10 @@ public abstract class AbstractMiloServerTest extends
CamelTestSupport {
try {
final KeyStoreLoader loader = new KeyStoreLoader();
- loader.setUrl("file:src/test/resources/cert/cert.p12");
- loader.setKeyStorePassword("pwd1");
- loader.setKeyPassword("pwd1");
+ loader.setUrl("file:src/test/resources/keystore");
+ loader.setKeyStorePassword("testtest");
+
+ loader.setKeyPassword("test");
return loader.load();
} catch (final GeneralSecurityException | IOException e) {
throw new RuntimeException(e);
@@ -122,4 +125,22 @@ 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 1c10522..5b3bcfcf 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:tcp://foo:bar@localhost:@@port@@?node="
+ 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")
- +
"&keyStoreUrl=file:src/test/resources/cert/cert.p12&keyStorePassword=pwd1&keyPassword=pwd1"
+ +
"&keyStoreUrl=file:src/test/resources/keystore&keyStorePassword=testtest&keyPassword=test&keyAlias=test"
+
"&discoveryEndpointSuffix=/discovery&overrideHost=true";
// with wrong password
- private static final String MILO_CLIENT_ITEM_C2_1 =
"milo-client:tcp://foo:bar2@localhost:@@port@@?node="
+ private static final String MILO_CLIENT_ITEM_C2_1 =
"milo-client:opc.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:tcp://foo:bar@localhost:@@port@@?clientId=1&node="
+ private static final String MILO_CLIENT_ITEM_C3_1 =
"milo-client:opc.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");
+ final Path trusted = baseDir.resolve("trusted/certs");
Files.createDirectories(trusted);
- Files.copy(Paths.get("src/test/resources/cert/certificate.der"),
trusted.resolve("certificate.der"), REPLACE_EXISTING);
+ Files.copy(Paths.get("src/test/resources/ca/cacert.pem"),
trusted.resolve("cacert.pem"), 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 dcccaf9..116cf98 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:tcp://foo:bar@localhost:@@port@@?node="
+ 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") +
"&overrideHost=true";
- private static final String MILO_CLIENT_ITEM_C2_1 =
"milo-client:tcp://foo:bar2@localhost:@@port@@?node="
+ private static final String MILO_CLIENT_ITEM_C2_1 =
"milo-client:opc.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:tcp://foo2:bar@localhost:@@port@@?node="
+ private static final String MILO_CLIENT_ITEM_C3_1 =
"milo-client:opc.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 b4d9b3e..3b3ba6d 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: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:opc.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 43214b3..9a0942c 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: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_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_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 56ef9ee..db70850 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,29 +18,34 @@ package org.apache.camel.component.milo.call;
import java.util.Arrays;
import java.util.EnumSet;
-import java.util.LinkedList;
+import java.util.LinkedHashSet;
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.call.MockCall.Call1;
+import org.apache.camel.component.milo.NodeIds;
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.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.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.stack.core.security.SecurityPolicy;
-import org.junit.After;
+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.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
@@ -49,17 +54,27 @@ public class CallClientTest extends AbstractMiloServerTest {
private static final String DIRECT_START_1 = "direct:start1";
- private static final String MILO_CLIENT_BASE_C1 =
"milo-client:tcp://localhost:@@port@@";
+ private static final String MILO_CLIENT_BASE_C1 =
"milo-client:opc.tcp://localhost:@@port@@";
- 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)
- protected ProducerTemplate producer1;
+ 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 Call1 call1;
+ @Produce(DIRECT_START_1)
+ private 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));
+ }
+ };
+ }
@Override
protected boolean isAddServer() {
@@ -68,43 +83,75 @@ public class CallClientTest extends AbstractMiloServerTest {
@Before
public void start() throws Exception {
- 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());
+ 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());
- this.server = new OpcUaServer(config.build());
+ this.namespace = new MockCamelNamespace(this.server, node ->
callMethod = new MockCallMethod(node));
+ this.namespace.startup();
+ this.server.startup().get();
+ }
- this.call1 = new MockCall.Call1();
+ private Set<EndpointConfiguration>
createEndpointConfigurations(List<UserTokenPolicy> userTokenPolicies,
Set<SecurityPolicy> securityPolicies) {
+ Set<EndpointConfiguration> endpointConfigurations = new
LinkedHashSet<>();
- this.server.getNamespaceManager().registerAndAdd(MockNamespace.URI,
index -> {
+ String bindAddress = "0.0.0.0";
+ Set<String> hostnames = new LinkedHashSet<>();
+ hostnames.add(HostnameUtil.getHostname());
+ hostnames.addAll(HostnameUtil.getHostnames(bindAddress));
- final List<UaMethodNode> methods = new LinkedList<>();
- methods.add(MockCall.fromNode(index, this.server.getNodeMap(),
"id1", "name1", this.call1));
+ UserTokenPolicy[] tokenPolicies = new UserTokenPolicy[]
{USER_TOKEN_POLICY_ANONYMOUS};
- return new MockNamespace(index, this.server, methods);
- });
+ for (String hostname : hostnames) {
+ EndpointConfiguration.Builder builder =
EndpointConfiguration.newBuilder()
+ .setBindAddress(bindAddress)
+ .setHostname(hostname)
+ .setCertificate(() -> null)
+ .addTokenPolicies(tokenPolicies);
- this.server.startup().get();
- }
- @After
- public void stop() {
- this.server.shutdown();
- }
+ if (securityPolicies == null ||
securityPolicies.contains(SecurityPolicy.None)) {
+ EndpointConfiguration.Builder noSecurityBuilder =
builder.copy()
+ .setSecurityPolicy(SecurityPolicy.None)
+ .setSecurityMode(MessageSecurityMode.None);
- @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));
+
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;
+ }
+
+ private EndpointConfiguration
buildTcpEndpoint(EndpointConfiguration.Builder base) {
+ return base.copy()
+ .setTransportProfile(TransportProfile.TCP_UASC_UABINARY)
+ .setBindPort(getServerPort())
+ .build();
}
@Test
@@ -115,8 +162,8 @@ public class CallClientTest extends AbstractMiloServerTest {
doCall(this.producer1, "bar");
// assert
-
- Assert.assertArrayEquals(new Object[] {"foo", "bar"},
this.call1.calls.toArray());
+ Assert.assertNotNull(this.callMethod);
+ Assert.assertArrayEquals(new Object[] {"out-foo", "out-bar"},
this.callMethod.getCalls().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
deleted file mode 100644
index 51408c2..0000000
---
a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCall.java
+++ /dev/null
@@ -1,71 +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.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
new file mode 100644
index 0000000..fe52c8c
--- /dev/null
+++
b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCallMethod.java
@@ -0,0 +1,77 @@
+/*
+ * 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
new file mode 100644
index 0000000..3197485
--- /dev/null
+++
b/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockCamelNamespace.java
@@ -0,0 +1,141 @@
+/*
+ * 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
deleted file mode 100644
index 1acd8de..0000000
---
a/components/camel-milo/src/test/java/org/apache/camel/component/milo/call/MockNamespace.java
+++ /dev/null
@@ -1,176 +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.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 fe58263..f4ea7f4 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/cert/certificate.der"),
trusted.resolve("certificate.der"), REPLACE_EXISTING);
+ Files.copy(Paths.get("src/test/resources/ca/cacert.pem"),
trusted.resolve("cacert.pem"), 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
new file mode 100644
index 0000000..f23452c
--- /dev/null
+++ b/components/camel-milo/src/test/resources/ca/cacert.pem
@@ -0,0 +1,32 @@
+-----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
deleted file mode 100644
index b44c850..0000000
--- a/components/camel-milo/src/test/resources/cert/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-.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
deleted file mode 100644
index 7eaaed2..0000000
--- a/components/camel-milo/src/test/resources/cert/cert.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[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
deleted file mode 100644
index 8a2eed9..0000000
Binary files a/components/camel-milo/src/test/resources/cert/cert.p12 and
/dev/null differ
diff --git a/components/camel-milo/src/test/resources/cert/certificate.crt
b/components/camel-milo/src/test/resources/cert/certificate.crt
deleted file mode 100644
index 8b7c784..0000000
--- a/components/camel-milo/src/test/resources/cert/certificate.crt
+++ /dev/null
@@ -1,20 +0,0 @@
------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
deleted file mode 100644
index 37abde7..0000000
Binary files a/components/camel-milo/src/test/resources/cert/certificate.der
and /dev/null differ
diff --git a/components/camel-milo/src/test/resources/cert/privateKey.key
b/components/camel-milo/src/test/resources/cert/privateKey.key
deleted file mode 100644
index 5900120..0000000
--- a/components/camel-milo/src/test/resources/cert/privateKey.key
+++ /dev/null
@@ -1,28 +0,0 @@
------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
new file mode 100644
index 0000000..ef6d68f
Binary files /dev/null and b/components/camel-milo/src/test/resources/keystore
differ
diff --git a/components/camel-milo/src/test/resources/openssl-ca.cnf
b/components/camel-milo/src/test/resources/openssl-ca.cnf
new file mode 100644
index 0000000..bd29e0e
--- /dev/null
+++ b/components/camel-milo/src/test/resources/openssl-ca.cnf
@@ -0,0 +1,80 @@
+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
new file mode 100644
index 0000000..dd3cd0e
--- /dev/null
+++ b/components/camel-milo/src/test/resources/openssl-server.cnf
@@ -0,0 +1,39 @@
+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
new file mode 100755
index 0000000..a6d1620
--- /dev/null
+++ b/components/camel-milo/src/test/resources/run.sh
@@ -0,0 +1,21 @@
+# 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 634f914..3517f7e 100644
--- a/docs/components/modules/ROOT/pages/milo-client-component.adoc
+++ b/docs/components/modules/ROOT/pages/milo-client-component.adoc
@@ -11,6 +11,9 @@
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:
@@ -53,13 +56,13 @@ The URI syntax of the endpoint is:
[source]
------------------------
-milo-client:tcp://[user:password@]host:port/path/to/service?node=RAW(nsu=urn:foo:bar;s=item-1)
+milo-client:opc.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:tcp://[user:password@]host:port?node=RAW(nsu=urn:foo:bar;s=item-1)
+milo-client:opc.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.
@@ -240,7 +243,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:tcp://user:password@localhost:12345?node=RAW(nsu=http://foo.bar;s=foo/bar)
+milo-client:opc.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 861c31c..072675e 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 22 options, which are listed below.
+The OPC UA Server component supports 20 options, which are listed below.
@@ -40,12 +40,10 @@ The OPC UA Server component supports 22 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 33abb55..4f75f8b 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,6 +41,27 @@ 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 c86d053..1cb3e58 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -164,6 +164,8 @@
<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>
@@ -458,7 +460,8 @@
<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.2.5</milo-version>
+ <milo-version>0.3.7</milo-version>
+ <milo-guava-version>26.0-jre</milo-guava-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 a183476..ae3b5e9 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -1750,19 +1750,26 @@
<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: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.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: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/sdk-client/${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-client/${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 60d881c..a66342c 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,12 +16,22 @@
*/
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");
@@ -30,4 +40,22 @@ 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;
+ }
}