Fix RBAC role-based permissions for accounts endpoint
Fixed critical bugs preventing users from seeing accounts through their assigned roles: 1. **Fixed duplicate function definition** (crud.py) - Removed duplicate auto_assign_default_role() that only took 1 parameter - Kept correct version with proper signature and logging - Added get_all_user_roles() helper function 2. **Added role-based permissions to accounts endpoint** (views_api.py) - Previously only checked direct user permissions - Now retrieves and combines both direct AND role permissions - Auto-assigns default role to new users on first access 3. **Fixed permission inheritance logic** (views_api.py) - Inheritance check now uses combined permissions (direct + role) - Previously only checked direct user permissions for parents - Users can now inherit access to child accounts via role permissions Changes enable proper RBAC functionality: - Users with "Employee" role (or any role) now see permitted accounts - Permission inheritance works correctly with role-based permissions - Auto-assignment of default role on first Castle access 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c086916be8
commit
52c6c3f8f1
2 changed files with 134 additions and 35 deletions
85
crud.py
85
crud.py
|
|
@ -1502,6 +1502,31 @@ async def get_user_roles(user_id: str) -> list[UserRole]:
|
|||
]
|
||||
|
||||
|
||||
async def get_all_user_roles() -> list[UserRole]:
|
||||
"""Get all active user role assignments"""
|
||||
rows = await db.fetchall(
|
||||
"""
|
||||
SELECT * FROM user_roles
|
||||
WHERE (expires_at IS NULL OR expires_at > :now)
|
||||
ORDER BY user_id, granted_at DESC
|
||||
""",
|
||||
{"now": datetime.now()},
|
||||
)
|
||||
|
||||
return [
|
||||
UserRole(
|
||||
id=row["id"],
|
||||
user_id=row["user_id"],
|
||||
role_id=row["role_id"],
|
||||
granted_by=row["granted_by"],
|
||||
granted_at=row["granted_at"],
|
||||
expires_at=row["expires_at"],
|
||||
notes=row["notes"],
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
|
||||
|
||||
async def get_role_users(role_id: str) -> list[UserRole]:
|
||||
"""Get all users assigned to a role"""
|
||||
rows = await db.fetchall(
|
||||
|
|
@ -1550,6 +1575,41 @@ async def get_role_count_for_user(user_id: str) -> int:
|
|||
return row["count"] if row else 0
|
||||
|
||||
|
||||
async def auto_assign_default_role(user_id: str, assigned_by: str) -> UserRole | None:
|
||||
"""
|
||||
Auto-assign the default role to a user if they don't have any roles yet.
|
||||
Returns the created UserRole if assigned, None if user already has roles or no default role exists.
|
||||
"""
|
||||
from loguru import logger
|
||||
|
||||
logger.info(f"[AUTO-ASSIGN] Checking auto-assignment for user {user_id}")
|
||||
|
||||
# Check if user already has any roles
|
||||
user_role_count = await get_role_count_for_user(user_id)
|
||||
logger.info(f"[AUTO-ASSIGN] User {user_id} has {user_role_count} roles")
|
||||
if user_role_count > 0:
|
||||
logger.info(f"[AUTO-ASSIGN] User {user_id} already has roles, skipping auto-assignment")
|
||||
return None
|
||||
|
||||
# Find the default role
|
||||
default_role = await get_default_role()
|
||||
if not default_role:
|
||||
logger.warning(f"[AUTO-ASSIGN] No default role found, cannot auto-assign for user {user_id}")
|
||||
return None
|
||||
|
||||
logger.info(f"[AUTO-ASSIGN] Found default role: {default_role.name} (id: {default_role.id})")
|
||||
|
||||
# Assign the default role
|
||||
data = AssignUserRole(
|
||||
user_id=user_id,
|
||||
role_id=default_role.id,
|
||||
notes="Auto-assigned default role on first access",
|
||||
)
|
||||
result = await assign_user_role(data, assigned_by)
|
||||
logger.info(f"[AUTO-ASSIGN] Successfully assigned role {default_role.name} to user {user_id}")
|
||||
return result
|
||||
|
||||
|
||||
async def get_user_count_for_role(role_id: str) -> int:
|
||||
"""Get count of users assigned to a role"""
|
||||
row = await db.fetchone(
|
||||
|
|
@ -1601,28 +1661,3 @@ async def check_user_has_role_permission(
|
|||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
async def auto_assign_default_role(user_id: str) -> Optional[UserRole]:
|
||||
"""
|
||||
Auto-assign the default role to a new user.
|
||||
Returns the UserRole if a default role exists and was assigned, None otherwise.
|
||||
"""
|
||||
default_role = await get_default_role()
|
||||
if not default_role:
|
||||
return None
|
||||
|
||||
# Check if user already has this role
|
||||
user_roles = await get_user_roles(user_id)
|
||||
if any(ur.role_id == default_role.id for ur in user_roles):
|
||||
return None
|
||||
|
||||
# Assign the default role
|
||||
return await assign_user_role(
|
||||
AssignUserRole(
|
||||
user_id=user_id,
|
||||
role_id=default_role.id,
|
||||
notes="Auto-assigned default role",
|
||||
),
|
||||
granted_by="system",
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue