Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Role-based Access Control #6521

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open

Role-based Access Control #6521

wants to merge 14 commits into from

Conversation

jpfr
Copy link
Member

@jpfr jpfr commented Jun 1, 2024

No description provided.

@@ -546,6 +546,9 @@ UA_Node_copy(const UA_Node *src, UA_Node *dst) {
UA_StatusCode retval = UA_NodeId_copy(&srchead->nodeId, &dsthead->nodeId);
retval |= UA_QualifiedName_copy(&srchead->browseName, &dsthead->browseName);

/* Copy the RolePermissions */
memcpy(dsthead->rolePermissions, srchead->rolePermissions, sizeof(UA_RoleSet) * 16);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not using sizeof(dsthead->rolePermissions) for the size or the named constant "UA_ROLEPERMISSIONS_COUNT" instead of "16" here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find. Will change that.

/* If a second server is started later it can "steal" the port.
* Having port reuse enabled is important for development.
* Otherwise a long TCP TIME_WAIT is required before the port can be used again. */
conf->tcpReuseAddr = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems to be off-topic here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Will be moved out of this PR.

#define UA_ROLEINDEX_SECURITYADMIN 7

typedef struct {
UA_UInt16 bits[UA_ROLESET_MAX / 16];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using "(UA_ROLESET_MAX + 15) / 16" here might relax the current restriction of UA_ROLESET_MAX being a multiple of 16.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, good idea.

Comment on lines +2003 to +2013
UA_RoleSet delNodeRoles = node->head.rolePermissions[UA_ROLEPERMISSIONINDEX_DELETENODE];
if(session != &server->adminSession &&
!UA_RoleSet_intersects(delNodeRoles, session->roles)) {
UA_LOG_NODEID_INFO(&node->head.nodeId,
UA_LOG_INFO_SESSION(server->config.logging, session, "DeleteNode (%.*s): "
"Cannot delete the node because of missing RolePermisions",
(int)nodeIdStr.length, nodeIdStr.data));
UA_NODESTORE_RELEASE(server, node);
*result = UA_STATUSCODE_BADUSERACCESSDENIED;
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly, this checks, if the session has a role assigned which is required to gain the DELETENODE permission. What is the difference of this check and the one in the AccessControl Plugin (allowDeleteNode)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AccessControl plugin checks go on top of the RolePermissions.
Everything the RolePermissions do can also be done in the pure AccessControl plugin.
But it will be a lot easier to move most checks into the Role-Based Access Control.
Because you don't to build all the machinery to track node access permissions individually.

@mcpat
Copy link
Contributor

mcpat commented Jun 4, 2024

Hi,
I just want to place an additional conceptual question here:

It seems, that the new permission checks are now hard-wired into several places instead of being encapsulated in the AccessControl plugin. Is this desired? What purpose does the AccessControl plugin have then if the permission checks are not done there?

Comment on lines +635 to +637
* OPC UA uses role-based access control (RBAC). Every session is assigned a set
* of roles it represents. Every node in the information contains
* RolePermissions that define the rights of each role.
Copy link
Contributor

@mcpat mcpat Jun 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be correct. When looking into the specification it states:

If not specified, the value of DefaultRolePermissions Property from the NamespaceMetadata Object associated with the Node shall be used instead.

My understanding is, that not every node in the information model contains RolePermissions.

Copy link
Member Author

@jpfr jpfr Jun 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every node can have it (optional) in the spec.
We would chose to have the overhead for every node.

* the node keeps a role-set of all the roles which have this permission.
* When a RolePermission is changed manually (added or removed) the changes
* propagate recursively to all child nodes (hierarchical reference). */
UA_RoleSet rolePermissions[UA_ROLEPERMISSIONS_COUNT];
Copy link
Contributor

@mcpat mcpat Jun 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like quite some overhead here. Beside that not every node actually has RolePermissions assigned (see comment below) it also poses an upper limit of roles that may be added at runtime.

Wouldn't it be better to keep the RolePermissions outside of the node and accessing them (or only check for access) through an abstraction? That way it would reduce the overhead here and it would also allow to deviate from the standard role mapping which is permitted by the OPC UA specification?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are 32byte overhead per node.
16 permission types and 2 byte per type (assuming up to 16 roles).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, the current size of UA_Node is already at around 400 Bytes so this increase is only about 8%.
And also from what I see, Namespace 0 contains around 5000 nodes. So yes, this overhead seems to be negligible.

Nevertheless I want to point two things out here, that might be worth considering:

  • I would expect the amount of permutations for these RolePermissions to be strictly smaller than the overall number of nodes.
    Why? Because first, it seems to be a maintenance burden to assign different role permissions to each node.
    And second, doing this does not make sense at all because of the inter-dependencies between the nodes.
  • It does not feel right to have this matrix embedded inside the UA_Node structure. ;-)
    Having a pointer here for example allows to easily detect that no RolePermissions have been assigned (e.g. to fall back to the namespace defaults). And it would also allow to add roles at runtime without any limitations.

@jpfr
Copy link
Member Author

jpfr commented Jun 5, 2024

It seems, that the new permission checks are now hard-wired into several places instead of being encapsulated in the AccessControl plugin. Is this desired?

We will have both.
You can set the RolePermissions to "always allow" and continue to use the AccessControl plugin as before.

@mcpat
Copy link
Contributor

mcpat commented Jun 6, 2024

It seems, that the new permission checks are now hard-wired into several places instead of being encapsulated in the AccessControl plugin. Is this desired?

We will have both. You can set the RolePermissions to "always allow" and continue to use the AccessControl plugin as before.

Well that sounds good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants