Implementing Role-Based Access Control (RBAC) in Python
Role-Based Access Control (RBAC) is a crucial security paradigm for managing user permissions. This challenge asks you to implement a basic RBAC system in Python, allowing you to define roles with specific permissions and then assign users to those roles. This is a common requirement in web applications and other systems where access control is necessary.
Problem Description
You need to design and implement a system that manages user roles and permissions. The system should allow you to:
- Define Roles: Create roles (e.g., "admin", "editor", "viewer") and associate each role with a set of permissions (e.g., "create_post", "edit_post", "view_post").
- Assign Users to Roles: Assign users to one or more roles.
- Check Permissions: Given a user and a specific action (permission), determine whether the user is authorized to perform that action.
The core of the system should be a class called RBACManager. This class should have methods for defining roles, assigning users to roles, and checking permissions.
Key Requirements:
- The system should be extensible to handle new roles and permissions easily.
- The permission checking logic should be clear and concise.
- The system should handle cases where a user has multiple roles.
- The system should handle cases where a user has no roles assigned.
Expected Behavior:
- When checking permissions, the system should return
Trueif the user has the required permission through any of their assigned roles, andFalseotherwise. - The system should not raise errors if a role or permission does not exist. Instead, it should return
Falsewhen checking permissions for non-existent roles or permissions.
Edge Cases to Consider:
- User with no roles assigned.
- Role with no permissions assigned.
- Permission that doesn't exist.
- User assigned to multiple roles, some with overlapping permissions.
- Case-insensitive permission checking (optional, but good practice).
Examples
Example 1:
Input:
roles = {
"admin": ["create_post", "edit_post", "view_post", "delete_post"],
"editor": ["edit_post", "view_post"],
"viewer": ["view_post"]
}
user_roles = {
"user1": ["admin", "editor"],
"user2": ["viewer"]
}
rbac = RBACManager(roles)
rbac.assign_user_roles(user_roles)
print(rbac.check_permission("user1", "create_post"))
print(rbac.check_permission("user1", "delete_post"))
print(rbac.check_permission("user2", "edit_post"))
print(rbac.check_permission("user3", "view_post")) # user3 has no roles
Output:
True
True
False
False
Explanation: "user1" is an admin and an editor, so they have "create_post" and "delete_post" permissions. "user2" is a viewer, so they only have "view_post" permission. "user3" has no roles, so they have no permissions.
Example 2:
Input:
roles = {
"admin": ["create_post", "edit_post", "view_post"],
"editor": ["edit_post", "view_post"],
"viewer": ["view_post"]
}
user_roles = {
"user1": ["admin"],
"user2": ["editor"],
"user3": ["viewer"]
}
rbac = RBACManager(roles)
rbac.assign_user_roles(user_roles)
print(rbac.check_permission("user1", "view_post"))
print(rbac.check_permission("user2", "create_post"))
print(rbac.check_permission("user3", "edit_post"))
Output:
True
False
False
Explanation: "user1" has "view_post" permission as an admin. "user2" does not have "create_post" permission. "user3" does not have "edit_post" permission.
Constraints
- The number of roles will be between 1 and 100.
- The number of permissions per role will be between 0 and 20.
- The number of users will be between 1 and 50.
- Role and permission names will be strings of length between 1 and 32 characters.
- User names will be strings of length between 1 and 32 characters.
- The permission checking operation should complete in O(n) time, where n is the number of roles the user has.
Notes
- Consider using dictionaries to represent roles and permissions for efficient lookups.
- Think about how to handle the case where a user has multiple roles. You'll need to iterate through their roles and check permissions.
- You can choose to implement case-insensitive permission checking for added flexibility. If you do, ensure that the comparison is consistent.
- Focus on creating a clean and well-documented solution. The code should be easy to understand and maintain.
- Error handling is not explicitly required for this challenge, but consider how you might handle invalid input in a real-world application.