diff --git a/plc4j/tools/opcua-server/pom.xml b/plc4j/tools/opcua-server/pom.xml index 5c857efb8..fa5572689 100644 --- a/plc4j/tools/opcua-server/pom.xml +++ b/plc4j/tools/opcua-server/pom.xml @@ -35,31 +35,18 @@ - + org.eclipse.milo - dictionary-manager - 0.6.16 + milo-sdk-server + 1.1.8 org.eclipse.milo - sdk-server - 0.6.16 - - - org.eclipse.milo - stack-server - 0.6.16 - - - org.eclipse.milo - stack-core - 0.6.16 - - - org.eclipse.milo - sdk-core - 0.6.16 + milo-transport + 1.1.8 diff --git a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/OPCUAServer.java b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/OPCUAServer.java index ad88b5b77..18bd4c016 100644 --- a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/OPCUAServer.java +++ b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/OPCUAServer.java @@ -27,6 +27,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.FileSystems; @@ -37,30 +38,39 @@ import org.apache.plc4x.java.opcuaserver.context.CertificateKeyPair; import org.apache.plc4x.java.opcuaserver.context.CertificateGenerator; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.eclipse.milo.opcua.sdk.server.EndpointConfig; 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.OpcUaServerConfig; +import org.eclipse.milo.opcua.sdk.server.identity.AnonymousIdentityValidator; 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.stack.core.NodeIds; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaRuntimeException; +import org.eclipse.milo.opcua.stack.core.security.DefaultApplicationGroup; 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.DefaultServerCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.FileBasedCertificateQuarantine; +import org.eclipse.milo.opcua.stack.core.security.FileBasedTrustListManager; +import org.eclipse.milo.opcua.stack.core.security.KeyStoreCertificateStore; +import org.eclipse.milo.opcua.stack.core.security.RsaSha256CertificateFactory; 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.builtin.NodeId; 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.server.EndpointConfiguration; -import org.eclipse.milo.opcua.stack.server.security.DefaultServerCertificateValidator; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransport; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransportConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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 static org.eclipse.milo.opcua.sdk.server.OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS; +import static org.eclipse.milo.opcua.sdk.server.OpcUaServerConfig.USER_TOKEN_POLICY_USERNAME; +import static org.eclipse.milo.opcua.sdk.server.OpcUaServerConfig.USER_TOKEN_POLICY_X509; import org.apache.commons.cli.*; @@ -210,6 +220,7 @@ public static void main(String[] args) throws Exception { private final OpcUaServer server; private final Plc4xNamespace plc4xNamespace; private final String certificateFileName = "plc4x-opcuaserver.pfx"; + private final String certificateAlias = "plc4x-certificate-alias"; public OPCUAServer(String[] args) throws Exception { @@ -222,14 +233,27 @@ public OPCUAServer(String[] args) throws Exception { } logger.info("Security Directory is: {}", securityTempDir.getAbsolutePath()); // + // 1.x cert/transport bootstrap follows Milo's ExampleServer pattern. File pkiDir = FileSystems.getDefault().getPath(config.getDir()).resolve("pki").toFile(); - DefaultTrustListManager trustListManager = new DefaultTrustListManager(pkiDir); + // Keep the directory layout of the Milo 0.6 trust list ("issuers", rejected certificates directly in + // "rejected") instead of the 1.x default ("issuer", "rejected/certs"), so existing installations keep + // their issuer certificates and CRLs. + Path issuerCertsDir = Files.createDirectories(pkiDir.toPath().resolve("issuers").resolve("certs")); + Path issuerCrlDir = Files.createDirectories(pkiDir.toPath().resolve("issuers").resolve("crl")); + Path trustedCertsDir = Files.createDirectories(pkiDir.toPath().resolve("trusted").resolve("certs")); + Path trustedCrlDir = Files.createDirectories(pkiDir.toPath().resolve("trusted").resolve("crl")); + FileBasedTrustListManager trustListManager = + new FileBasedTrustListManager(issuerCertsDir, issuerCrlDir, trustedCertsDir, trustedCrlDir); + trustListManager.initialize(); logger.info("Certificate directory is: {}, Please move certificates from the reject dir to the trusted directory to allow encrypted access", pkiDir.getAbsolutePath()); - DefaultServerCertificateValidator certificateValidator = new DefaultServerCertificateValidator(trustListManager); + FileBasedCertificateQuarantine certificateQuarantine = + FileBasedCertificateQuarantine.create(pkiDir.toPath().resolve("rejected")); + + DefaultServerCertificateValidator certificateValidator = + new DefaultServerCertificateValidator(trustListManager, certificateQuarantine); UsernameIdentityValidator identityValidator = new UsernameIdentityValidator( - true, authChallenge -> { boolean check = passwordConfig.checkPassword(authChallenge.getUsername(), authChallenge.getPassword()); if (!check) { @@ -254,7 +278,7 @@ public OPCUAServer(String[] args) throws Exception { certificate = CertificateGenerator.generateCertificate(); logger.info("Creating new KeyStore at {}", serverKeyStore); keyStore.load(null, passwordConfig.getSecurityPassword().toCharArray()); - keyStore.setKeyEntry("plc4x-certificate-alias", certificate.getKeyPair().getPrivate(), passwordConfig.getSecurityPassword().toCharArray(), new X509Certificate[] { certificate.getCertificate() }); + keyStore.setKeyEntry(certificateAlias, certificate.getKeyPair().getPrivate(), passwordConfig.getSecurityPassword().toCharArray(), new X509Certificate[] { certificate.getCertificate() }); keyStore.store(new FileOutputStream(serverKeyStore), passwordConfig.getSecurityPassword().toCharArray()); } else { logger.info("Loading KeyStore at {}", serverKeyStore); @@ -271,22 +295,27 @@ public OPCUAServer(String[] args) throws Exception { StatusCodes.Bad_ConfigurationError, "certificate is missing the application URI")); - Set endpointConfigurations = new LinkedHashSet<>(); + Set endpointConfigurations = new LinkedHashSet<>(); String hostname = InetAddress.getLocalHost().getHostName(); - EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder() + EndpointConfig.Builder builder = EndpointConfig.newBuilder() .setBindAddress("0.0.0.0") .setHostname(hostname) .setPath("/plc4x") .setCertificate(certificate.getCertificate()) .setBindPort(config.getTcpPort()) + .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) .setSecurityMode(MessageSecurityMode.None) .addTokenPolicies( - USER_TOKEN_POLICY_ANONYMOUS, USER_TOKEN_POLICY_USERNAME, USER_TOKEN_POLICY_X509); + // Anonymous clients can read and write every configured tag, so they are only offered when asked for. + if (config.getAllowAnonymousAccess()) { + builder.addTokenPolicies(USER_TOKEN_POLICY_ANONYMOUS); + } + endpointConfigurations.add( builder.copy() .setSecurityPolicy(SecurityPolicy.Basic256Sha256) @@ -302,14 +331,14 @@ public OPCUAServer(String[] args) throws Exception { .build() ); - EndpointConfiguration.Builder discoveryBuilder = builder.copy() + EndpointConfig.Builder discoveryBuilder = builder.copy() .setPath("/discovery") .setSecurityPolicy(SecurityPolicy.None) .setSecurityMode(MessageSecurityMode.None); endpointConfigurations.add(discoveryBuilder.build()); - EndpointConfiguration.Builder discoveryLocalBuilder = builder.copy() + EndpointConfig.Builder discoveryLocalBuilder = builder.copy() .setPath("/discovery") .setHostname("127.0.0.1") .setSecurityPolicy(SecurityPolicy.None) @@ -317,7 +346,7 @@ public OPCUAServer(String[] args) throws Exception { endpointConfigurations.add(discoveryLocalBuilder.build()); - EndpointConfiguration.Builder discoveryLocalPlc4xBuilder = builder.copy() + EndpointConfig.Builder discoveryLocalPlc4xBuilder = builder.copy() .setPath("/plc4x/discovery") .setHostname("127.0.0.1") .setSecurityPolicy(SecurityPolicy.None) @@ -326,26 +355,64 @@ public OPCUAServer(String[] args) throws Exception { endpointConfigurations.add(discoveryLocalPlc4xBuilder.build()); if (!config.getDisableInsecureEndpoint()) { - EndpointConfiguration.Builder noSecurityBuilder = builder.copy() + EndpointConfig.Builder noSecurityBuilder = builder.copy() .setSecurityPolicy(SecurityPolicy.None) .setTransportProfile(TransportProfile.TCP_UASC_UABINARY); endpointConfigurations.add(noSecurityBuilder.build()); } //Always add an unsecured endpoint to localhost, this is a work around for Milo throwing an exception if it isn't here. - EndpointConfiguration.Builder noSecurityBuilder = builder.copy() + EndpointConfig.Builder noSecurityBuilder = builder.copy() .setSecurityPolicy(SecurityPolicy.None) .setHostname("127.0.0.1") .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) .setSecurityMode(MessageSecurityMode.None); endpointConfigurations.add(noSecurityBuilder.build()); - DefaultCertificateManager certificateManager = new DefaultCertificateManager( - certificate.getKeyPair(), - Arrays.stream(keyStore.getCertificateChain(keyStore.getCertificateAlias(certificate.getCertificate())))// Added so that existing certificates are loaded on startup + // In Milo 1.x the application's own certificate/key live in a CertificateStore, and the + // CertificateManager is assembled from a quarantine + an application group. We reuse the + // key pair and chain already loaded from the PKCS#12 keystore above. + final KeyPair serverKeyPair = certificate.getKeyPair(); + final String serverCertificateAlias = keyStore.getCertificateAlias(certificate.getCertificate()); + final X509Certificate[] serverCertificateChain = + Arrays.stream(keyStore.getCertificateChain(serverCertificateAlias)) .map(X509Certificate.class::cast) - .toArray(X509Certificate[]::new) - ); + .toArray(X509Certificate[]::new); + + KeyStoreCertificateStore certificateStore = new KeyStoreCertificateStore( + new KeyStoreCertificateStore.Settings( + serverKeyStore.toPath(), + () -> passwordConfig.getSecurityPassword().toCharArray(), + alias -> passwordConfig.getSecurityPassword().toCharArray())) { + // Milo 1.x looks the server certificate up as "server-rsa-sha256". Point it at the entry loaded + // above instead (the first alias of an existing keystore, as before, or certificateAlias for a + // new one), so an existing keystore is used as is instead of gaining a second entry. + @Override + protected String getAlias(NodeId certificateTypeId) { + return NodeIds.RsaSha256ApplicationCertificateType.equals(certificateTypeId) + ? serverCertificateAlias + : super.getAlias(certificateTypeId); + } + }; + certificateStore.initialize(); + + RsaSha256CertificateFactory certificateFactory = new RsaSha256CertificateFactory() { + @Override + protected KeyPair createRsaSha256KeyPair() { + return serverKeyPair; + } + + @Override + protected X509Certificate[] createRsaSha256CertificateChain(KeyPair keyPair) { + return serverCertificateChain; + } + }; + + DefaultApplicationGroup defaultApplicationGroup = DefaultApplicationGroup.createAndInitialize( + trustListManager, certificateStore, certificateFactory, certificateValidator); + + DefaultCertificateManager certificateManager = + new DefaultCertificateManager(certificateQuarantine, defaultApplicationGroup); OpcUaServerConfig serverConfig = OpcUaServerConfig.builder() .setApplicationUri(applicationUri) @@ -359,13 +426,16 @@ public OPCUAServer(String[] args) throws Exception { OpcUaServer.SDK_VERSION, "", DateTime.now())) .setCertificateManager(certificateManager) - .setTrustListManager(trustListManager) - .setCertificateValidator(certificateValidator) - .setIdentityValidator(new CompositeValidator(identityValidator, x509IdentityValidator)) + .setIdentityValidator(config.getAllowAnonymousAccess() + ? new CompositeValidator(AnonymousIdentityValidator.INSTANCE, identityValidator, x509IdentityValidator) + : new CompositeValidator(identityValidator, x509IdentityValidator)) .setProductUri("urn:eclipse:milo:plc4x:server") .build(); - server = new OpcUaServer(serverConfig); + server = new OpcUaServer(serverConfig, transportProfile -> { + OpcTcpServerTransportConfig transportConfig = OpcTcpServerTransportConfig.newBuilder().build(); + return new OpcTcpServerTransport(transportConfig); + }); plc4xNamespace = new Plc4xNamespace(server, config); plc4xNamespace.startup(); diff --git a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java index 76cf0553a..e225b9242 100644 --- a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java +++ b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java @@ -29,9 +29,9 @@ import org.apache.plc4x.java.api.types.PlcValueType; import org.apache.plc4x.java.utils.cache.PlcConnectionCache; import org.eclipse.milo.opcua.sdk.server.AbstractLifecycle; -import org.eclipse.milo.opcua.sdk.server.api.DataItem; +import org.eclipse.milo.opcua.sdk.server.items.DataItem; import org.eclipse.milo.opcua.sdk.server.nodes.filters.AttributeFilterContext; -import org.eclipse.milo.opcua.stack.core.Identifiers; +import org.eclipse.milo.opcua.stack.core.NodeIds; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; @@ -123,42 +123,42 @@ public void removeTag(DataItem item) { public static NodeId getNodeId(PlcValueType plcValueType) { switch (plcValueType) { case BOOL: - return Identifiers.Boolean; + return NodeIds.Boolean; case BYTE: case USINT: - return Identifiers.Byte; + return NodeIds.Byte; case SINT: - return Identifiers.SByte; + return NodeIds.SByte; case INT: - return Identifiers.Int16; + return NodeIds.Int16; case WORD: case UINT: - return Identifiers.UInt16; + return NodeIds.UInt16; case DINT: - return Identifiers.Int32; + return NodeIds.Int32; case DWORD: case UDINT: - return Identifiers.UInt32; + return NodeIds.UInt32; case LINT: - return Identifiers.Int64; + return NodeIds.Int64; case ULINT: case LWORD: - return Identifiers.UInt64; + return NodeIds.UInt64; case REAL: - return Identifiers.Float; + return NodeIds.Float; case LREAL: - return Identifiers.Double; + return NodeIds.Double; case CHAR: case WCHAR: case STRING: case WSTRING: - return Identifiers.String; + return NodeIds.String; default: - return Identifiers.BaseDataType; + return NodeIds.BaseDataType; } } - public DataValue getValue(AttributeFilterContext.GetAttributeContext ctx, String tag, String connectionString) { + public DataValue getValue(AttributeFilterContext ctx, String tag, String connectionString) { PlcConnection connection = null; try { diff --git a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java index 9185dbada..5eadedd3e 100644 --- a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java +++ b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java @@ -27,15 +27,14 @@ import org.eclipse.milo.opcua.sdk.core.Reference; import org.eclipse.milo.opcua.sdk.core.ValueRank; 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.ManagedNamespaceWithLifecycle; -import org.eclipse.milo.opcua.sdk.server.api.MonitoredItem; -import org.eclipse.milo.opcua.sdk.server.dtd.DataTypeDictionaryManager; +import org.eclipse.milo.opcua.sdk.server.ManagedNamespaceWithLifecycle; +import org.eclipse.milo.opcua.sdk.server.items.DataItem; +import org.eclipse.milo.opcua.sdk.server.items.MonitoredItem; import org.eclipse.milo.opcua.sdk.server.nodes.UaFolderNode; import org.eclipse.milo.opcua.sdk.server.nodes.UaVariableNode; import org.eclipse.milo.opcua.sdk.server.nodes.filters.AttributeFilters; import org.eclipse.milo.opcua.sdk.server.util.SubscriptionModel; -import org.eclipse.milo.opcua.stack.core.Identifiers; +import org.eclipse.milo.opcua.stack.core.NodeIds; 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; @@ -57,7 +56,6 @@ public class Plc4xNamespace extends ManagedNamespaceWithLifecycle { private final Configuration config; private final Logger logger = LoggerFactory.getLogger(getClass()); - private final DataTypeDictionaryManager dictionaryManager; private final SubscriptionModel subscriptionModel; private final Plc4xCommunication plc4xServer; @@ -65,9 +63,7 @@ public Plc4xNamespace(OpcUaServer server, Configuration c) { super(server, APPLICATIONID); this.config = c; subscriptionModel = new SubscriptionModel(server, this); - dictionaryManager = new DataTypeDictionaryManager(getNodeContext(), APPLICATIONID); plc4xServer = new Plc4xCommunication(); - getLifecycleManager().addLifecycle(dictionaryManager); getLifecycleManager().addLifecycle(subscriptionModel); getLifecycleManager().addLifecycle(plc4xServer); getLifecycleManager().addStartupTask(this::addNodes); @@ -88,8 +84,8 @@ private void addNodes() { folderNode.addReference(new Reference( folderNode.getNodeId(), - Identifiers.Organizes, - Identifiers.ObjectsFolder.expanded(), + NodeIds.Organizes, + NodeIds.ObjectsFolder.expanded(), false )); @@ -106,7 +102,7 @@ private void addConfiguredNodes(UaFolderNode rootNode, DeviceConfiguration c) { final String tag = item.getAddress(); Class datatype = null; - NodeId typeId = Identifiers.String; + NodeId typeId = NodeIds.String; UaVariableNode node = null; Variant variant = null; try { @@ -124,7 +120,7 @@ private void addConfiguredNodes(UaFolderNode rootNode, DeviceConfiguration c) { .setBrowseName(newQualifiedName(name)) .setDisplayName(LocalizedText.english(name)) .setDataType(typeId) - .setTypeDefinition(Identifiers.BaseDataVariableType) + .setTypeDefinition(NodeIds.BaseDataVariableType) .setValueRank(ValueRank.OneDimension.getValue()) .setArrayDimensions(new UInteger[]{uint(length)}) .build(); @@ -142,7 +138,7 @@ private void addConfiguredNodes(UaFolderNode rootNode, DeviceConfiguration c) { .setBrowseName(newQualifiedName(name)) .setDisplayName(LocalizedText.english(name)) .setDataType(typeId) - .setTypeDefinition(Identifiers.BaseDataVariableType) + .setTypeDefinition(NodeIds.BaseDataVariableType) .build(); variant = new Variant(0); } diff --git a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/configuration/Configuration.java b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/configuration/Configuration.java index 2059b926c..b2808dc2e 100644 --- a/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/configuration/Configuration.java +++ b/plc4j/tools/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/configuration/Configuration.java @@ -40,6 +40,9 @@ public class Configuration { @JsonProperty private final Boolean disableInsecureEndpoint = true; + @JsonProperty + private final Boolean allowAnonymousAccess = false; + @JsonProperty private List devices; @@ -61,6 +64,10 @@ public boolean getDisableInsecureEndpoint() { return disableInsecureEndpoint; } + public boolean getAllowAnonymousAccess() { + return allowAnonymousAccess; + } + public String getDir() { return dir; } diff --git a/plc4j/tools/opcua-server/src/main/resources/config.yml b/plc4j/tools/opcua-server/src/main/resources/config.yml index c17293819..068e15e1d 100644 --- a/plc4j/tools/opcua-server/src/main/resources/config.yml +++ b/plc4j/tools/opcua-server/src/main/resources/config.yml @@ -21,6 +21,8 @@ version: 0.8 #dir: "./security" name: Plc4x.OPC.UA.Server disableInsecureEndpoint: true +# true lets clients connect without credentials and read and write every tag below. +allowAnonymousAccess: false tcpPort: 12687 devices: - name: "Simulated Device" diff --git a/plc4j/tools/opcua-server/src/test/java/org/apache/plc4x/java/opcuaserver/configuration/ConfigurationTest.java b/plc4j/tools/opcua-server/src/test/java/org/apache/plc4x/java/opcuaserver/configuration/ConfigurationTest.java new file mode 100644 index 000000000..eac11809f --- /dev/null +++ b/plc4j/tools/opcua-server/src/test/java/org/apache/plc4x/java/opcuaserver/configuration/ConfigurationTest.java @@ -0,0 +1,47 @@ +/* + * 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 + * + * https://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.plc4x.java.opcuaserver.configuration; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import org.junit.jupiter.api.Test; + +public class ConfigurationTest { + + private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + + @Test + public void anonymousAccessIsOffWhenNotConfigured() throws Exception { + Configuration config = mapper.readValue("dir: \"target/test-tmp/\"\n", Configuration.class); + + assertFalse(config.getAllowAnonymousAccess()); + } + + @Test + public void anonymousAccessCanBeTurnedOn() throws Exception { + Configuration config = mapper.readValue( + "dir: \"target/test-tmp/\"\nallowAnonymousAccess: true\n", Configuration.class); + + assertTrue(config.getAllowAnonymousAccess()); + } + +}