sciortid opened a new issue, #1844:
URL: https://github.com/apache/plc4x/issues/1844
### What would you like to happen?
Hello! First of all I'm pretty sure I'm missing something but i'll try.
I created an OPCUA Python server with username or certificates
authentication policies. It has been tested with OPCUA Expert and i can access
it with both policies methods.
I (and ChatGPT) created a simple standalone example to connect to the server:
```
package opcua;
import org.apache.plc4x.java.api.PlcConnection;
import org.apache.plc4x.java.api.messages.PlcReadRequest;
import org.apache.plc4x.java.api.messages.PlcReadResponse;
import org.apache.plc4x.java.DefaultPlcDriverManager;
import java.util.concurrent.CompletableFuture;
public class OpcUaClientWithCert {
public static void main(String[] args) {
// URL del server OPC UA, con certificato client e chiave privata
inclusi
String serverUrl = "opcua:tcp://127.0.0.1:4840";
String discovery = "true";
String securityPolicy = "Basic256Sha256"; // Percorso del
certificato del client
String clientKeyStore = ".../client_keystore.p12";
String clientKeySotrePass = "clientKeystorePassword"; //
Password della chiave
// Modificare la stringa di connessione per includere certificato e
chiave privata
String connectionString = String.format(
"%s?discovery=%s&security-policy=%s&key-store-file=%s&key-store-password=%s",
serverUrl, discovery, securityPolicy, clientKeyStore,
clientKeySotrePass
);
String nodeId = "ns=2;i=2"; // Sostituire con il nodo che si
desidera leggere
// Connettersi al server OPC UA con certificati
DefaultPlcDriverManager driverManager = new
DefaultPlcDriverManager(); // Crea un'istanza di DefaultPlcDriverManager
try (PlcConnection connection =
driverManager.getConnection(connectionString)) {
if (connection != null && connection.isConnected()) {
System.out.println("Connessione stabilita con il server OPC
UA usando certificati.");
// Creare una richiesta di lettura
PlcReadRequest.Builder builder =
connection.readRequestBuilder();
builder.addTagAddress("myNode", nodeId); // Aggiungere il
nodo da leggere
PlcReadRequest readRequest = builder.build();
// Eseguire la lettura in modo asincrono
CompletableFuture<? extends PlcReadResponse> future =
readRequest.execute();
PlcReadResponse response = future.get();
// Stampare il risultato
System.out.println("Valore letto dal nodo: " +
response.getObject("myNode"));
} else {
System.out.println("Connessione fallita.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
And this is the pom.xml file:
```
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>opcua</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test</name>
<description>test</description>
<dependencies>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-api</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-driver-opcua</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-transport-tcp</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
</project>
```
When it runs, I get the "_Unable to find endpoint.._" exception in this part
of _SecureChannel.java_
```
private void selectEndpoint(CreateSessionResponse sessionResponse)
throws PlcRuntimeException {
// Get a list of the endpoints which match ours.
Stream<EndpointDescription> filteredEndpoints =
sessionResponse.getServerEndpoints().stream()
.map(e -> (EndpointDescription) e)
.filter(this::isEndpoint);
//Determine if the requested security policy is included in the
endpoint
filteredEndpoints.forEach(endpoint -> hasIdentity(
endpoint.getUserIdentityTokens().stream()
.map(p -> (UserTokenPolicy) p)
.toArray(UserTokenPolicy[]::new)
));
if (this.policyId == null) {
throw new PlcRuntimeException("Unable to find endpoint - " +
this.endpoints.get(0));
}
if (this.tokenType == null) {
throw new PlcRuntimeException("Unable to find Security Policy
for endpoint - " + this.endpoints.get(0));
}
}
```
And noticed this is because the policyId is set to null but because
**apparently the _hasIdentity_ function has no option for policy other than
anonymous and username**:
```
private void hasIdentity(UserTokenPolicy[] policies) {
for (UserTokenPolicy identityToken : policies) {
if ((identityToken.getTokenType() ==
UserTokenType.userTokenTypeAnonymous) && (this.username == null)) {
policyId = identityToken.getPolicyId();
tokenType = identityToken.getTokenType();
} else if ((identityToken.getTokenType() ==
UserTokenType.userTokenTypeUserName) && (this.username != null)) {
policyId = identityToken.getPolicyId();
tokenType = identityToken.getTokenType();
}
}
}
```
The policies that my server returns correspond to the ones i set with the
python script:


What am I missing? Shouldn't the library allow this kind of access with just
the cetificate? I expected other "if" for certificate policies. Did i end up in
other functions that should not be used for this policies? In this case, is
there something wrong with the main function?
Please note that the example works if i modify the connection string by just
adding the username & password, correctly reading the node value:
```
String serverUrl = "opcua:tcp://127.0.0.1:4840";
String discovery = "true";
String securityPolicy = "Basic256Sha256"; // Percorso del
certificato del client
String clientKeyStore = "..../client_keystore.p12";
String clientKeySotrePass = "clientKeystorePassword"; //
Password della chiave
String userName = "user1";
String password = "password1";
// Modificare la stringa di connessione per includere certificato e
chiave privata
String connectionString = String.format(
"%s?discovery=%s&security-policy=%s&key-store-file=%s&key-store-password=%s&username=%s&password=%s",
serverUrl, discovery, securityPolicy, clientKeyStore,
clientKeySotrePass, userName, password
);
```
But it does not surprise me because it is using the username policy in this
case (even if Basic256Sha256 is still specified)
### Programming Languages
- [X] plc4j
- [ ] plc4go
- [ ] plc4c
- [ ] plc4net
### Protocols
- [ ] AB-Ethernet
- [ ] ADS /AMS
- [ ] BACnet/IP
- [ ] CANopen
- [ ] DeltaV
- [ ] DF1
- [ ] EtherNet/IP
- [ ] Firmata
- [ ] KNXnet/IP
- [ ] Modbus
- [X] OPC-UA
- [ ] S7
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]