Introduction
This article describes how you can provide the user identity that your OPC UA client application will use to connect to the OPC UA server. Whether or not this user authentication is needed depends on how the OPC UA server is set up. Depending on whether or not you are providing the user identity, and depending on which concrete user you specify, the OPC UA server may allow you to perform different set of operations, or it may reject the connection altogether.
In your application based on OPC Studio, you specify the user inside the EasyUAClient object parameters (see User Identity in QuickOPC-UA), or as part of the OPC UA endpoint descriptor (UAEndpointDescriptor Class). The main part of the endpoint descriptor is the endpoint URL, but there are other parts that can be specified as well, and one of them is the UserIdentity Property. This property contains a user identity object, which is an instance of the UserIdentity Class.
The user identity object acts as a collection of token infos. The token info specifies the user to be authenticated using a particular approach, such as anonymous, user name, Kerberos (issued), or X.509 certificate. Each token info can be either configured, or not. Token infos that are not configured are ignored for user authentication. When QuickOPC connects to the OPC UA server, it matches the configured token infos with the token types supported by the server endpoint, and finds the best match. If no match is found, no user token is passed to the server, which usually results in an error.
Most often, you will configure one user token in the user identity. If you configure multiple user tokens in the user identity, they should logically correspond to the same user - just specified in different ways. This way, the proper user token can be chosen when connecting to different servers or endpoints - but there will no ambiguity as to which user is actually connecting.
Manipulating this object in the endpoint descriptor that you use to connect to the OPC UA server gives you a way to specify the user identity. It can be done by setting the various properties and sub-properties. Alternatively, in .NET languages, QuickOPC gives you extension methods (on the UAEndpointDescriptor Class) that allow you to create an endpoint descriptor with a chosen token info type using a single method call. These extension methods are called WithXXXXIdentity, where XXXX is the type of the token info to be used.
Anonymous token
Anonymous token in the user identity is represented by the AnonymousTokenInfo Class object in the UserIdentity.AnonymousTokenInfo Property, and is configured by default. You can control whether or not it is configured by manipulating the UserIdentity.AnonymousTokenInfo.IsEnabled Property.
With many servers, it does not make any difference whether an anonymous token is specified or not, and if there is no user token, the behavior is the same as if the anonymous token was specified.
Kerberos (issued) token
This functionality is not available under (or the text does not apply to) .NET 6+ development platform.
In Windows environments, this token type allows you to use the network credentials for OPC UA user authentication. Either a custom network credential, or the current user's identity can be used. The custom network credential specifies the user name, password, and domain.
Kerberos (issued) token in the user identity is represented by the KerberosTokenInfo Class object in the UserIdentity.KerberosTokenInfo Property. The actual user that you want to authenticate is specified by the NetworkSecurity object in the UserIdentity.KerberosTokenInfo.NetworkSecurity Property.
In .NET languages, instead of manipulating the object properties, you can take an OPC UA endpoint descriptor, and create a new endpoint descriptor from it, with user identity provided by the Kerberos (issued) token. To do so, use the WithKerberosIdentity Method.
User name token
The user name token uses a user name (string) and an optional password (a string) to identify and authenticate the user. The user name token is represented by the UserNameTokenInfo Class object in the UserIdentity.UserNameTokenInfo Property. The user name is contained in the UserName Property and the password in the Password Property of the UserNameTokenInfo Class. The user name token info is considered configured when the user name or the password is not empty.
In .NET languages, instead of manipulating the object properties, you can take an OPC UA endpoint descriptor, and create a new endpoint descriptor from it, with user identity provided by the user name token. To do so, use the WithUserNameIdentity Method.
Example
.NET
// Shows how to find all registrations in the GDS.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.
using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.Discovery;
using OpcLabs.EasyOpc.UA.Extensions;
using OpcLabs.EasyOpc.UA.Gds;
using OpcLabs.EasyOpc.UA.OperationModel;
namespace UADocExamples.Gds._EasyUAGlobalDiscoveryClient
{
class FindApplications
{
public static void Main1()
{
// Define which GDS we will work with.
UAEndpointDescriptor gdsEndpointDescriptor =
((UAEndpointDescriptor)"opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer")
.WithUserNameIdentity("appuser", "demo");
// Instantiate the global discovery client object
var globalDiscoveryClient = new EasyUAGlobalDiscoveryClient();
// Find all (client or server) applications registered in the GDS.
UAApplicationDescription[] applicationDescriptionArray;
try
{
globalDiscoveryClient.QueryApplications(
gdsEndpointDescriptor: gdsEndpointDescriptor,
startingRecordId: 0,
maximumRecordsToReturn: 0,
applicationName: "",
applicationUriString: "",
applicationTypes: UAApplicationTypes.All,
productUriString: "",
serverCapabilities: new string[0],
lastCounterResetTime: out _,
nextRecordId: out _,
applications: out applicationDescriptionArray);
}
catch (UAException uaException)
{
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
return;
}
// For each application returned by the query, find its registrations in the GDS.
foreach (UAApplicationDescription applicationDescription in applicationDescriptionArray)
{
Console.WriteLine();
Console.WriteLine("Application URI string: {0}", applicationDescription.ApplicationUriString);
UAApplicationRecordDataType[] applicationRecordArray;
try
{
applicationRecordArray = globalDiscoveryClient.FindApplications(
gdsEndpointDescriptor,
applicationDescription.ApplicationUriString);
}
catch (UAException uaException)
{
Console.WriteLine(" *** Failure: {0}", uaException.GetBaseException().Message);
continue;
}
// Display results
foreach (UAApplicationRecordDataType applicationRecord in applicationRecordArray)
Console.WriteLine(" Application ID: {0}", applicationRecord.ApplicationId);
}
// Example output:
//
//Application URI string: urn:sampleserver
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=09ecaa08-6ec6-462c-a214-1e66a3099107
//
//Application URI string: urn:alarmconditionserver
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=783e1e9a-8036-43b6-928f-97488c460266
//
//Application URI string: urn:PC:MultiTargetUADocExamples:5.54.1026.1:neutral:null
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=9e700ea5-55a6-4c3c-ba9f-b91c890dc519
//
//Application URI string: urn:PC:UADocExamples:5.56.0.16:neutral:null
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=e182e28c-086b-4fc7-82c7-70ca7cda3033
//
//Application URI string: urn:PC:cscript:5.812.10240.16384
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=aec94459-f513-4979-8619-8383555fca61
}
}
}
' Shows how to find all registrations in the GDS.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.Discovery
Imports OpcLabs.EasyOpc.UA.Extensions
Imports OpcLabs.EasyOpc.UA.Gds
Imports OpcLabs.EasyOpc.UA.OperationModel
Namespace Gds._EasyUAGlobalDiscoveryClient
Friend Class FindApplications
Public Shared Sub Main1()
' Define which GDS we will work with.
Dim gdsEndpointDescriptor As UAEndpointDescriptor =
New UAEndpointDescriptor("opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer") _
.WithUserNameIdentity("appuser", "demo")
' Instantiate the global discovery client object
Dim globalDiscoveryClient = New EasyUAGlobalDiscoveryClient()
' Find all (client or server) applications registered in the GDS.
Dim applicationDescriptionArray() As UAApplicationDescription = Nothing
Try
Dim lastCounterResetTime As DateTime
Dim nextRecordId As Long
globalDiscoveryClient.QueryApplications(
gdsEndpointDescriptor:=gdsEndpointDescriptor,
startingRecordId:=0,
maximumRecordsToReturn:=0,
applicationName:="",
applicationUriString:="",
applicationTypes:=UAApplicationTypes.All,
productUriString:="",
serverCapabilities:=New String() {},
lastCounterResetTime:=lastCounterResetTime,
nextRecordId:=nextRecordId,
applications:=applicationDescriptionArray)
Catch uaException As UAException
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
Exit Sub
End Try
' For each application returned by the query, find its registrations in the GDS.
For Each applicationDescription As UAApplicationDescription In applicationDescriptionArray
Console.WriteLine()
Console.WriteLine("Application URI string: {0}", applicationDescription.ApplicationUriString)
Dim applicationRecordArray() As UAApplicationRecordDataType
Try
applicationRecordArray = globalDiscoveryClient.FindApplications(
gdsEndpointDescriptor,
applicationDescription.ApplicationUriString)
Catch uaException As UAException
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
Continue For
End Try
' Display results
For Each applicationRecord As UAApplicationRecordDataType In applicationRecordArray
Console.WriteLine(" Application ID: {0}", applicationRecord.ApplicationId)
Next applicationRecord
Next applicationDescription
End Sub
End Class
End Namespace
COM
// Shows how to find all registrations in the GDS.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in Object Pascal (Delphi) on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-OP .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.
class procedure FindApplications.Main;
var
ApplicationDescription: _UAApplicationDescription;
ApplicationDescriptionArray: OleVariant;
ApplicationName: WideString;
ApplicationRecord: _UAApplicationRecordDataType;
ApplicationRecordArray: OleVariant;
ApplicationUriString: WideString;
GlobalDiscoveryClient: OpcLabs_EasyOpcUA_TLB._EasyUAGlobalDiscoveryClient;
GdsEndpointDescriptor: _UAEndpointDescriptor;
I, J: integer;
LastCounterResetTime: TDateTime;
MaximumRecordsToReturn: Integer;
NextRecordId: Integer;
ProductUriString: WideString;
ServerCapabilities: array of string;
StartingRecordId: Integer;
begin
// Define which GDS we will work with.
GdsEndpointDescriptor := CoUAEndpointDescriptor.Create;
GdsEndpointDescriptor.UrlString := 'opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer';
GdsEndpointDescriptor.UserIdentity.UserNameTokenInfo.UserName := 'appadmin';
GdsEndpointDescriptor.UserIdentity.UserNameTokenInfo.Password := 'demo';
// Instantiate the global discovery client object
GlobalDiscoveryClient := CoEasyUAGlobalDiscoveryClient.Create;
// Find all (client or server) applications registered in the GDS.
StartingRecordId := 0;
MaximumRecordsToReturn := 0;
ApplicationName := '';
ApplicationUriString := '';
ProductUriString := '';
try
GlobalDiscoveryClient.QueryApplications(
GdsEndpointDescriptor,
StartingRecordId,
MaximumRecordsToReturn,
ApplicationName,
ApplicationUriString,
UAApplicationTypes_All,
ProductUriString,
ServerCapabilities,
LastCounterResetTime,
NextRecordId,
ApplicationDescriptionArray);
except
on E: EOleException do
begin
WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
end;
end;
// For each application returned by the query, find its registrations in the GDS.
for I := VarArrayLowBound(ApplicationDescriptionArray,1) to VarArrayHighBound(ApplicationDescriptionArray,1) do
begin
ApplicationDescription := IUnknown(ApplicationDescriptionArray[I]) as _UAApplicationDescription;
WriteLn;
WriteLn('Application URI string: ', ApplicationDescription.ApplicationUriString);
try
TVarData(ApplicationRecordArray).VType := varArray or varVariant;
TVarData(ApplicationRecordArray).VArray := PVarArray(
GlobalDiscoveryClient.FindApplications(
GdsEndpointDescriptor,
ApplicationDescription.ApplicationUriString));
except
on E: EOleException do
begin
WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
Continue;
end;
end;
for J := VarArrayLowBound(ApplicationRecordArray, 1) to VarArrayHighBound(ApplicationRecordArray, 1) do
begin
// Display results
ApplicationRecord := IUnknown(ApplicationRecordArray[J]) as _UAApplicationRecordDataType;
WriteLn(' Application ID: ', ApplicationRecord.ApplicationId.ToString);
end;
end;
// Example output:
//
//Application URI string: urn:sampleserver
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=09ecaa08-6ec6-462c-a214-1e66a3099107
//
//Application URI string: urn:alarmconditionserver
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=783e1e9a-8036-43b6-928f-97488c460266
//
//Application URI string: urn:PC:MultiTargetUADocExamples:5.54.1026.1:neutral:null
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=9e700ea5-55a6-4c3c-ba9f-b91c890dc519
//
//Application URI string: urn:PC:UADocExamples:5.56.0.16:neutral:null
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=e182e28c-086b-4fc7-82c7-70ca7cda3033
//
//Application URI string: urn:PC:cscript:5.812.10240.16384
// Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=aec94459-f513-4979-8619-8383555fca61
end;
Rem Shows how to find all registrations in the GDS.
Rem
Rem Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
Rem OPC client and subscriber examples in VBScript on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBScript .
Rem Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
Rem a commercial license in order to use Online Forums, and we reply to every post.
Option Explicit
Const UAApplicationTypes_All = 7
' Define which GDS we will work with.
Dim GdsEndpointDescriptor: Set GdsEndpointDescriptor = CreateObject("OpcLabs.EasyOpc.UA.UAEndpointDescriptor")
GdsEndpointDescriptor.UrlString = "opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer"
GdsEndpointDescriptor.UserIdentity.UserNameTokenInfo.UserName = "appadmin"
GdsEndpointDescriptor.UserIdentity.UserNameTokenInfo.Password = "demo"
' Instantiate the global discovery client object
Dim GlobalDiscoveryClient: Set GlobalDiscoveryClient = CreateObject("OpcLabs.EasyOpc.UA.Gds.EasyUAGlobalDiscoveryClient")
' Find all (client or server) applications registered in the GDS.
Dim startingRecordId: startingRecordId = 0
Dim maximumRecordsToReturn: maximumRecordsToReturn = 0
Dim applicationName: applicationName = ""
Dim applicationUriString: applicationUriString = ""
Dim productUriString: productUriString = ""
Dim serverCapabilities: serverCapabilities = Array()
Dim lastCounterResetTime
Dim nextRecordId
Dim applicationDescriptionArray
On Error Resume Next
GlobalDiscoveryClient.QueryApplications _
GdsEndpointDescriptor, _
startingRecordId, _
maximumRecordsToReturn, _
applicationName, _
applicationUriString, _
UAApplicationTypes_All, _
productUriString, _
serverCapabilities, _
lastCounterResetTime, _
nextRecordId, _
applicationDescriptionArray
If Err.Number <> 0 Then
WScript.Echo "*** Failure: " & Err.Source & ": " & Err.Description
WScript.Quit
End If
On Error Goto 0
' For each application returned by the query, find its registrations in the GDS.
Dim ApplicationDescription
For Each ApplicationDescription In applicationDescriptionArray
WScript.Echo
WScript.Echo "Application URI string: " & ApplicationDescription.ApplicationUriString
On Error Resume Next
Dim applicationRecordArray: applicationRecordArray = GlobalDiscoveryClient.FindApplications( _
gdsEndpointDescriptor, _
ApplicationDescription.ApplicationUriString)
If Err.Number <> 0 Then
WScript.Echo " *** Failure: " & Err.Source & ": " & Err.Description
Else
Dim ApplicationRecord
For Each ApplicationRecord In applicationRecordArray
' Display results
WScript.Echo " Application ID: " & ApplicationRecord.ApplicationId
Next
End If
On Error Goto 0
Next
' Example output:
'
'Application URI string: urn:sampleserver
' Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=09ecaa08-6ec6-462c-a214-1e66a3099107
'
'Application URI string: urn:alarmconditionserver
' Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=783e1e9a-8036-43b6-928f-97488c460266
'
'Application URI string: urn:PC:MultiTargetUADocExamples:5.54.1026.1:neutral:null
' Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=9e700ea5-55a6-4c3c-ba9f-b91c890dc519
'
'Application URI string: urn:PC:UADocExamples:5.56.0.16:neutral:null
' Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=e182e28c-086b-4fc7-82c7-70ca7cda3033
'
'Application URI string: urn:PC:cscript:5.812.10240.16384
' Application ID: nsu=http://opcfoundation.org/UA/GDS/applications/ ;ns=2;g=aec94459-f513-4979-8619-8383555fca61
Python
# Shows how to find all registrations in the GDS.
#
# Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
# OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python .
# Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
# a commercial license in order to use Online Forums, and we reply to every post.
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc
# Import .NET namespaces.
from System import *
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.Discovery import *
from OpcLabs.EasyOpc.UA.Extensions import *
from OpcLabs.EasyOpc.UA.Gds import *
from OpcLabs.EasyOpc.UA.OperationModel import *
# Define which GDS we will work with.
gdsEndpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:58810/GlobalDiscoveryServer')
gdsEndpointDescriptor = UAEndpointDescriptorExtension.WithUserNameIdentity(gdsEndpointDescriptor,
'appadmin', 'demo')
# Instantiate the global discovery client object.
globalDiscoveryClient = EasyUAGlobalDiscoveryClient()
# Find all (client or server) applications registered in the GDS.
try:
_, _, _, applicationDescriptionArray = globalDiscoveryClient.QueryApplications(
gdsEndpointDescriptor,
0, # startingRecordId
0, # maximumRecordsToReturn
'', # applicationName
'', # applicationUriString
UAApplicationTypes.All, # applicationTypes
'', # productUriString
Array.Empty[String](), # serverCapabilities
DateTime(), # out lastCounterResetTime
0, # out nextRecordId
Array.Empty[UAApplicationDescription]()) # out applications
except UAException as uaException:
print('*** Failure: ' + uaException.GetBaseException().Message)
exit()
# For each application returned by the query, find its registrations in the GDS.
for applicationDescription in applicationDescriptionArray:
print()
print('Application URI string: ', applicationDescription.ApplicationUriString, sep='')
try:
applicationRecordArray = globalDiscoveryClient.FindApplications(
gdsEndpointDescriptor,
applicationDescription.ApplicationUriString)
except UAException as uaException:
print(' *** Failure: ' + uaException.GetBaseException().Message)
continue
# Display results.
for applicationRecord in applicationRecordArray:
print(' Application ID: ', applicationRecord.ApplicationId, sep='')
print()
print('Finished.')
X.509 certificate token
The X.509 certificate token authenticates the user by its user certificate (challenge-response process is used underneath). This token is represented by the X509CertificateTokenInfo Class object in the UserIdentity.X509CertificateTokenInfo Property.
In order to specify the user certificate that will be used, you fill in a certificate query, contained in the CertificateQuery Property of the X509CertificateTokenInfo object. The certificate query specify where the certificate comes from, and which certificate should be selected. The source of the certificate is given by the source type (SourceType Property), and depending on its value, further properties in the certificate query object need to be filled in.
The X.509 certificate token info is considered configured when the source type is not None.
In .NET languages, instead of manipulating the object properties, you can take an OPC UA endpoint descriptor, and create a new endpoint descriptor from it, with user identity provided by the X.509 certificate token. To do so, use the WithX509CertificateIdentity Method.
Dynamic User Identity Change
OPC UA has a feature that allows the clients to change the identity of the user on an existing connection (OPC UA session), without having to close the session and re-open it. QuickOPC supports this feature as well. For more information, see Dynamic User Identity Change.
Note that this feature is only available if the OPC UA server supports it.
See Also
Examples - OPC UA GDS and CM
Reference
Concepts
Examples - Client OPC UA User Authentication