peaq access (RBAC)
Role-Based Access Control (RBAC) Pallet
How to implement the RBAC pallet
Although we already have the RBAC smart contract, we recently created a version for the pallet that meets our long-term goals for using it. Access control management was done using the current RBAC as a Substrate pallet with external calls. Recognize that the RBAC pallet is created with the idea that anyone using board-based networks can utilize it. The dApp developer must coordinate the entities and relationships that own them. Only access control structures can be created using the pallet.
The following items are required to configure RBAC.
User
The Access User is the entity around which the entire implementation revolves. The user is indicated by public key/EntityId which is a [u8; 32] type on our implementation but the
developer implementing the pallet can choose the preferred type EntityId which must satisfy all required traits.
Group
This is an entity that provides a way for the developer to represent the assignment of permissions/roles for multiple users rather than having to assign these relationships individually. All permissions assigned to a user group grant them access without being assigned directly. Each member of a group has the same permissions as that group, and users can be members of multiple groups. Users have many-to-many relationships with groups represented in storage as User2GroupStore.
Role
The role is an entity that can be assigned to a user or a group. The role determines the permission granted to users or groups, since permissions can only be assigned to roles. The RBAC owner has the exclusive right to assign these relationships between roles and users/groups and between roles and permissions. Roles are saved on the storage using the owner AccountId as key and values are vector type (Vec<Entity<T::EntityId>>). This is to prevent retrieving multiple owners roles and for easy transversal during a fetch request to the storage. A key lookup store (KeysLookUpStore<T: Config>) is also used to store the unique ownership of the saved entity with a key generated from the hash of the owner AccountId, EntityId and the tag name (Tag::Role). This key lookup store is used to check for entity existence and status during validations.
Permission
Permissions determine the access granted to a user/group with a specific role. Permissions must be created before they can be assigned. Validations are performed on existing records to mitigate duplicates and verify existence before assignment. Permissions have a many-to-many relationship with roles and are represented in storage as Permission2RoleStore.
Relationships on Storage
The RBAC pallet was designed to take into account the most necessary relationship between entities, which provides the solution required to verify user/group access rights.The unique ownership to these relationship assignments is achieved by generating a storage key using the hash of owner's AccountId, EntityId and relationship tag name. This is used for validation during insertions and modifications.
Role2UserStore:
This storage is responsible for storing the relationships between roles and users. The storage exists as a key-value map storethat uses the hash of the owner AccountId, user id of EntityId type and the tag name of Role2User (Tag::Role2User) enum type as the key while vector of Role2User struct type Vec<Role2User> as the value type.
Role2GroupStore:
This storage is responsible for storing the relationships between roles and groups. The storage exists as a key-value map store tthat uses the hash of the owner AccountId, group id of EntityId type and the tag name of Role2Group (Tag::Role2Group) enum type as the key while vector of Role2Group struct type Vec<Role2Group> as the value type.
User2GroupStore:
This storage is responsible for storing the relationships between users and groups. The storage exists as a key-value map store that uses the hash of the owner AccountId, user id of EntityId type and the tag name of User2Group (Tag::User2Group) enum type as the key while the vector of User2Group struct type Vec<User2Group> as the value type.
Permission2RoleStore:
This storage is responsible for storing the relationships between permissions and roles. The storage exists as a key-value map store that uses the hash of the owner AccountId, role id of EntityId type and the tag name of Permission2Role (Tag::Permission2Role) enum type as the key while the vector of Permission2Role struct type Vec<Permission2Role> as the value type.
Vector is used as the value type for easy transversal of entities and also to return all entities during a fetch extrinsic calls.
Adding RBAC Pallet to Substrate-based node
RBAC can be used by any Substrate-based blockchain network. Adding the pallet to your node runtime can be done following the simple steps:
Import the pallet dependency by adding below snippets to the runtime/src/Cargo.toml file
Implement the pallet on the runtime by adding below snippets to the runtime/src/lib.rs file.
Add peaqRbac parameter type to the runtime construct on runtime/src/lib.rs file using below snippet.
Accessing and using the RBAC pallet
After completing the above installation, the following steps are required to access and use the pallet:
- Build your node
- Run your node
- Select peaqRbac under the developer - Extrinsics tab.
Implemented RBAC Pallet Extrinsic Calls
The complete extrinsic calling capabilities that enable RBAC implementation are listed and explained below:
- addRole(roleId: EntityId, name: Vec<u8>): Creates a new role on RoleStore storage.
- roleId: The unique ID of the role that will be used as part of the key in storage.
- name: The display name of the role for easy identification.
- updateRole(roleId: EntityId, name: Vec<u8>): Updates an existing role on RoleStore storage. Only the name field is being updated.
- roleId: The unique ID of the role that will be used as part of the key in storage.
- name: The display name of the role for easy identification.
- addGroup(groupId: EntityId, name: Vec<u8>): Creates a new group on GroupStore storage.
- groupId: The unique ID of the group that will be used as part of the key in storage.
- name: The display name of the group for easy identification.
- updateGroup(groupId: EntityId, name: Vec<u8>): Updates an existing group on GroupStore storage. Only the name field is updated.
- groupId: The unique ID of the group that will be used as part of the key in storage.
- name: The display name of the group for easy identification.
- addPermission(permissionId: EntityId, name: Vec<u8>): Creates a new permission entity on PermissionStore storage.
- permissionId: The unique ID of the permission that will be used as part of the key in storage.
- name: The display name of the permission for easy identification.
- UpdatePermission(permissionId: EntityId, name: Vec<u8>): Updates an existing permission entity on PermissionStore storage. Only the name field is updated.
- permissionId: The unique ID of the permission that will be used as part of the key in storage.
- name: The display name of the permission for easy identification.
- assignPermissionToRole(permissionId: EntityId, roleId: EntityId): Creates a new relationship between permission and role entity on Permission2RoleStore storage.
- permissionId: The unique ID of the permission that will be used as part of the key in storage for a relationship to be established.
- roleId: The unique ID of the role that will be used as part of the key in storage for a relationship to be established.
- unassignPermissionToRole(permissionId: EntityId, roleId: EntityId): Disable an existing relationship between permission and role entity on Permission2RoleStore storage.
- permissionId: The unique ID of the permission that will be used as part of the key in storage for a relationship to be established.
- roleId: The unique ID of the role that will be used as part of the key in storage for a relationship to be established.
- assignRoleToGroup(roleId: EntityId, groupId: EntityId): Creates a new relationship between role and group entities on Role2GroupStore storage.
- roleId: The unique ID of the role that will be used as part of the key in storage for a relationship to be established.
- groupId: The unique ID of the group that will be used as part of the key in storage for a relationship to be established.
- unassignRoleToGroup(roleId: EntityId, groupId: EntityId): Disable an existing relationship between role and group entities on Role2GroupStore storage.
- roleId: The unique ID of the role that will be used as part of the key in storage for a relationship to be established.
- groupId: The unique ID of the group that will be used as part of the key in storage for a relationship to be established.
- assignRoleToUser(roleId: EntityId, userId: EntityId): Creates a new relationship between role and user entities on Role2UserStore storage.
- roleId: The unique ID of the role that will be used as part of the key in storage for a relationship to be established.
- userId: The unique ID of the user that will be used as part of the key in storage for a relationship to be established.
- unassignRoleToUser(roleId: EntityId, userId: EntityId): Disable an existing relationship between role and user entities on Role2UserStore storage.
- roleId: The unique ID of the role that will be used as part of the key in storage for a relationship to be established.
- userId: The unique ID of the user that will be used as part of the key in storage for a relationship to be established.
- assignUserToGroup(userId: EntityId, groupId: EntityId): Creates a new relationship between user and group entities on UserToGroupStore storage. The userId and the tag is used as the key while the value is the vector of User2Group struct (Vec<User2Group>).
- userId: The unique ID of the user that will be used as part of the key in storage for a relationship to be established.
- groupId: The unique ID of the group that will be used as part of the key in storage for a relationship to be established.
- unassignUserToGroup(userId: EntityId, groupId: EntityId): Disable an existing relationship between user and group entities on UserToGroupStore storage. The userId and the tag is used as the key while the value is the vector of User2Group struct (Vec<User2Group>).
- userId: The unique ID of the user that will be used as part of the key in storage for a relationship to be established.
- groupId: The unique ID of the group that will be used as part of the key in storage for a relationship to be established.
- disableGroup(groupId: EntityId): Disable a group and all its relationships.
- groupId: The unique ID of the group that is being disabled.
- disableRole(roleId: EntityId): Disable a role and all its relationships.
- roleId: The unique ID of the role that is being disabled.
- disablePermission(permissionId: EntityId): Disable a permission and all its relationships.
- permissionId: The unique ID of the permission that is being disabled.
- fetchGroup(owner: AccountId, groupId: EntityId): Fetches a single group.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- groupId: The unique ID of the group that is being fetched.
- fetchGroupPermissions(owner: AccountId, groupId: EntityId): Fetches all permissions of a group.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- groupId: The unique ID of the group whose permissions are being fetched.
- fetchGroupRoles(owner: AccountId, groupId: EntityId): Fetches all roles of a group.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- fetchGroupRoles(owner: AccountId, groupId: EntityId): Fetches all roles of a group.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- groupId: The unique ID of the group whose roles are being fetched.
- fetchGroups(owner: AccountId): Fetches all groups.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- fetchPermission(owner: AccountId, permissionId: EntityId): Fetches a single permission using its ID.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- permissionId: The unique ID of the permission being fetched.
- fetchPermissions(owner: AccountId): Fetches all permissions.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- fetchRole(owner: AccountId, roleId: EntityId): Fetches a single role using its ID.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- roleId: The unique ID of the role being fetched.
- fetchRolePermissions(owner: AccountId, roleId: EntityId): Fetches all permissions of a role.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- roleId: The unique ID of the role whose permissions are being fetched.
- fetchRoles(owner: AccountId): Fetches all roles.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- fetchUserGroups(owner: AccountId, userId: EntityId): Fetches all groups of a user.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- userId: The unique ID of the user whose groups are being fetched.
- fetchUserPermissions(owner: AccountId, userId: EntityId): Fetches all permissions of a user.
- owner: The account ID of the creator of the entity. This is added to curb an instant where the same entity ID is used by different accounts.
- userId: The unique ID of the user whose permissions are being fetched.
- fetchUserRoles(owner: AccountId, userId: EntityId): Fetches all roles of a user.
- owner: The account ID of the creator of the entity. This is added to curb an instance where the same entity ID is used by different accounts.
- userId: The unique ID of the user whose roles are being fetched.