1 package de.dlr.bt.stc.opcuaserver;
2
3 import java.io.File;
4 import java.nio.file.Files;
5 import java.nio.file.Path;
6 import java.nio.file.Paths;
7 import java.security.KeyPair;
8 import java.security.Security;
9 import java.security.cert.X509Certificate;
10 import java.util.ArrayList;
11 import java.util.LinkedHashSet;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.concurrent.CompletableFuture;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.TimeUnit;
17 import java.util.concurrent.TimeoutException;
18
19 import org.bouncycastle.jce.provider.BouncyCastleProvider;
20 import org.eclipse.milo.opcua.sdk.server.OpcUaServer;
21 import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig;
22 import org.eclipse.milo.opcua.sdk.server.identity.CompositeValidator;
23 import org.eclipse.milo.opcua.sdk.server.identity.UsernameIdentityValidator;
24 import org.eclipse.milo.opcua.sdk.server.identity.X509IdentityValidator;
25 import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil;
26 import org.eclipse.milo.opcua.stack.core.StatusCodes;
27 import org.eclipse.milo.opcua.stack.core.UaRuntimeException;
28 import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager;
29 import org.eclipse.milo.opcua.stack.core.security.DefaultTrustListManager;
30 import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
31 import org.eclipse.milo.opcua.stack.core.transport.TransportProfile;
32 import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
33 import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
34 import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode;
35 import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo;
36 import org.eclipse.milo.opcua.stack.core.util.CertificateUtil;
37 import org.eclipse.milo.opcua.stack.core.util.NonceUtil;
38 import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
39 import org.eclipse.milo.opcua.stack.core.util.SelfSignedHttpsCertificateBuilder;
40 import org.eclipse.milo.opcua.stack.server.EndpointConfiguration;
41 import org.greenrobot.eventbus.EventBus;
42
43 import lombok.extern.slf4j.Slf4j;
44
45 @Slf4j
46 public class UAServer {
47 private static final String IP_ANY = "0.0.0.0";
48
49 static {
50
51 Security.addProvider(new BouncyCastleProvider());
52 try {
53 NonceUtil.blockUntilSecureRandomSeeded(10, TimeUnit.SECONDS);
54 } catch (ExecutionException | InterruptedException | TimeoutException e) {
55 e.printStackTrace();
56 System.exit(-1);
57 }
58 }
59
60 private final OpcUaServer server;
61
62 public UAServer(int tcpBindPort, EventBus eventBus) throws Exception {
63
64 Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "server", "security");
65 Files.createDirectories(securityTempDir);
66 if (!Files.exists(securityTempDir)) {
67 throw new Exception("unable to create security temp dir: " + securityTempDir);
68 }
69
70 File pkiDir = securityTempDir.resolve("pki").toFile();
71
72 log.info("security dir: {}", securityTempDir.toAbsolutePath());
73 log.info("security pki dir: {}", pkiDir.getAbsolutePath());
74
75 KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir);
76
77 DefaultCertificateManager certificateManager = new DefaultCertificateManager(loader.getServerKeyPair(),
78 loader.getServerCertificateChain());
79
80 DefaultTrustListManager trustListManager = new DefaultTrustListManager(pkiDir);
81
82
83
84
85 AcceptAllCertificateValidator acceptAllValidator = new AcceptAllCertificateValidator();
86
87 KeyPair httpsKeyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);
88
89 SelfSignedHttpsCertificateBuilder httpsCertificateBuilder = new SelfSignedHttpsCertificateBuilder(httpsKeyPair);
90 httpsCertificateBuilder.setCommonName(HostnameUtil.getHostname());
91 HostnameUtil.getHostnames(IP_ANY).forEach(httpsCertificateBuilder::addDnsName);
92 X509Certificate httpsCertificate = httpsCertificateBuilder.build();
93
94
95 UsernameIdentityValidator identityValidator = new UsernameIdentityValidator(true, authChallenge -> true);
96
97 X509IdentityValidator x509IdentityValidator = new X509IdentityValidator(c -> true);
98
99
100 X509Certificate certificate = certificateManager.getCertificates().stream().findFirst()
101 .orElseThrow(() -> new UaRuntimeException(StatusCodes.Bad_ConfigurationError, "no certificate found"));
102
103
104 String applicationUri = CertificateUtil.getSanUri(certificate)
105 .orElseThrow(() -> new UaRuntimeException(StatusCodes.Bad_ConfigurationError,
106 "certificate is missing the application URI"));
107
108 Set<EndpointConfiguration> endpointConfigurations = createEndpointConfigurations(certificate, tcpBindPort);
109
110 @SuppressWarnings("unchecked")
111 OpcUaServerConfig serverConfig = OpcUaServerConfig.builder().setApplicationUri(applicationUri)
112 .setApplicationName(LocalizedText.english("Shepard Timeseries Collector"))
113 .setEndpoints(endpointConfigurations)
114 .setBuildInfo(new BuildInfo("urn:dlr:stc:server:opcua", "DLR e.V.", "Shepard Timeseries Connector",
115 OpcUaServer.SDK_VERSION, "", DateTime.now()))
116 .setCertificateManager(certificateManager).setTrustListManager(trustListManager)
117 .setCertificateValidator(acceptAllValidator).setHttpsKeyPair(httpsKeyPair)
118 .setHttpsCertificateChain(new X509Certificate[] { httpsCertificate })
119 .setIdentityValidator(new CompositeValidator<>(identityValidator, x509IdentityValidator))
120 .setProductUri("urn:dlr:stc:server:opcua").build();
121
122 server = new OpcUaServer(serverConfig);
123
124 STCNamespace stcns = new STCNamespace(server, eventBus);
125 stcns.startup();
126 }
127
128 private Set<EndpointConfiguration> createEndpointConfigurations(X509Certificate certificate, int bindPort) {
129 Set<EndpointConfiguration> endpointConfigurations = new LinkedHashSet<>();
130
131 List<String> bindAddresses = new ArrayList<>();
132 bindAddresses.add(IP_ANY);
133
134 Set<String> hostnames = new LinkedHashSet<>();
135 hostnames.add(HostnameUtil.getHostname());
136 hostnames.addAll(HostnameUtil.getHostnames(IP_ANY));
137
138 for (String bindAddress : bindAddresses) {
139 for (String hostname : hostnames) {
140 EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder().setBindAddress(bindAddress)
141 .setHostname(hostname).setPath("/").setCertificate(certificate)
142 .addTokenPolicies(OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS);
143
144 EndpointConfiguration.Builder noSecurityBuilder = builder.copy().setSecurityPolicy(SecurityPolicy.None)
145 .setSecurityMode(MessageSecurityMode.None);
146
147 endpointConfigurations.add(buildTcpEndpoint(noSecurityBuilder, bindPort));
148
149
150 endpointConfigurations
151 .add(buildTcpEndpoint(builder.copy().setSecurityPolicy(SecurityPolicy.Basic256Sha256)
152 .setSecurityMode(MessageSecurityMode.SignAndEncrypt), bindPort));
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 }
171 }
172
173 return endpointConfigurations;
174 }
175
176 private static EndpointConfiguration buildTcpEndpoint(EndpointConfiguration.Builder base, int bindPort) {
177 return base.copy().setTransportProfile(TransportProfile.TCP_UASC_UABINARY).setBindPort(bindPort).build();
178 }
179
180 public OpcUaServer getServer() {
181 return server;
182 }
183
184 public CompletableFuture<OpcUaServer> startup() {
185 return server.startup();
186 }
187
188 public CompletableFuture<OpcUaServer> shutdown() {
189 return server.shutdown();
190 }
191
192
193
194
195 }