Role-Based Access Control (RBAC) System in Python
This challenge asks you to design and implement a basic Role-Based Access Control (RBAC) system in Python. RBAC is a common security model where permissions are assigned to roles, and users are assigned to roles, rather than directly assigning permissions to users. This simplifies permission management, especially in larger applications.
Problem Description
You need to create a Python class called PermissionSystem that manages users, roles, permissions, and their relationships. The system should allow you to:
- Define Permissions: Create new permissions with unique names (e.g., "read_data", "write_data", "delete_data").
- Define Roles: Create new roles with unique names (e.g., "administrator", "editor", "viewer").
- Assign Permissions to Roles: Grant specific permissions to roles (e.g., the "administrator" role has "read_data", "write_data", and "delete_data" permissions).
- Create Users: Create new users with unique identifiers.
- Assign Users to Roles: Assign users to one or more roles (e.g., user "john" is assigned to the "editor" role).
- Check User Permissions: Given a user and a permission, determine if the user has that permission. This should be based on the roles the user is assigned to and the permissions granted to those roles.
Key Requirements:
- The system should be extensible to handle more complex scenarios (e.g., hierarchical roles, permission inheritance).
- The system should be efficient in checking user permissions.
- Error handling: Handle cases where a permission or role doesn't exist gracefully.
Expected Behavior:
The PermissionSystem class should provide methods for each of the functionalities listed above. The check_permission method is the core of the system and should accurately determine if a user has a given permission.
Edge Cases to Consider:
- A user with no roles assigned.
- A permission not assigned to any role.
- A role with no permissions assigned.
- Attempting to assign a non-existent role to a user.
- Attempting to check a permission for a non-existent user.
Examples
Example 1:
Input:
permissions = ["read", "write", "delete"]
roles = ["admin", "editor", "viewer"]
users = ["john", "jane", "peter"]
system = PermissionSystem()
system.add_permission("read")
system.add_permission("write")
system.add_permission("delete")
system.add_role("admin")
system.add_role("editor")
system.add_role("viewer")
system.grant_permission("read", "admin")
system.grant_permission("write", "admin")
system.grant_permission("read", "editor")
system.add_user("john")
system.add_user("jane")
system.add_user("peter")
system.assign_user_to_role("john", "editor")
system.assign_user_to_role("jane", "admin")
Output:
system.check_permission("john", "read") # True
system.check_permission("john", "write") # False
system.check_permission("jane", "read") # True
system.check_permission("jane", "write") # True
system.check_permission("peter", "read") # False
Explanation: John is an editor and editors have read permission. Jane is an admin and admins have read and write permissions. Peter has no roles and therefore no permissions.
Example 2:
Input:
system = PermissionSystem()
system.add_permission("create")
system.add_role("manager")
system.grant_permission("create", "manager")
system.add_user("bob")
system.assign_user_to_role("bob", "manager")
Output:
system.check_permission("bob", "create") # True
system.check_permission("bob", "read") # False
Explanation: Bob is a manager and managers have create permission. He does not have read permission.
Example 3: (Edge Case)
Input:
system = PermissionSystem()
system.add_user("alice")
Output:
system.check_permission("alice", "read") # False
Explanation: Alice has no roles assigned, so she has no permissions.
Constraints
- Permission and role names must be unique strings.
- User identifiers must be unique.
- The number of permissions, roles, and users should be reasonably limited (e.g., less than 1000 each) for performance considerations. While not strictly enforced, excessive numbers could impact performance.
- All method arguments must be validated to prevent errors (e.g., checking if a role exists before assigning a user to it).
Notes
- Consider using dictionaries or sets to efficiently store and retrieve permissions, roles, and user assignments.
- Think about how to structure your code to make it easy to add new features in the future (e.g., hierarchical roles).
- Focus on clarity and readability in your code. Good variable names and comments are appreciated.
- Error handling is important. Raise appropriate exceptions when invalid input is provided.
- This is a simplified RBAC system. Real-world RBAC systems can be much more complex.