Role Based Access Control

Role Based Access Control

Manish Dipankar's photo
·

9 min read

At Girmantech, we partner with numerous clients across diverse industries, and one challenge we consistently encounter is the need for robust and flexible systems like Role-Based Access Control (RBAC). Whether it's managing complex user permissions, safeguarding sensitive data, or enhancing operational efficiency, a scalable, granular RBAC system is critical.

What is RBAC?

RBAC (Role-Based Access Control) is a method of managing user permissions based on their roles within an organization. It assigns specific privileges to roles, and users are granted access to resources based on the roles they belong to.

Basic RBAC?

Basic RBAC assigns predefined roles to users, granting them fixed permissions. This approach is suitable for simple systems but lacks flexibility for organizations with dynamic roles and permissions.

Example of Basic RBAC

  1. Administrator:

    • Can create, edit, and delete users, roles, and products.

    • Has full control over the management plane.

  2. Manager:

    • Can create and edit users and products.

    • Can assign and remove roles from users.

    • Cannot delete users or roles.

Example of Granular RBAC for Product Management

Scenario:

A company has a product management platform with different levels of product managers: Product Owners, Product Managers, and Product Analysts. Each role requires varying levels of access to product data and management capabilities.

Granular RBAC Implementation:

  • Product Owner:

      • Can create, edit, and delete products.

        • Can manage product life cycle, set goals, and prioritise features.

        • Can assign and remove product managers and analysts.

  • Product Manager:

      • Can create, edit, and view products.

        • Can manage product features, track progress, and collaborate with teams.
  • Product Analyst:

      • Can view product data, analyse metrics, and provide insights.
  • The owner of the tenant can create as many roles as they want based on their organisational structure, assign permission corresponding to that role and map user to each role !

AspectSimple RBACGranular RBAC
Permission ControlBroad permissions, applied uniformly across resources.Fine-grained permissions, applied to specific actions and resources.
FlexibilityLimited, suitable for straightforward use cases.Highly flexible, suitable for complex environments.
Implementation ComplexityEasy to implement and maintain.Complex to implement and maintain.
Use CasesBest for smaller applications with straightforward requirements.Ideal for large, complex systems with diverse access needs.
Role DefinitionRoles are broadly defined with fixed permissions.Roles are detailed, with specific permissions tied to actions and resources.
ExampleA content management system with "Admin," "Editor," and "Viewer" roles.An enterprise system with varying access to financial data and customer records.

Scenarios in which Granular RBAC shines.

Simple RBAC assigns broad roles (e.g., Manager, Employee), while Granular RBAC grants specific permissions based on tasks.

Organizations with complex structures and workflows benefit greatly from granular RBAC. It allows for precise control over access, ensuring employees only have the permissions they need to do their jobs effectively.

1. Fine-Tuned Access: Allows precise permissions, ensuring users only access what they need.
2. Approval Processes: Controls access at each workflow stage for secure progress.
3.Separation of Duties: Ensures no single user controls an entire process, reducing fraud risk.
4. Scalable Management: Adapts easily as roles and workflows evolve within the enterprise.
5. Compliance: Facilitates detailed access control and logging for regulatory compliance.
6. Insider Threats: Limits access to essential functions, minimizing misuse risks.
7. Collaboration: Enables controlled information sharing while protecting sensitive data.
8. Temporary Access: Provides time-bound permissions that expire automatically for added security.

How to implement Granular RBAC in an RDBMS system and exposing API on top of that !

Table Users

Column NameConstraintsData TypeRemark
idPRIMARY KEY, UNIQUEBIGSERIALAuto-incrementing unique identifier for users
nameNOT NULLVARCHAR(255)User's full name
emailUNIQUEVARCHAR(255)User's email address
verifiedBOOLEANUser's hashed password
created_atNOT NULLTIMESTAMPTimestamp indicating when the user was created
updated_atNOT NULLBIGINT
created_byFK ( users.id ), NOT NULLBIGINT
updated_byFK ( users.id ), NOT NULLBIGINT

Table - Tenants

Column NameConstraintsData TypeRemark
idPRIMARY KEYBIGSERIALAuto-incrementing unique identifier for tenants
nameNOT NULLVARCHAR(255)Tenant name
ownerFOREIGN KEY REFERENCES USER(user_id), NOT NULLINTEGERUser ID of the tenant owner
created_atNOT NULLBIGINTTimestamp indicating when the tenant was created
updated_atBIGSERIALBIGINT
created_byFK ( users.id ), NOT NULLBIGINT
updated_byFK ( users.id ), NOT NULLBIGINT

Table - Roles

Column NameConstraintsData TypeRemark
idPRIMARY KEY, UNIQUEBIGSERIALAuto-incrementing unique identifier for roles
nameNOT NULLVARCHAR(255)Role name
tenant_idPRIMARY KEY, UNIQUEBIGSERIALTenant ID associated with the role
descriptionTEXTDescription of the role
created_atNOT NULLBIGINTTimestamp indicating when the role was created
updated_atNOT NULLBIGINT
created_byFK ( users.id ), NOT NULLBIGINT
updated_byFK ( users.id ), NOT NULLBIGINT

