How to create a simple role management feature?

Satya G
SAFE Engineering
Published in
6 min readMay 25, 2021

Role Management requirement is a basic access control functionality for a product that has different kinds of user roles. Some access control methods focus on the resource being requested like MAC/DAC (Mandatory/Discretionary Access Control), while other methods focus on the identity of the user who made the request like IBAC (Identity Based Access Control) in which each individual is given specific access rights for every operation.

IBAC can be used in simple systems with few users, However as systems grow in user numbers, it usually gets difficult to manage. RBAC (Role-Based Access Control) tries to solve the limitations of IBAC by mimicking the real-world needs more closely. In RBAC operational privileges are grouped into roles and each user is assigned a role (Think of a role as a group of users that have some common characteristics). The difference between IBAC and RBAC is that the role, instead of the individual, is the basis for access checks.

In this article, we will try to achieve the following two objectives:

  • understand the role management feature
  • learn the approach to implement role management for an imaginary virtual school application

One final thing I want to tell you before we dwell on the solution, don’t take the requirements you just read above for granted, in real-world scenarios most probably these requirements will keep changing again and again according to different business needs.

What is Role Management?

In any company, we have different employees with different roles. Some of the common roles in an organization could be HR (who manage human resources of the companies), IT (who manage IT-related issues), Accounts (who manage accounts related work, transfer salary, maintain accounts documents, other finances), Sales (who sell the products), and developers (who are the most critical piece :p, they develop) too. As it is quite evident, depending upon an employee's role, they perform their respective actions.

The basic principle of Role-Management is simple: the Finance department can’t see HR data and vice versa.

Suppose, when you’re developing an enterprise product, and if your product is going to be used by various employees in the organization with different roles, you need to provide a mechanism to manage the product as per the user role.

Let us take an example to understand what I mean by that.

Note that this example will be used to explain the further parts of the article.

Suppose you’re creating an online/virtual school application (relatable these days). In that, teachers can start a class, end a class, take attendance, give assignments, take exams, give results, etc. Similarly, students can attend class, submit assignments, attend exams, view results. Then the guardians can pay fees, attend the parents-teachers meetings, collaborate with teachers, etc.

In the above example, there are multiple users of your application i.e., Teachers, Students, Parents. These are the different roles of users for your application. They have their actions to be performed, and their actions should not be performed by any user of some other role. It means a student user should not be able to start a class or end a class.

In a way we can say, we need to devise a mechanism in the product to manage these roles. This is called Role Management.

How to implement the Role Management feature?

There are multiple solutions you will find on the web. In this article, we discuss a simple approach as following.

Let us define some terms which will be used while implementation.

Roles — a string based on the role of the user. For example — Teachers, Students, Guardians, etc.

Permissions — a string based on access level. For example — start_class, end_class, submit_assignment, evaluate_assignment, etc.

permissions_status — a binary string denoting a list of permissions and their status (allowed/denied) (will be further explained below). For example — 0110, 0010, etc.

We can define the following tables (in a relational database):-

1- Roles: contains the list of roles.

(`id`, `name`)

For example — (1, ‘Teacher’), (2, ‘Student’), (3, ‘Guardians’)

2- Permissions: contains the list of permissions

(`id`, `name`)

For example — (1, ‘start_class’), (2, ‘end_class’), (3, ‘submit_assignment’), (4, ‘evaluate_assignment’)

3- Policy: denotes the group of permissions and their status, whether they are allowed or not allowed.

(`id`, `permissions_status`)

For example — (1, ‘0010’), (2, ‘1101’)

Now be careful, `permissions_status` will be a string, of length equal to the number of available permissions. In the above table `Permissions`, there are 4 permissions, so `permissions_status` will be a string of length 4.

The value of `permissions_status` at any `index` can be either 0 or 1 (binary string). For ex- 0000, 1000, 1101, etc.

The value of a bit at any `index` denotes whether, in the current policy, the corresponding permission is allowed or denied.

For ex- if there is a policy row (1, 1001), it means for this policy, start_class and evaluate_assignment permissions are allowed, whereas end_class and `submit_assignment` permissions are denied. This should get more clear ahead.

4- Role_Policy_Map: maps a policy to a role.

(`id`, `role_id`, `policy_id`)

For example — (1, 1, 2), This means, for role_id = 1, the policy attached is the second one.

The next thing we need to prepare is a mapping between resources and permissions as below. (url_permission.js)

Now, suppose we have the following resources (URLs):

example.com/class/start

example.com/class/end

example.com/assignments/submit

example.com/assignments/evaluate

The mapping in url_permission.js denotes that for a given URL, all permissions which are needed to be checked. For example, if some user requests example.com/class/start, then we need to check whether the user has start_class permission allowed or denied. If it is denied, the request is not authorized. Otherwise, the request is authorized. Now if there are multiple permissions against a URL, we should check whether any of them is allowed, then the request is authorized. If all the permissions are denied, then the request is not authorized.

url_permission.js

Implementation Flow

Let us say a request is made to assignments/submit, by a user whose role_id = 2 (Student).

1- Now we find which policy is attached to the current role. (let us restrict to only one policy per role).

2- Now we can fetch the `permissions_status` string for policy_id in step 1.

3- From `permissions_status`, we can calculate an array of permissions that are allowed in that policy.

4- Now we find which permissions are needed to be checked for this URL (which can be found from url_permission.js).

5- Now, we check whether at least one of the permissions from the `permissions_to_be_checked` array is allowed or not.

That’s it! We have now created a very simple resource-based role management system.

Now, if a student accesses “example.com/class/start”, it will give “Unauthorized error”, whereas, for a teacher, it will work just fine.

Furthermore, when you create a new URL / API, you need to perform the following steps:

  1. Create new permission for new Url in the “Permissions” table
  2. Append a bit (corresponding to the new permission in step 1) in the policy table for all the rows
  3. Add new Url / API in url_permission.js.

Things to ponder!

How to handle the URLs which do not require any permission?

How can we extend this to support multiple policies for one role?

How to handle a url with dynamic values? (/class/start/1, /class/start/2, …)

--

--