Hone logo
Hone
Problems

Python Permission System Challenge

Imagine you're building a web application or a system where different users have varying levels of access to different resources. You need a robust way to manage these permissions. This challenge asks you to design and implement a Python-based permission system that allows you to define users, roles, and permissions, and then check if a specific user has the necessary permission for an action on a resource.

Problem Description

Your task is to create a Python class-based system that models users, roles, and permissions. This system should allow you to:

  1. Define Resources: Represent different entities or actions within your system that require permissions (e.g., 'document:read', 'document:write', 'user:admin').
  2. Define Roles: Group permissions into logical roles (e.g., 'editor', 'viewer', 'administrator'). A role can have multiple permissions assigned to it.
  3. Define Users: Represent individual users. Each user can be assigned one or more roles.
  4. Check Permissions: Implement a method to verify if a given user possesses a specific permission. This check should consider all roles assigned to the user.

Key Requirements:

  • Class-Based Design: Utilize Python classes for User, Role, and Permission.
  • Permission Granularity: Permissions should be strings, allowing for detailed access control (e.g., resource_type:action).
  • Role-Based Access Control (RBAC): Users gain permissions through their assigned roles.
  • Efficient Permission Checking: The system should be able to quickly determine if a user has a permission.

Expected Behavior:

  • A user should have a permission if any of their assigned roles grants that permission.
  • The system should handle cases where a user has no roles or no permissions assigned to any of their roles.

Edge Cases to Consider:

  • A user with no roles assigned.
  • A role with no permissions assigned.
  • Checking for a permission that is not defined anywhere.
  • Case sensitivity of permission strings.

Examples

Example 1:

# Setup
permission_read = "document:read"
permission_write = "document:write"
permission_admin = "user:admin"

role_viewer = Role("Viewer")
role_viewer.add_permission(permission_read)

role_editor = Role("Editor")
role_editor.add_permission(permission_read)
role_editor.add_permission(permission_write)

role_admin = Role("Administrator")
role_admin.add_permission(permission_read)
role_admin.add_permission(permission_write)
role_admin.add_permission(permission_admin)

user_alice = User("Alice")
user_alice.assign_role(role_viewer)

user_bob = User("Bob")
user_bob.assign_role(role_editor)

user_charlie = User("Charlie")
user_charlie.assign_role(role_editor)
user_charlie.assign_role(role_admin)

# Checks
print(user_alice.has_permission(permission_read))    # Expected: True
print(user_alice.has_permission(permission_write))   # Expected: False
print(user_bob.has_permission(permission_write))     # Expected: True
print(user_charlie.has_permission(permission_admin)) # Expected: True

Output:

True
False
True
True

Explanation: Alice is a viewer, so she can only read documents. Bob is an editor and can read and write. Charlie is both an editor and an administrator, so he has all the permissions of both roles, including the ability to administer users.

Example 2: User with no roles

# Setup
permission_read = "document:read"

role_viewer = Role("Viewer")
role_viewer.add_permission(permission_read)

user_david = User("David") # David has no roles assigned

# Checks
print(user_david.has_permission(permission_read)) # Expected: False

Output:

False

Explanation: David has no roles, therefore he inherits no permissions and cannot read documents.

Example 3: Role with no permissions

# Setup
permission_read = "document:read"

role_empty = Role("Empty") # This role has no permissions added

role_viewer = Role("Viewer")
role_viewer.add_permission(permission_read)

user_eve = User("Eve")
user_eve.assign_role(role_empty)
user_eve.assign_role(role_viewer)

# Checks
print(user_eve.has_permission(permission_read)) # Expected: True (from Viewer role)
print(user_eve.has_permission("any:permission")) # Expected: False

Output:

True
False

Explanation: Eve has two roles. While the "Empty" role grants no permissions, the "Viewer" role grants document:read. Therefore, Eve has the read permission. She does not have any:permission as neither of her roles grants it.

Constraints

  • Permission strings are case-sensitive.
  • The system should be designed to handle a potentially large number of users, roles, and permissions efficiently.
  • Your implementation should be in Python 3.
  • You may define additional helper classes or methods as needed, but the core functionality should be within User and Role classes.

Notes

  • Consider how you will store permissions within a Role and how a User will aggregate permissions from their roles.
  • Think about the data structures that would be most efficient for checking if a permission exists.
  • The goal is to create a clean, object-oriented solution.
Loading editor...
python