High Performance OPC UA Server SDK  1.5.0.296
Authorization

Overview

Warning
The Authorization is currently standardized in a way that differs from this implementation. A future version of the SDK may adopt the new standard and break with the mechanisms described on this page.

The server allows to control access of different users to the addressspace and values of the server. For the authorization to work the Authentication must also be enabled. Authorization is implemented as backend, where the following are currently available:

Null Backend
Disable authorization
Inode Backend
User, group and other permissions for every node

To activate a backend, the according backend must be selected using the cmake option UA_AUTHORIZATION_BACKEND.

Null Backend

Disables Authorization completely and grants every user access to all node.

Inode Backend

The inode is embedded in every node of the addressspace and contains a user id, a group id and the permissions for the user, group and everybody else (other).

Adding Users

Users can be loaded from a users file with the following format:

<userid>:<username>
0:anonymous
1:john
2:root

Users can also be added inside the code:

#include <uaserver/session/authorization/inode/inode.h>
int ret;
ret = ua_inode_add_user("anonymous", 0);
if (ret != 0) goto error;
ret = ua_inode_add_user("john", 1);
if (ret != 0) goto error;
ret = ua_inode_add_user("root", 2);
if (ret != 0) goto error;
Note
The username anonymous has a special meaning and is assigned to an unauthenticated user if anonymous authentication is allowed.

Adding Groups

Groups can be loaded from a groups file with the following format:

<groupid>:<groupname>:<username1>,<username2>
1:operators:root,john

Groups can also be added inside the code:

#include <uaserver/session/authorization/inode/inode.h>
int ret;
ret = ua_inode_add_group("operators", 1);
if (ret != 0) goto error;
ret = ua_inode_add_user_to_group("root", "operators");
if (ret != 0) goto error;
ret = ua_inode_add_user_to_group("john", "operators");
if (ret != 0) goto error;

Access Permissions

The following table shows the access permissions available in the SDK and the nodeclasses these are applicable to:

Permission Nodeclass Description
ATTRREADABLE All All attributes except the value are readable, nodes without this permission will also not show up in browse results
ATTRWRITABLE All All attributes except the value are writable
EVENTREADABLE Object The Events the node creates are readable
EXECUTABLE Method The function associated to the node can be executed
READABLE Variable The value attribute is readable
WRITABLE Variable The value attribute is writable
HISTORYREADABLE Variable The history of the value attribute is readable
HISTORYINSERT Variable New values can be inserted in the history of the value attribute
HISTORYMODIFY Variable Values in the history of the value attribute can be modified
HISTORYDELETE Variable Values from the history of the value attribute can be deleted
Note
To minimize the memory footprint of the server the inode backend shares one bit for HISTORYINSERT, HISTORYMODIFY and HISTORYDELETE. If one of these permissions is granted, the other two are also enabled automatically.

There are also some composite permissions defined by the SDK:

Permission Description
OBSERVATION Read everything: attributes, values, events, history
OPERATION Observation plus write values and execute methods
ALL All of the available permissions

All of these permission can be set independently for the user, the group and others. To set the access permissions there is a define for every combination, e.g.:

  • ATTRREADABLE for others: UA_OTHER_ATTRREADABLE
  • WRITABLE for group: UA_GROUP_WRITABLE
  • OPERATION for user: UA_USER_OPERATION

There is furthermore a special permission UA_ALL_ENCRYPTION_REQUIRED. It ensures the node can only be accessed using an encrypted connection. If this permission is set, it is in effect for user, group and others and is meant to protect confidential nodes.

Setting Access Permissions

Access permissions can be set as default permissions for every newly created node after this call:

#include <uaserver/session/authorization/inode/inode.h>
int ret;
/* Get user and group id */
ret = ua_inode_get_uid("john", &uid);
if (ret != 0) goto error;
ret = ua_inode_get_gid("operators", &gid);
if (ret != 0) goto error;
/* Set default permissions:
* -Everybody can read
* -User john can write values
* -Members of group operators can execute methods
*/
ret = ua_inode_set_default_perm(uid, gid, UA_OTHER_OBSERVATION | UA_USER_WRITABLE | UA_GROUP_EXECUTABLE | );
if (ret != 0) goto error;

Access permissions can also be set for a single node:

#include <uaserver/session/authorization/inode/inode.h>
#include <uaserver/addressspace.h>
int ret;
ua_node_t node;
uint16_t mynsindex = ...
ua_uid_t uid;
/* Get the node to set permissions */
node = ua_node_find_string(mynsindex, "confidential_node");
if (node == UA_NODE_INVALID) goto error;
/* Get user id */
ret = ua_inode_get_uid("root", &uid);
if (ret != 0) goto error;
/* User root has full access to the node, but only
* with an encrypted connection. Everybody else has
* no permission at all.
*/
ret = ua_inode_set_perm(node, uid, 0, UA_USER_ALL | UA_ALL_ENCRYPTION_REQUIRED);
if (ret != 0) goto error;

Checking Access Permissions

When implementing a provider, the provider has to check the permissions before providing information to the client. This works independent of the authorization backend using the following functions:

Example when implementing a provider to read the value attribute (other attributes are handled by the SDK in this example):

