All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ar4k.agent.opcua.server.Ar4kOpcUaServer Maven / Gradle / Ivy


package org.ar4k.agent.opcua.server;

import static com.google.common.collect.Lists.newArrayList;
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;

import java.io.File;
import java.security.KeyPair;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import org.ar4k.agent.core.interfaces.EdgeComponent.ServiceStatus;
import org.ar4k.agent.logger.EdgeLogger;
import org.ar4k.agent.logger.EdgeStaticLoggerBinder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
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.identity.CompositeValidator;
import org.eclipse.milo.opcua.sdk.server.identity.UsernameIdentityValidator;
import org.eclipse.milo.opcua.sdk.server.identity.X509IdentityValidator;
import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil;
import org.eclipse.milo.opcua.stack.core.StatusCodes;
import org.eclipse.milo.opcua.stack.core.UaRuntimeException;
import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager;
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.DateTime;
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.BuildInfo;
import org.eclipse.milo.opcua.stack.core.util.CertificateUtil;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedHttpsCertificateBuilder;
import org.eclipse.milo.opcua.stack.server.EndpointConfiguration;
import org.eclipse.milo.opcua.stack.server.security.DefaultServerCertificateValidator;

public class Ar4kOpcUaServer {

	private static final EdgeLogger logger = EdgeStaticLoggerBinder.getClassLogger(Ar4kOpcUaServer.class);

	static {
		// Required for SecurityPolicy.Aes256_Sha256_RsaPss
		Security.addProvider(new BouncyCastleProvider());
	}

	private final OpcUaServer server;
	private final OpcUaNamespace nameSpaceOpc;
	private final org.ar4k.agent.opcua.server.OpcUaServerConfig configuration;

	public Ar4kOpcUaServer(org.ar4k.agent.opcua.server.OpcUaServerConfig configuration) throws Exception {
		this.configuration = configuration;
		final File securityTempDir = new File(System.getProperty("java.io.tmpdir"), "security");
		if (!securityTempDir.exists() && !securityTempDir.mkdirs()) {
			throw new Exception("unable to create security temp dir: " + securityTempDir);
		}
		logger.debug("security temp dir: {}", securityTempDir.getAbsolutePath());

		final KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir);

		final DefaultCertificateManager certificateManager = new DefaultCertificateManager(loader.getServerKeyPair(),
				loader.getServerCertificateChain());

		final File pkiDir = securityTempDir.toPath().resolve("pki").toFile();
		final DefaultTrustListManager trustListManager = new DefaultTrustListManager(pkiDir);
		logger.debug("pki dir: {}", pkiDir.getAbsolutePath());

		final DefaultServerCertificateValidator certificateValidator = new DefaultServerCertificateValidator(
				trustListManager);

