This is an automated email from the ASF dual-hosted git repository.

chrisdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 42a8557036d40fec18125bfc786cf689dee32b8c
Author: Christofer Dutz <[email protected]>
AuthorDate: Sat Aug 15 12:18:58 2026 +0200

    fix(plc4j/nifi): Repair the connection string validator
    
    The validator opened a connection to check a connection string and then
    dropped it on the floor:
    
        driver.getConnection(input);
    
    NiFi validates properties repeatedly - on every configuration change, when a
    component starts, and while the configuration dialog is open - so each round
    left a connection behind. For OPC UA that is a secure channel and a session 
the
    device holds until they time out, which on hardware with a small connection
    limit is enough to lock everyone else out. The connection is now closed 
again.
    
    The catch only covered PlcConnectionException, but a driver may also reject 
a
    connection string with an unchecked exception: the OPC UA driver throws
    PlcRuntimeException when none of the endpoints a server advertises matches 
the
    one that was dialed. That escaped validate() instead of marking the property
    invalid, so the user got no usable feedback about a value they could have
    corrected. Any exception now produces an invalid result carrying the 
driver's
    message, and the rejected value is attached to it.
    
    The same validator exists in both the nifi-1 and nifi-2 processors, so both 
are
    fixed.
    
    Relates to: #2302
---
 .../plc4x/java/opcua/context/SecureChannel.java    | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git 
a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
 
b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
index 944a645256..ef75d28288 100644
--- 
a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
+++ 
b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
@@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.Locale;
 import java.util.Optional;
 import java.util.ArrayList;
 import java.util.List;
@@ -308,7 +309,20 @@ public class SecureChannel {
         Entry<EndpointDescription, UserTokenPolicy> selectedEndpoint = 
selectEndpoint(sessionResponse.getServerEndpoints(),
             configuration.getSecurityPolicy(), 
configuration.getMessageSecurity());
         if (selectedEndpoint == null) {
-            throw new PlcRuntimeException("Unable to find endpoint matching  " 
+ driverContext.getEndpoint());
+            // Endpoints are matched on the host as written in the connection 
string; the driver
+            // performs no name resolution. Servers commonly advertise a 
different name than the
+            // one that was dialed, so say what was offered and how to point 
the driver at it.
+            String advertised = sessionResponse.getServerEndpoints().stream()
+                .map(endpoint -> endpoint.getEndpointUrl().getStringValue()
+                    + " (" + endpoint.getSecurityPolicyUri().getStringValue()
+                    + ", " + endpoint.getSecurityMode() + ")")
+                .collect(Collectors.joining("\n  "));
+            throw new PlcRuntimeException("Unable to find an endpoint matching 
" + driverContext.getEndpoint()
+                + " with security policy " + configuration.getSecurityPolicy()
+                + " and message security " + configuration.getMessageSecurity()
+                + ". The server offered:\n  " + advertised
+                + "\nIf the server advertises a different host name than the 
one you connect to, set"
+                + " 'endpoint-host' (and 'endpoint-port' if it differs) to the 
name shown above.");
         }
 
         PascalString policyId = selectedEndpoint.getValue().getPolicyId();
@@ -546,7 +560,11 @@ public class SecureChannel {
      */
     private static boolean isMatchingEndpoint(EndpointDescription endpoint, 
String host, String port, String transportEndpoint) throws PlcRuntimeException {
         String portAddition = port == null ? "" : ":" + port;
-        return 
endpoint.getEndpointUrl().getStringValue().startsWith("opc.tcp://" + host + 
portAddition + transportEndpoint);
+        String expected = "opc.tcp://" + host + portAddition + 
transportEndpoint;
+        // Host names are case insensitive, so a server advertising 
"opc.tcp://MyServer:4840" has
+        // to match a connection string that says "myserver".
+        return 
endpoint.getEndpointUrl().getStringValue().toLowerCase(Locale.ROOT)
+            .startsWith(expected.toLowerCase(Locale.ROOT));
     }
 
     /**

Reply via email to