#include <uabase/service/readresponse.h>
#include <uabase/service/readrequest.h>
#include <uabase/statuscodes.h>
#include <uabase/attributeid.h>
#include <uaserver/read_internal.h>
#include <uaserver/addressspace.h>
#include <uaprovider/provider.h>
extern uint16_t g_mynsindex;
void myprovider_read(struct uaprovider_read_ctx *ctx)
{
struct ua_readrequest *req = ctx->req;
struct ua_readresponse *res = ctx->res;
ua_node_t node;
int32_t i;
for (i = 0; i < req->num_nodes; i++) {
/* skip node from other namespace */
if (req->nodes[i].node_id.nsindex != g_mynsindex) continue;
/* find the node handle */
node = ua_node_find(&req->nodes[i].node_id);
if (node == UA_NODE_INVALID) continue;
if (req->nodes[i].attribute_id == UA_ATTRIBUTEID_VALUE) {
#ifdef UA_AUTHORIZATION_SUPPORT
res->results[i].status = ua_authorization_is_readable(node, &ctx->session->user_ctx);
if (res->results[i].status != 0) continue;
#endif
/* read value */
...
} else {
/* read internal checks the access permissions itself */
uaserver_read_internal(node, ctx->session, req->max_age, req->ts, req->nodes[i].attribute_id, NULL, 0, &res->results[i]);
}
}
}
ua_readresponse::results
struct ua_datavalue * results
structures.
Definition: readresponse.h:88
ua_readresponse
Definition: readresponse.h:87
ua_readrequest::max_age
double max_age
Maximum age of the value to be read in milliseconds.
Definition: readrequest.h:112
ua_gid_t
uint8_t ua_gid_t
Datatype for the group id, can be increased to support more groups.
Definition: inode.h:111
ua_inode_get_gid
int ua_inode_get_gid(const char *groupname, ua_gid_t *gid)
Get the groupid for a groupname.
Definition: inode.c:147
ua_authorization_is_readable
ua_statuscode ua_authorization_is_readable(ua_node_t node, struct ua_user_ctx *user)
Check if the value of a variable is readable by the user.
Definition: inode.c:577
UA_NODE_INVALID
#define UA_NODE_INVALID
Value of an invalid node handle.
Definition: node.h:55
ua_inode_set_perm
int ua_inode_set_perm(ua_node_t node, ua_uid_t uid, ua_gid_t gid, uint32_t permissions)
Set permission for a single node.
Definition: inode.c:303
uaprovider_read_ctx::req
struct ua_readrequest * req
Request from the client.
Definition: provider.h:207
ua_inode_get_uid
int ua_inode_get_uid(const char *username, ua_uid_t *uid)
Get the userid for a username.
Definition: inode.c:99
ua_readrequest::ts
enum ua_timestampstoreturn ts
An enumeration that specifies the Timestamps to be returned for each requested Variable Value Attribu...
Definition: readrequest.h:113
uaserver_read_internal
void uaserver_read_internal(ua_node_t node, struct uasession_session *session, enum ua_timestampstoreturn ts, uint32_t attribute_id, struct ua_indexrange *index_range, unsigned int num_ranges, struct ua_datavalue *result)
Read the attribute of a node.
Definition: read_internal.c:747
ua_node_find
ua_node_t ua_node_find(const struct ua_nodeid *id)
Finds a node by its NodeId.
Definition: node.c:1328
uaprovider_read_ctx
Context given to the read service handler.
Definition: provider.h:204
uaserver_read_complete
void uaserver_read_complete(struct uaprovider_read_ctx *ctx)
Function to be called when a read service handler has finished handling all the nodes it is responsib...
Definition: provider.c:461
ua_inode_add_group
int ua_inode_add_group(const char *groupname, ua_gid_t id)
Add a new group with groupname and id.
Definition: inode.c:237
ua_datavalue::status
ua_statuscode status
The StatusCode that defines with the Server’s ability to access/provide the value.
Definition: datavalue.h:61
ua_inode_set_default_perm
int ua_inode_set_default_perm(ua_uid_t uid, ua_gid_t gid, uint32_t permissions)
Set new default permission for all newly created nodes.
Definition: inode.c:277
ua_readvalueid::node_id
struct ua_nodeid node_id
NodeId of a Node.
Definition: readvalueid.h:107
ua_uid_t
uint8_t ua_uid_t
Datatype for the user id, can be increased to support more users.
Definition: inode.h:109
ua_node_find_string
ua_node_t ua_node_find_string(uint16_t nsindex, const char *string_id)
Convenience function for finding nodes based on their string nodeid.
Definition: node.c:1311
ua_readrequest
Reads values and attributes asynchronously from OPC server.
Definition: readrequest.h:111
ua_inode_add_user_to_group
int ua_inode_add_user_to_group(const char *username, const char *groupname)
Add a user to a group.
Definition: inode.c:168
uaprovider_read_ctx::session
struct uasession_session * session
Session associated with the request.
Definition: provider.h:205
ua_readrequest::num_nodes
int32_t num_nodes
Number of elements in ua_readrequest::nodes.
Definition: readrequest.h:115
ua_inode_add_user
int ua_inode_add_user(const char *username, ua_uid_t id)
Add a new user with username and id.
Definition: inode.c:198
ua_readrequest::nodes
struct ua_readvalueid * nodes
List of Nodes and their Attributes to read.
Definition: readrequest.h:114
ua_node_t
int32_t ua_node_t
Handle for a node in the addressspace.
Definition: node.h:53
ua_readvalueid::attribute_id
uint32_t attribute_id
Id of the Attribute.
Definition: readvalueid.h:108
ua_nodeid::nsindex
uint16_t nsindex
The index for a namespace URI.
Definition: nodeid.h:182
uaprovider_read_ctx::res
struct ua_readresponse * res
Response for the client.
Definition: provider.h:209