Fixes for public mode authentication flows.
This commit is contained in:
+6
-1
@@ -95,8 +95,13 @@ async def control(req, ws):
|
||||
async def watch(req, ws):
|
||||
# Build user info from either built-in auth or SSO
|
||||
user_info = None
|
||||
if sso.paskia_enabled():
|
||||
# SSO auth: call validation to get user info (don't enforce auth in public mode)
|
||||
try:
|
||||
await sso.validate_sso_request(req)
|
||||
except Exception:
|
||||
pass # Ignore auth errors, user_info stays None
|
||||
if sso_user := getattr(req.ctx, "sso_user", None):
|
||||
# SSO auth (paskia mode): extract from validation response
|
||||
ctx = sso_user.get("ctx", {})
|
||||
perms = ctx.get("permissions", [])
|
||||
user_info = {
|
||||
|
||||
+1
-4
@@ -257,10 +257,7 @@ def get_files(wanted: set) -> list[tuple[PurePosixPath, Path]]:
|
||||
@app.get("/zip/<keys>/<zipfile:ext=zip>")
|
||||
async def zip_download(req, keys, zipfile, ext):
|
||||
"""Download a zip archive of the given keys"""
|
||||
if config.config.authentication == "paskia":
|
||||
await auth.verify_sso(req)
|
||||
else:
|
||||
auth.verify(req)
|
||||
await auth.verify(req)
|
||||
|
||||
wanted = set(keys.split("+"))
|
||||
files = get_files(wanted)
|
||||
|
||||
+8
-11
@@ -236,39 +236,36 @@ async def verify(request, *, privileged=False):
|
||||
|
||||
For paskia mode (PASKIA_BACKEND_URL set), validates against the SSO backend.
|
||||
For built-in mode, checks session-based authentication.
|
||||
For public mode (config.public=True), allows all requests.
|
||||
|
||||
All 401/403 responses include auth.iframe URL for consistent frontend handling
|
||||
via the paskia library's showAuthIframe().
|
||||
For public mode (config.public=True), skips auth unless privileged is required.
|
||||
|
||||
Args:
|
||||
request: The Sanic request object
|
||||
privileged: If True, requires admin privileges
|
||||
privileged: If True, requires admin privileges (always enforced even in public mode)
|
||||
|
||||
Raises:
|
||||
Unauthorized: If authentication is required
|
||||
Forbidden: If access is denied
|
||||
"""
|
||||
# Public mode: skip auth unless privileged access is required
|
||||
if config.config.public and not privileged:
|
||||
return
|
||||
|
||||
sso = _get_sso()
|
||||
if sso.paskia_enabled():
|
||||
# SSO validation against auth backend
|
||||
# Always check cista:login; privileged flag comes from response perm list
|
||||
perm = "cista:admin" if privileged else "cista:login"
|
||||
await sso.validate_sso_request(request, perm=perm)
|
||||
return
|
||||
|
||||
user = getattr(request.ctx, "user", None)
|
||||
if privileged:
|
||||
if user:
|
||||
if user.privileged:
|
||||
if user and user.privileged:
|
||||
return
|
||||
raise Forbidden(
|
||||
"Access Forbidden: Only for privileged users",
|
||||
quiet=True,
|
||||
)
|
||||
elif config.config.public or user:
|
||||
if user:
|
||||
return
|
||||
# Return iframe URL for paskia library to show login dialog
|
||||
raise Unauthorized(
|
||||
f"Login required for {request.path}",
|
||||
"cookie",
|
||||
|
||||
@@ -94,11 +94,11 @@ const settingsMenu = (e: Event) => {
|
||||
|
||||
if (store.user.isLoggedIn) {
|
||||
items.push({ label: '🚪 Logout', onClick: () => store.logout() })
|
||||
} else if (!ssoStore.isExternalAuth) {
|
||||
// Show login in paskia iframe overlay
|
||||
} else if (store.server.public) {
|
||||
// Show login option only in public mode (non-public modes trigger auth automatically)
|
||||
items.push({ label: '🔐 Login', onClick: async () => {
|
||||
try {
|
||||
await showAuthIframe('/auth/restricted')
|
||||
await showAuthIframe('/auth/restricted#theme=light')
|
||||
resumeWatching()
|
||||
} catch (e) {
|
||||
console.log('Login cancelled')
|
||||
|
||||
Reference in New Issue
Block a user