# Users and roles

> Concept: Which user identities OPC UA supports, how a client authenticates users, and how a server checks them against access control lists and roles.

> This content was machine translated and may contain errors. [Read in German](https://www.traeger.de/docs/development/opcua/security/users-roles)

**Sample applications:**

- Server.UserIdentities ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Scenarios/Server.UserIdentities), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Scenarios/Server.UserIdentities)): This use case demonstrates how generic user identities could be implemented using built-in ACL functionality and how subclassing can be used to define the generic user identities.
- Server.NodeAccess ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Scenarios/Server.NodeAccess), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Scenarios/Server.NodeAccess)): This use case realizes restricted node access using built-in ACL functionality And subclassing for user dependent node metadata.
- Client.Authentication ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Basic/Client.Authentication), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Basic/Client.Authentication)): This sample demonstrates how to authenticate at an OPC UA server using user name and password.

Certificates identify client and server applications. In addition, a server can check the users who work with it through a client and assign permissions to them. This page explains the basic concepts for client and server. The section [Authenticate users](https://www.traeger.de/en/docs/development/opcua/security/client#authenticate-users) on the page "Secure clients" and the sections [Authenticate users](https://www.traeger.de/en/docs/development/opcua/security/server#authenticate-users) and [Roles](https://www.traeger.de/en/docs/development/opcua/security/server#roles) on the page "Secure servers" describe the configuration in detail.

## User identities

A client application is always operated by a specific user who works with the server through it. Depending on its configuration, a server also requests information about the identity of this user from the client. OPC UA supports the following kinds of user identities:

| Identity | In the client | In the server |
|---|---|---|
| Anonymous | Default, nothing to specify | Access control list `AnonymousAcl`; active as long as no other access control list is active |
| User name and password | Class `OpcClientIdentity` | Access control list `UserNameAcl` |
| Certificate | Class `OpcCertificateIdentity`, with private key | Access control list `CertificateAcl`, compared by thumbprint |
| Issued token | | Access control list `IssuedTokenAcl`; checks only Kerberos tickets, and only if the server runs on .NET Framework |

So a certificate does not only serve client and server applications as an ID card. It can also identify a user. How thoroughly a server checks the certificate of a user for validity, authenticity, and trustworthiness depends on the server. The server of the SDK checks whether the thumbprint is in its access control list for certificate-based user identities. If a validator is configured for this access control list (property `OpcServer.Security.CertificateAcl.CertificateValidator`), the server first also checks the certificate with this validator.

## Authentication on the client

The client sets the identity of the user through the property `OpcClient.Security.UserIdentity`. If the server supports an anonymous user identity, you do not have to set an identity. However, access through an anonymous identity is usually restricted. A specific identity, in contrast, can give the client access to more sensitive data.

The client encrypts the password of a user name and password identity with the certificate of the server, provided that the server specifies a security policy for its user tokens. Even so, authenticate users only through endpoints with the mode `SignAndEncrypt`, and do not accept unknown server certificates automatically. The section [Authenticate users](https://www.traeger.de/en/docs/development/opcua/security/client#authenticate-users) describes the reasons and shows examples.

## Verification on the server

By default, a server also allows access without a specific user identity (anonymous authentication). If a client specifies a user identity, the server must know this identity. To do this, configure and activate the matching access control lists (ACL). As soon as another access control list is active, anonymous access is turned off automatically.

Each entry of an access control list represents a user. On the entry, you define which operations the user may perform and through which endpoints the user may log on. The access control mode determines how the server evaluates granted and denied operations. The access control lists of the SDK use the mode `Whitelist` by default: an entry may perform all operations that have not been explicitly denied to it. The sections [Authenticate users](https://www.traeger.de/en/docs/development/opcua/security/server#authenticate-users) and [Access control modes](https://www.traeger.de/en/docs/development/opcua/security/server#access-control-modes) describe the modes and show examples.

## Roles

OPC UA defines standard roles that the users of a server can belong to, for example `Observer`, `Operator`, `Engineer`, and `SecurityAdmin`. The server automatically assigns anonymous users to the role `Anonymous` and all users authenticated through an access control list to the role `AuthenticatedUser`. You assign further roles to an access control entry. The section [Roles](https://www.traeger.de/en/docs/development/opcua/security/server#roles) describes all roles with their permissions and the methods for them.

## One session per user

Types used: `OpcServer`, `OpcAccessControlEntry`, `OpcSession`

A user should be able to connect only once per access control entry (ACE), that is, per user defined in the OPC UA server. A new connection should only be possible again after the active connection has been closed. To achieve this, the server must block the available endpoints for the user as long as a session of the user is active. This is what it can look like:

```csharp
server.SessionActivated += (sender, e) => {
    var identityEntry = GetUserEntry(server.Security, e.Session);

    if (identityEntry != null)
        identityEntry.Disable(OpcEndpointIdentity.GetCurrent());
};

server.SessionClosing += (sender, e) => {
    var identityEntry = GetUserEntry(server.Security, e.Session);

    if (identityEntry != null)
        identityEntry.Enable(OpcEndpointIdentity.GetCurrent());
};

private static OpcAccessControlEntry GetUserEntry(
        OpcServerSecurity security,
        OpcSession session)
{
    var identity = session.UsedIdentity;

    // In case of anonymous.
    if (identity == null)
        return null;

    return (from userEntry in security.UserNameAcl.Entries
            let userPrincipal = userEntry.Principal
            let userIdentity = (OpcUserIdentity)userPrincipal.Identity
            where userIdentity.DisplayName == identity.DisplayName
            select userEntry).FirstOrDefault();
}
```

```vbnet
AddHandler server.SessionActivated, _
    Sub(sender, e)
        Dim identityEntry = GetUserEntry(server.Security, e.Session)

        If identityEntry IsNot Nothing Then identityEntry.Disable(OpcEndpointIdentity.GetCurrent())
    End Sub

AddHandler server.SessionClosing, _
    Sub(sender, e)
        Dim identityEntry = GetUserEntry(server.Security, e.Session)

        If identityEntry IsNot Nothing Then identityEntry.Enable(OpcEndpointIdentity.GetCurrent())
    End Sub

Private Shared Function GetUserEntry( _
        ByVal security As OpcServerSecurity, _
        ByVal session As OpcSession) As OpcAccessControlEntry
    Dim identity = session.UsedIdentity

    'In case of anonymous.
    If identity Is Nothing Then Return Nothing

    Return (From userEntry In security.UserNameAcl.Entries _
            Let userPrincipal = userEntry.Principal _
            Let userIdentity = CType(userPrincipal.Identity, OpcUserIdentity) _
            Where userIdentity.DisplayName = identity.DisplayName _
            Select userEntry).FirstOrDefault()
End Function

```
