High Performance OPC UA Server SDK  1.7.1.383
User Authentication Configuration

This section describes how to configure user authentication in the UA Server.

General

OPC UA currently supports four different ways to authenticate a user during the ActivateSession service call:

  • AnonymousIdentityToken
  • UserNameIdentityToken
  • X509IdentityToken
  • IssuedIdentityToken

AnonymousIdentityToken

This actually performs no authentication at all. Every user which uses an application which is allowed to connect, either because the client is trusted, or because the server also allows to use SecurityPolicy None (no application authentication), is able to connect.

It is recommended to disable this kind of authentication for security reasons.

Also, note, that simply relying on application authentication is not an appropriate solution, because

  • a) You don't know which user is using this client.
  • b) If you have trusted a CA certificate, you don't event know how many clients are trusted this way.
  • c) You cannot use user authorization to restrict access to critical information for this user. Every user that connects anonymously is mapped to the same anonymous user account, which should have as few permissions as possible.

UserNameIdentityToken

This allows to authenticate the user using an username and password. The password gets encrypted, even when using a none secure channel, because the UserToken itself get individually encrypted. Technically OPC UA allows transmitting passwords also in clear text, but this option SHALL not be used.

Using the password a server can authenticate users using existing APIs like e.g. Windows LoginUser or Linux PAM. The High Performance SDK supports to replace the authentication backend with own implementations. By default, it uses its "internal" implementation which is a portable solution using plain text configuration files, which store the passwords as cryptographic hash.

X509IdentityToken

This allows authenticating users using X509 certificates. It is especially useful to integrate smart cards for user authentication, to increase the security level. This requires smart cart support in client side to access the private key information. It is also possible to use file based private keys, but this is not recommended.

On server side there is no difference in using smart cards or file based private keys. The server only needs the X509 certificate, which is transmitted during the ActivateSession call. Using the public key in the certificate the server can verify the cryptographic signature, which proves that the client is in possession of the private key which belongs to the given certificate.

The authentication process consists of the following steps:

  • Checking that the certificate is valid and trusted.
  • Verifying that the user token signature is correct.
  • Mapping the CommonName field of the certificate to a user identity. This user must exist.

IssuedIdentityToken

This allows delegating user authentication to an external OAuth2 server. This is currently not support by the SDK.

Configuring Users

The SDK provides example files for users, groups and passwords to use with the DemoServer and ServerExamples. When making a product do not use these files but create your own.

Adding a user to the configuration can be done by simply adding new entries into the users file in the server's bin directory. This file contains a mapping from the internally used numeric user ID (UID) and the username. The UID must be unique. Simply increment this number of each entry.

Example:

# <userid>:<username>
0:anonymous
1:root
2:joe
3:john
4:sue

The user anonymous has a special meaning and is used to map clients authenticating with an AnonymousIdentityToken. To disable anonymous clients, do not add that entry to the users file. For compile time deactivation of anonymous clients, disable the CMake option UA_AUTHENTICATION_SUPPORT_ANONYMOUS.

The next step is to assign this user to groups it needs permissions to. Therefor you edit the file groups. This file contains a mapping from the group ID (GID) to a group name in the same way as the users file for users. In addition, there is a third column with a comma separated list of users which belong to this group.

Example:

# <groupid>:<groupname>:<username1>,<username2>
0:operators:root,joe
1:users:john,sue

Configuring Passwords

The passwords are stored in the file unreadable as hashes with salt, however it is still possible to start brute-force attacks against these hashes to retrieve the passwords. Therefore the password file should only be readable by the server process and no other user.

The passwords for each user are configured in the file passwd. It is possible to add plaintext passwords here, but this is not recommended. Instead, you can use the tool uapasswd to add cryptographically hashed and salted password here.

./uapasswd -u john
Changing password for user 'john'.
New password:
Retype new password:
Successfully wrote file 'passwd'

See UA Password Manager for more information on this tool.

Configuring X509 Authentication

To make X509 user authentication working you need to create a second PKI store, so that the user certificates are independent of the application instance certificates.

This example contains two stores. The first for application instance certificates, the second for user certificates.

[pkistore]
pkistores/size = 2
pkistores/0/config = "pki_store_0;50;50;50;50"
pkistores/0/import_dir = "import"
pkistores/1/config = "pki_store_user;50;50;50;50"
pkistores/1/import_dir = "import_user"

The import_dir parameter defines a folder, where you can place certificates which should be imported into the store when starting the server. Because there are two stores, you need to use also two different import folder.

Trusting a Self-Signed User Certificate

To trust a self-signed user certificate you need to import it into the trust list of the user PKI store, which by default has the store index 1.

cd /path/to/sdk/bin
./uacertmgr -s 1 import /path/to/john.pem

uacertmgr can import DER encoded and PEM encoded certificate files.

You can also programmatically trust certificates by using the function pki_store_save_cert to import the certificate. In this case you need a DER encoded certificate.

Trusting CA-Signed User Certificates

To trust CA-signed certificates you need to import the CA certificate. This way all certificates issued but this CA will be trusted as well. The recommended way of importing certificates and CRLs is to use uacertmgr application.

cd /path/to/sdk/bin
./uacertmgr -s 1 import rootCA.der rootCA.crl

In addition the PKI store implementation offers its own import functionality. To import the CA certificate you need to store the CA certificate in the import_user folder DER encoded with the file extension .der. Additionally you need to store also the CA's certificate revocation list in this folder. This file also needs to be DER encoded with the file extension .crl.

Example Files:

rootCA.der (DER encoded certificate)
rootCA.crl (DER encoded CRL)

Example:

cd /path/to/sdk/bin
# create configured import directory if it does not exist yet
mkdir import_user
# copy certificate and CRL into import dir
cp rootCA.der rootCA.crl import_user/
# start the server to import the files
./uaserverhp

These files get imported in [pki_store_user trusted certs](pki_store_user/trusted/certs) and pki_store_user/trusted/crl using the certificate thumbprint as filename. The CRL needs to be updated on a regular basis, so that revoked certificates are not allowed to connect anymore.

Attention: Never copy files manually into the store!

You can also programmatically trust certificates by using the function pki_store_save_cert and pki_store_save_crl to import the certificate and CRL. Note, that CA certificates should always have a CRL, so that it is possible to revoke certificates. The CRL needs to be updated regularly.

Creating X509 User Certificates

A user certificate is a regular X509v3 certificate, where the Common Name field is mapped to a username. This means you need to create the user and group settings in the same way as for password authentication, which is described above in Configuring Users. But instead of a password the user can use his private key to authenticate himself.

Creating Self-Signed User Certificates

The following example shows how to create a self-signed user certificate using OpenSSL command line tool:

$> openssl req -x509 -extensions v3_req -newkey rsa:4096 -keyout john_key.pem -out john.pem -days 365
Generating a RSA private key
.................++++
...............++++
writing new private key to 'john_key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:CA
Locality Name (eg, city) []:LA
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Skynet
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:john
Email Address []:john@skynet.com
$> ls -l john*
-rw------- 1 john john 3414 Jun 19 15:56 john_key.pem
-rw------- 1 john john 2057 Jun 19 15:56 john.pem

This command creates the files john_key.pem, which contains a password protected private key, and john.pem which contains John's certificate. Important is the question regarding the Common Name. This name is later on mapped to the username in the server.

Creating CA Signed User Certificates

Creating CA signed user certificates is normally handled by the IT department of the company running the OPC UA infrastructure. For testing purpose you can also create your own local CA and issue certificates yourself. The SDK includes some example scripts for testing this feature in the folder bin/CA. These scripts require GNU Bash and the OpenSSL command line tool. This is available on Linux by default, on Windows you can use the WSL (Windows Subsytem for Linux), Git Bash or Cygwin Bash. See bin/CA/README.md for detailed instructions on how to use those scripts. For more information on the OpenSSL tools please consult the documentation at https://www.openssl.org/docs/.

Testing User Certificates

For testing this feature you can use UaExpert, which supports password authentication as well as X509 user certificate authentication. See http://documentation.unified-automation.com/uaexpert/1.5.1/html/connect.html#connect_authentication for a step by step guide. Simply select the option "Certificate" instead of "Password" and configure the path to the user certificate file (john.der) and key file (john_key.pem). If the key file is password protected, UaExpert will ask you for that password when loading the key.

Server Configuration

The server settings.conf allows configuring multiple user token types. In this example we configured UserNameIdentityToken and X509IdentityToken, but removed the AnonymousIdentityToken.

user_tokens/size = 2
user_tokens/0/name = Username_256_Token
user_tokens/0/type = Username
user_tokens/0/policy_id = http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256
user_tokens/1/name = X509_Token
user_tokens/1/type = Certificate
user_tokens/1/policy_id = http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256

Then in every configured endpoint you can select what user tokens are accepted for this endpoint. You select the token by its index. In this example both token types are allowed.

endpoints/size = 1
endpoints/0/endpoint_url = opc.tcp://[hostname]:4840
endpoints/0/bind_address = 0.0.0.0
endpoints/0/bind_port = 4840
endpoints/0/security_policies = 0,1,2
endpoints/0/user_tokens = 0,1

In the section [session] you can select password file to use for password based user authentication and the PKI store to use for X509 based user authentication.

# location of file to load users and passwords for authentication
authentication_passwd_file = passwd
# PKI store index for X509 user authentication
authentication_store = 1