Table - user_role_mapping

Column NameConstraintsData TypeRemark
idPRIMARY KEYBIGSERIALAuto-incrementing unique identifier for user role mapping
user_idFOREIGN KEY REFERENCES USER(user_id)INTEGERUser ID associated with the role
role_idFOREIGN KEY REFERENCES ROLE(role_id)INTEGERRole ID associated with the user
created_atNOT NULLBIGINTTimestamp indicating when the mapping was created
updated_atTIMESTAMPBIGINT
created_byFK ( users.id ), NOT NULLBIGINT
updated_byFK ( users.id ), NOT NULLBIGINT

Table - features

Column NameConstraintsData TypeRemark
idPRIMARY KEY, UNIQUE, DEFAULT nextval('feature_seq')BIGSERIALAuto-incrementing unique identifier for features
api_identifierNOT NULL, UNIQUEVARCHAR(255)Feature name
api_methodNOT NULLVARCHAR(255)POST, PUT, PATCH, GET, DELETE
api_urlNOT NULLVARCHAR(255)
descriptionTEXTDescription of the feature
created_byFOREIGN KEY REFERENCES USER(user_id)INTEGERUser ID of the creator
updated_byFOREIGN KEY REFERENCES USER(user_id)INTEGERUser ID of the last updater
created_atNOT NULLBIGINTTimestamp indicating when the feature was created
updated_atNOT NULLBIGINT

Table - Role Feature Mapping

Column NameConstraintsData TypeRemark
idPRIMARY KEYBIGSERIALAuto-incrementing unique identifier for user role mapping
role_idFOREIGN KEY REFERENCES ROLE(role_id)INTEGERRole ID associated with the feature. UNIQ ( role_id, feature_id )
feature_idFOREIGN KEY REFERENCES FEATURE(feature_id)INTEGERFeature ID associated with the role. UNIQ ( role_id, feature_id )
created_atNOT NULLTIMESTAMPTimestamp indicating when the mapping was created
updated_atTIMESTAMPTimestamp indicating when the mapping was last updated
created_byFK ( users.id ), NOT NULLBIGINT
updated_byFK ( users.id ), NOT NULLBIGINT

API Specification for RBAC and Feature Management

Token-based authentication: Use JWT tokens to authenticate API requests.

  • Endpoint: /login

    Request:

Response:

  • 200 OK

  • Body: JSON { "token": "your_jwt_token", “refresh_token” : “your_refresh_token” }

  • 401 UnAuthorized if authentication fails.

User Management

Authentication. The logged In user must be authenticated and should be the owner of the tenant !

GET: List all users: /users

POST: Create a new user : /users

GET: Retrieve a specific user: /users/{user_id}

PUT: Update a user: /users/{users_id}

DELETE: Delete a user: /users/{users_id}

Role Management

Authentication. The logged In user must be authenticated and should be the owner of the tenant !

GET: List all roles: /tenant/{tenant_id}/roles

POST: Create a new role: /tenant/{tenant_id}/roles

GET: Retrieve a specific role: /tenant/{tenant_id}/roles/{role_id}

PUT: Update a role: /tenant/{tenant_id}/roles/{role_id}

DELETE: Delete a role: /tenant/{tenant_id}/roles/{role_id}

Feature Management

Endpoint: /features

GET: List all features: Requires authentication and no special roles. This API is not tenant specific.

INSERT, UPDATE and DELETE of features to be maintained by the developers of application.

Role-Feature Mapping

Authentication. The logged In user must be authenticated and should be the owner of the tenant !

GET: List features associated with a role: /tenant/{tenant_id}/roles/{role_id}/features

POST: Associate a feature with a role: /tenant/{tenant_id}/roles/{role_id}/features

DELETE: Disassociate a feature from a role: /tenant/{tenant_id}/roles/{role_id}/features/{mapping_id}

User-Role Mapping

Authentication. The logged In user must be authenticated and should be the owner of the tenant !

POST: Associate a role with a user: /tenant/{tenant_id}/user_role_mapping. user_id and role_id is provided in the request body !

PUT: Change the role of a user: /tenant/{tenant_id}/user_role_mapping: user_id and role_id is provided in the request body !

DELETE: not supported as a user must be associated to 1 role.

GET: Not supported as we want to return the role of the user in the GET USER rest call.

Middleware

  • Implement middleware to check for authentication tokens, extract user information, and enforce access control based on user roles and feature permissions.

Authentication:

  • Verify the user's identity using JWT tokens and extract the user's ID from the authenticated token.

  • Return 401 if token validation fails or if token has expired

Role Retrieval:

  • Fetch the user's associated role from the USER_ROLE_MAPPING table based on the user ID.

  • Retrieve the corresponding features from the ROLE_FEATURE_MAPPING table.

  • Before allowing access to a feature, check if the user's permissions include that feature.

    • You can check it with the help of “api_url” + “api_method” combination or you can annotate api_identifier on top of each controller method and test it out.
  • If the user has permission, proceed with the request.

  • If the user lacks permission, return an appropriate error response (e.g., 403 Forbidden).