		final KeyPair httpsKeyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);

		final SelfSignedHttpsCertificateBuilder httpsCertificateBuilder = new SelfSignedHttpsCertificateBuilder(
				httpsKeyPair);
		httpsCertificateBuilder.setCommonName(HostnameUtil.getHostname());
		HostnameUtil.getHostnames(configuration.bindAddress).forEach(httpsCertificateBuilder::addDnsName);
		// TODO sostituire con certificati di sistema in OPCUA
		final X509Certificate httpsCertificate = httpsCertificateBuilder.build();

		final UsernameIdentityValidator identityValidator = new UsernameIdentityValidator(true, authChallenge -> {
			final String username = authChallenge.getUsername();
			final String password = authChallenge.getPassword();
//TODO inserire wrapper autenticazione per OPCUA
			final boolean userOk = "user".equals(username) && "password1".equals(password);
			final boolean adminOk = "admin".equals(username) && "password2".equals(password);

			return userOk || adminOk;
		});

		final X509IdentityValidator x509IdentityValidator = new X509IdentityValidator(c -> true);

		// If you need to use multiple certificates you'll have to be smarter than this.
		final X509Certificate certificate = certificateManager.getCertificates().stream().findFirst()
				.orElseThrow(() -> new UaRuntimeException(StatusCodes.Bad_ConfigurationError, "no certificate found"));

		// The configured application URI must match the one in the certificate(s)
		final String applicationUri = CertificateUtil.getSanUri(certificate)
				.orElseThrow(() -> new UaRuntimeException(StatusCodes.Bad_ConfigurationError,
						"certificate is missing the application URI"));

		final Set endpointConfigurations = createEndpointConfigurations(certificate);

		final OpcUaServerConfig serverConfig = OpcUaServerConfig.builder().setApplicationUri(applicationUri)
				.setApplicationName(LocalizedText.english(configuration.applicationName))
				.setEndpoints(endpointConfigurations)
				.setBuildInfo(new BuildInfo(configuration.productUri, configuration.manufacturerName,
						configuration.productName, OpcUaServer.SDK_VERSION, "", DateTime.now()))
				.setCertificateManager(certificateManager).setTrustListManager(trustListManager)
				.setCertificateValidator(certificateValidator).setHttpsKeyPair(httpsKeyPair)
				.setHttpsCertificate(httpsCertificate)
				.setIdentityValidator(new CompositeValidator(identityValidator, x509IdentityValidator))
				.setProductUri(configuration.productUri).build();

		server = new OpcUaServer(serverConfig);

		nameSpaceOpc = new OpcUaNamespace(server, configuration);
		// nameSpaceOpc.startup();
	}

	private Set createEndpointConfigurations(X509Certificate certificate) {
		final Set endpointConfigurations = new LinkedHashSet<>();

		final List bindAddresses = newArrayList();
		bindAddresses.add(configuration.bindAddress);

		final Set hostnames = new LinkedHashSet<>();
		hostnames.add(HostnameUtil.getHostname());
		hostnames.addAll(HostnameUtil.getHostnames(configuration.bindAddress));

		for (final String bindAddress : bindAddresses) {
			for (final String hostname : hostnames) {
				final EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder()
						.setBindAddress(bindAddress).setHostname(hostname).setPath(configuration.serverPath)
						.setCertificate(certificate).addTokenPolicies(USER_TOKEN_POLICY_ANONYMOUS,
								USER_TOKEN_POLICY_USERNAME, USER_TOKEN_POLICY_X509);

				final EndpointConfiguration.Builder noSecurityBuilder = builder.copy()
						.setSecurityPolicy(SecurityPolicy.None).setSecurityMode(MessageSecurityMode.None);

				endpointConfigurations.add(buildTcpEndpoint(noSecurityBuilder));
				endpointConfigurations.add(buildHttpsEndpoint(noSecurityBuilder));

				endpointConfigurations
						.add(buildTcpEndpoint(builder.copy().setSecurityPolicy(SecurityPolicy.Basic256Sha256)
								.setSecurityMode(MessageSecurityMode.SignAndEncrypt)));

				endpointConfigurations.add(buildHttpsEndpoint(builder.copy()
						.setSecurityPolicy(SecurityPolicy.Basic256Sha256).setSecurityMode(MessageSecurityMode.Sign)));

				final EndpointConfiguration.Builder discoveryBuilder = builder.copy()
						.setPath(configuration.serverPath + "/discovery").setSecurityPolicy(SecurityPolicy.None)
						.setSecurityMode(MessageSecurityMode.None);

				endpointConfigurations.add(buildTcpEndpoint(discoveryBuilder));
				endpointConfigurations.add(buildHttpsEndpoint(discoveryBuilder));
			}
		}

		return endpointConfigurations;
	}

	private EndpointConfiguration buildTcpEndpoint(EndpointConfiguration.Builder base) {
		return base.copy().setTransportProfile(TransportProfile.TCP_UASC_UABINARY).setBindPort(configuration.serverPort)
				.build();
	}

	private EndpointConfiguration buildHttpsEndpoint(EndpointConfiguration.Builder base) {
		return base.copy().setTransportProfile(TransportProfile.HTTPS_UABINARY)
				.setBindPort(configuration.serverPortHttps).build();
	}

	public OpcUaServer getServer() {
		return server;
	}

	public CompletableFuture startup() {
		return server.startup();
	}

	public CompletableFuture shutdown() {
		// nameSpaceOpc.shutdown();

		return server.shutdown();
	}

	public ServiceStatus updateAndGetStatus() {
		// TODO updateAndGetStatus di OPCUA
		return null;
	}

	public org.ar4k.agent.opcua.server.OpcUaServerConfig getConfiguration() {
		return configuration;
	}

	public OpcUaNamespace getNamespace() {
		return nameSpaceOpc;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy