feat: RBAC multi-user role-based access control
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 1m14s
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 1m14s
- Add rbac.py with User model, LDAP group-to-role mapping, page/write dependencies - Proxy auth reads Remote-Groups header to resolve role from LDAP groups - JWT tokens carry role claim, /me returns role + allowed pages - Per-router page access control and viewer write protection - Terminal WebSocket RBAC check - Frontend filters sidebar links and routes by allowed pages - Admin-only Settings page and RBAC override endpoints - Mount rbac.json in docker-compose for page config persistence
This commit is contained in:
@@ -7,6 +7,7 @@ from slowapi.util import get_remote_address
|
||||
from slowapi.errors import RateLimitExceeded
|
||||
from routers import docker_router, gitea, files, terminal, system, auth, chat_summary, security
|
||||
import auth as auth_module
|
||||
from rbac import require_page, require_write
|
||||
|
||||
import asyncio
|
||||
import httpx
|
||||
@@ -139,16 +140,27 @@ def _router_reachable():
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# Dependency to store user in request.state for rbac dependencies
|
||||
async def _inject_user(request: Request, user = Depends(auth_module.get_current_user)):
|
||||
request.state.user = user
|
||||
return user
|
||||
|
||||
# Public auth endpoints
|
||||
app.include_router(auth.router, prefix="/api/auth", tags=["auth"])
|
||||
|
||||
# Protected endpoints
|
||||
app.include_router(docker_router.router, prefix="/api/docker", dependencies=[Depends(auth_module.get_current_user)])
|
||||
app.include_router(gitea.router, prefix="/api/gitea", dependencies=[Depends(auth_module.get_current_user)])
|
||||
app.include_router(files.router, prefix="/api/files", dependencies=[Depends(auth_module.get_current_user)])
|
||||
app.include_router(system.router, prefix="/api/system", dependencies=[Depends(auth_module.get_current_user)])
|
||||
app.include_router(chat_summary.router, prefix="/api/chat-summary", dependencies=[Depends(auth_module.get_current_user)])
|
||||
app.include_router(security.router, prefix="/api/security", dependencies=[Depends(auth_module.get_current_user)])
|
||||
# Protected endpoints with page-level RBAC
|
||||
app.include_router(docker_router.router, prefix="/api/docker",
|
||||
dependencies=[Depends(_inject_user), Depends(require_page("docker")), Depends(require_write())])
|
||||
app.include_router(gitea.router, prefix="/api/gitea",
|
||||
dependencies=[Depends(_inject_user), Depends(require_page("gitea"))])
|
||||
app.include_router(files.router, prefix="/api/files",
|
||||
dependencies=[Depends(_inject_user), Depends(require_page("files")), Depends(require_write())])
|
||||
app.include_router(system.router, prefix="/api/system",
|
||||
dependencies=[Depends(_inject_user), Depends(require_page("dashboard"))])
|
||||
app.include_router(chat_summary.router, prefix="/api/chat-summary",
|
||||
dependencies=[Depends(_inject_user), Depends(require_page("chat-digest"))])
|
||||
app.include_router(security.router, prefix="/api/security",
|
||||
dependencies=[Depends(_inject_user), Depends(require_page("security"))])
|
||||
|
||||
# WebSocket endpoint (auth handled inside handler via Query param)
|
||||
app.add_api_websocket_route("/ws/terminal", terminal.ws_endpoint)
|
||||
|
||||
Reference in New Issue
Block a user