mud_server.api.permissions
Role-based permission system (RBAC).
This module implements a Role-Based Access Control (RBAC) system for the MUD server. It defines: 1. User roles with different privilege levels 2. Specific permissions that can be checked 3. Mapping of which roles have which permissions 4. Helper functions to check permissions and role hierarchy
- Role Hierarchy (lowest to highest):
Player → World Builder → Admin → Superuser
Permission Design: - Each role has an explicit set of permissions - Roles DO NOT automatically inherit lower role permissions (must be explicit) - Superuser has a special FULL_ACCESS permission that grants everything - Permissions are granular to allow fine-grained access control
Usage in API Routes: 1. Use validate_session_with_permission() to check specific permissions 2. Use require_permission() decorator for route-level protection 3. Use require_role() decorator for minimum role requirements 4. Use can_manage_role() to prevent privilege escalation
Security Considerations: - Never allow users to elevate their own privileges - Always check role hierarchy for user management operations - Superusers can manage everyone, admins can manage lower roles - Players and World Builders cannot manage other users
Attributes
Classes
User roles in the system, ordered by privilege level. |
|
Specific permissions that can be granted to roles. |
Functions
|
Check if a role has a specific permission. |
|
Get the numeric hierarchy level of a role. |
|
Check if a manager can manage (promote/demote/ban) a target user. |
|
Decorator to require a specific permission for a route. |
|
Decorator to require a minimum role level for a route. |
Module Contents
- class mud_server.api.permissions.Role(*args, **kwds)[source]
Bases:
enum.EnumUser roles in the system, ordered by privilege level.
Each role represents a different level of access and trust in the system. Roles are stored as lowercase strings in the database but represented as enum values in code for type safety.
- Roles (in order of privilege):
PLAYER: Standard game player (lowest privilege) WORLDBUILDER: Player with world editing capabilities ADMIN: Administrator with user management powers SUPERUSER: Super administrator with full system access (highest privilege)
- PLAYER = 'player'
- WORLDBUILDER = 'worldbuilder'
- ADMIN = 'admin'
- SUPERUSER = 'superuser'
- class mud_server.api.permissions.Permission(*args, **kwds)[source]
Bases:
enum.EnumSpecific permissions that can be granted to roles.
Permissions are organized by category and represent specific actions that users can perform. Each permission should be as granular as possible to allow fine-grained access control.
- Permission Categories:
Player: Basic gameplay actions
World Builder: Content creation and editing
Admin: User management and system administration
Superuser: Full unrestricted access
- PLAY_GAME = 'play_game'
- CHAT = 'chat'
- EDIT_WORLD = 'edit_world'
- CREATE_ROOMS = 'create_rooms'
- CREATE_ITEMS = 'create_items'
- CREATE_USERS = 'create_users'
- KICK_USERS = 'kick_users'
- BAN_USERS = 'ban_users'
- VIEW_LOGS = 'view_logs'
- STOP_SERVER = 'stop_server'
- MANAGE_USERS = 'manage_users'
- CHANGE_ROLES = 'change_roles'
- FULL_ACCESS = 'full_access'
- mud_server.api.permissions.ROLE_PERMISSIONS: dict[Role, set[Permission]]
- mud_server.api.permissions.has_permission(role, permission)[source]
Check if a role has a specific permission.
This is the core permission checking function used throughout the application. It converts the role string to an enum, looks up the role’s permissions, and checks if the requested permission is granted.
- Special Case:
Superusers automatically have ALL permissions due to the FULL_ACCESS permission. This is checked first before looking up specific permissions.
- Parameters:
role (str) – Role string (case-insensitive: “player”, “worldbuilder”, “admin”, “superuser”)
permission (Permission) – Permission enum value to check (e.g., Permission.MANAGE_USERS)
- Returns:
True if the role has the permission, False if not or if role is invalid
- Return type:
Example
>>> has_permission("admin", Permission.VIEW_LOGS) True >>> has_permission("player", Permission.MANAGE_USERS) False >>> has_permission("superuser", Permission.ANYTHING) True # Superuser has all permissions
- mud_server.api.permissions.get_role_hierarchy_level(role)[source]
Get the numeric hierarchy level of a role.
The hierarchy level is used to determine which users can manage other users. Higher numbers indicate more privilege. This prevents lower-privileged users from managing higher-privileged users.
- Hierarchy Levels:
0 = Player (lowest privilege) 1 = World Builder 2 = Admin 3 = Superuser (highest privilege)
- Parameters:
role (str) – Role string (case-insensitive)
- Returns:
Integer hierarchy level (0-3) Returns 0 for invalid/unknown roles (treated as lowest privilege)
- Return type:
Example
>>> get_role_hierarchy_level("admin") 2 >>> get_role_hierarchy_level("player") 0 >>> get_role_hierarchy_level("invalid") 0
- mud_server.api.permissions.can_manage_role(manager_role, target_role)[source]
Check if a manager can manage (promote/demote/ban) a target user.
This function enforces the rule that you can only manage users with a lower hierarchy level than yourself. This prevents privilege escalation and ensures proper administrative boundaries.
- Management Rules:
Superuser (3) can manage Admin (2), WorldBuilder (1), Player (0)
Admin (2) can manage WorldBuilder (1), Player (0)
WorldBuilder (1) can manage Player (0)
Player (0) cannot manage anyone
You CANNOT manage users at the same level or higher
- Parameters:
- Returns:
True if manager can manage target, False otherwise
- Return type:
- Security Note:
Always call this function before allowing role changes, bans, or other user management actions to prevent privilege escalation attacks.
Example
>>> can_manage_role("admin", "player") True >>> can_manage_role("player", "admin") False >>> can_manage_role("admin", "admin") False # Cannot manage users at same level >>> can_manage_role("superuser", "admin") True
- mud_server.api.permissions.require_permission(permission)[source]
Decorator to require a specific permission for a route.
This decorator wraps a route function and checks if the user has the required permission before allowing the function to execute. If the user lacks the permission, an HTTP 403 Forbidden error is raised.
Note
This decorator is currently defined but not actively used in the codebase. Most routes use validate_session_with_permission() directly instead. This decorator could be useful for cleaner route definitions in the future.
- Parameters:
permission (Permission) – The permission required to access the route
- Returns:
Decorator function that wraps the route handler
- Raises:
HTTPException(403) – If user lacks the required permission
- Usage:
@app.post(“/admin/action”) @require_permission(Permission.MANAGE_USERS) async def admin_action(username: str, role: str):
# This only executes if user has MANAGE_USERS permission …
- Requirements:
The wrapped function must have “role” in its kwargs, typically obtained from validate_session() before calling the route handler.
- mud_server.api.permissions.require_role(min_role)[source]
Decorator to require a minimum role level for a route.
This decorator checks role hierarchy level rather than specific permissions. It ensures the user has at least the specified role level (or higher) before allowing access to the route.
Note
This decorator is currently defined but not actively used in the codebase. Most routes use validate_session_with_permission() for permission-based checks instead of role-based checks. However, this could be useful for routes that need role-level restrictions regardless of specific permissions.
- Parameters:
min_role (Role) – Minimum role enum value required (e.g., Role.ADMIN)
- Returns:
Decorator function that wraps the route handler
- Raises:
HTTPException(403) – If user’s role is below the minimum required level
- Usage:
@app.post(“/admin/dashboard”) @require_role(Role.ADMIN) async def admin_dashboard(username: str, role: str):
# This only executes if user is Admin or Superuser …
- Requirements:
The wrapped function must have “role” in its kwargs, typically obtained from validate_session() before calling the route handler.
Example
If min_role=Role.ADMIN: - Superuser (level 3) ✓ Allowed (3 >= 2) - Admin (level 2) ✓ Allowed (2 >= 2) - WorldBuilder (level 1) ✗ Denied (1 < 2) - Player (level 0) ✗ Denied (0 < 2)