[Bug]: Issue with Special Characters in Connection String (Password and NodeId) OPC UA
What happened?
I have encountered an issue when using Apache PLC4X to connect to an OPC UA server. The problem occurs when the password contains an exclamation mark (!). The connection fails with the following error:
2025-03-27 10:45:22.588 [nioEventLoopGroup-3-1] ERROR o.a.p.j.o.p.OpcuaProtocolLogic - Failed to establish connection java.util.concurrent.CompletionException: org.apache.plc4x.java.api.exceptions.PlcProtocolException: Server returned error BadIdentityTokenInvalid (0x80200000) at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:332) at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:347) at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:636) at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2194) at org.apache.plc4x.java.opcua.context.Conversation.lambda$38(Conversation.java:341) at java.base/java.util.function.Consumer.lambda$andThen$0(Consumer.java:65) at org.apache.plc4x.java.spi.Plc4xNettyWrapper.decode(Plc4xNettyWrapper.java:183) at io.netty.handler.codec.MessageToMessageCodec$2.decode(MessageToMessageCodec.java:81) at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:88) at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) at io.netty.handler.codec.ByteToMessageCodec.channelRead(ByteToMessageCodec.java:103) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:1583) Caused by: org.apache.plc4x.java.api.exceptions.PlcProtocolException: Server returned error BadIdentityTokenInvalid (0x80200000) at org.apache.plc4x.java.opcua.context.Conversation.toProtocolException(Conversation.java:417) ... 33 common frames omitted
I have successfully connected to other OPC UA servers using anonymous authentication and username/password authentication. However, when the password contains special characters (like !), authentication fails.
Another related issue occurs when reading NodeIds that contain single quotes (') or double quotes (") in their identifier. I cannot read values from these nodes, and escaping the characters does not help.
For example, I cannot read the following NodeId(copied from UaExpert) : ns=3;s="Stationen". When attempting to read it, I receive the following error:
`2025-03-27 10:52:07.280 [nioEventLoopGroup-3-1] ERROR o.a.p.j.o.p.OpcuaProtocolLogic - Error while reading value from OPC UA server error code:-
ÔòöÔòÉStatusCode/statusCodeÔòù Ôòæ0x80340000 2150891520 Ôòæ ÔòÜÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòÉÔòØ
2025-03-27 10:52:07.284 [main] INFO o.p.webinar.plc4x.SingleApiDemo - Process the responce... 2025-03-27 10:52:07.284 [main] ERROR o.p.webinar.plc4x.SingleApiDemo - Error[Constant]: NOT_FOUND 2025-03-27 10:52:07.286 [plc4x-tm-thread-3] INFO o.a.p.j.opcua.context.SecureChannel - Disconnecting 2025-03-27 10:52:07.288 [main] INFO o.a.p.j.s.c.NettyChannelFactory - Channel is closed, closing worker Group also 2025-03-27 10:52:09.359 [main] INFO o.a.p.j.s.c.NettyChannelFactory - Worker Group was closed successfully!`
Additional Information: Using UaExpert, both authentication and reading the above NodeId work without any issues.
It seems like special characters in the connection string parameters are not being handled correctly.
Steps to Reproduce: Try to connect to an OPC UA server with a password containing !.
Try to read a NodeId containing double quotes (") in its identifier (e.g., ns=3;s="Stationen").
Environment:
Java version: 21
OPC UA Server: SecurityPolicy = None
PLC4x: i have also tried 0.13.0-SNAPSHOT
Thank you for looking into this issue!
Version
v0.12.0
Programming Languages
- [ ] plc4c
- [ ] plc4go
- [x] plc4j
- [ ] plc4net
- [ ] plc4py
Protocols
- [ ] AB-Ethernet
- [ ] ADS /AMS
- [ ] BACnet/IP
- [ ] C-Bus
- [ ] CANopen
- [ ] EtherNet/IP
- [ ] Firmata
- [ ] IEC-69870
- [ ] KNXnet/IP
- [ ] Modbus
- [x] OPC-UA
- [ ] Profinet
- [ ] S7
The issue I had with reading values that contain double quotes (") has been resolved. It turned out that I was missing the following dependency. Unfortunately it is not mentioned in the Documentation:
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-transport-tcp</artifactId>
<version>0.12.0</version>
</dependency>
Hello @anuriwise, is this issue solved for you? Overall our drivers usually stick to transport API, in case of OPC-UA we indeed could include TCP as it is only one transport supported by this driver.
Hello @splatch, only part of my issue has been resolved. I still cannot establish a connection to an OPC UA server that requires authentication when the password contains a special character (in my case, '!').
Please try to replace ! with %21 if you pass it in URL. You can also try to pass username/password directly to PlcConnectionManager while calling getConnection.
@splatch thank you for this idea, but i've tried it already and it didn't work.