added auth flag and auth to /upload
This commit is contained in:
@@ -47,7 +47,7 @@ IMAP2_DELETE_AFTER_PROCESS=false
|
|||||||
GOTENBERG_URL=http://gotenberg:3000
|
GOTENBERG_URL=http://gotenberg:3000
|
||||||
|
|
||||||
# ** needed for Authentik **
|
# ** needed for Authentik **
|
||||||
|
AUTH_ENABLED=true
|
||||||
SESSION_SECRET=<atLeast32Characters>
|
SESSION_SECRET=<atLeast32Characters>
|
||||||
AUTHENTIK_CLIENT_ID=<yourAuthentikAppClientID>
|
AUTHENTIK_CLIENT_ID=<yourAuthentikAppClientID>
|
||||||
AUTHENTIK_CLIENT_SECRET=<yourAuthentikAppClientSecret>
|
AUTHENTIK_CLIENT_SECRET=<yourAuthentikAppClientSecret>
|
||||||
|
|||||||
+34
-36
@@ -1,4 +1,5 @@
|
|||||||
# app/auth.py
|
# app/auth.py
|
||||||
|
# app/auth.py
|
||||||
import os
|
import os
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
@@ -10,60 +11,57 @@ from starlette.responses import RedirectResponse
|
|||||||
config = Config(".env")
|
config = Config(".env")
|
||||||
oauth = OAuth(config)
|
oauth = OAuth(config)
|
||||||
|
|
||||||
oauth.register(
|
AUTH_ENABLED = config("AUTH_ENABLED", cast=bool, default=True)
|
||||||
name="authentik",
|
|
||||||
client_id=config("AUTHENTIK_CLIENT_ID"),
|
if AUTH_ENABLED:
|
||||||
client_secret=config("AUTHENTIK_CLIENT_SECRET"),
|
oauth.register(
|
||||||
server_metadata_url=config("AUTHENTIK_CONFIG_URL"),
|
name="authentik",
|
||||||
client_kwargs={
|
client_id=config("AUTHENTIK_CLIENT_ID"),
|
||||||
"scope": "openid profile email",
|
client_secret=config("AUTHENTIK_CLIENT_SECRET"),
|
||||||
},
|
server_metadata_url=config("AUTHENTIK_CONFIG_URL"),
|
||||||
)
|
client_kwargs={"scope": "openid profile email"},
|
||||||
|
)
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
def get_current_user(request: Request):
|
def get_current_user(request: Request):
|
||||||
return request.session.get("user")
|
return request.session.get("user")
|
||||||
|
|
||||||
|
|
||||||
def require_login(func):
|
def require_login(func):
|
||||||
|
if not AUTH_ENABLED:
|
||||||
|
return func # no-op
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
async def wrapper(request: Request, *args, **kwargs):
|
async def wrapper(request: Request, *args, **kwargs):
|
||||||
if not request.session.get("user"):
|
if not request.session.get("user"):
|
||||||
# Save original URL in session before redirecting to login
|
|
||||||
request.session["redirect_after_login"] = str(request.url)
|
request.session["redirect_after_login"] = str(request.url)
|
||||||
return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
|
return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
|
||||||
return await func(request, *args, **kwargs)
|
return await func(request, *args, **kwargs)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@router.get("/login")
|
|
||||||
async def login(request: Request):
|
|
||||||
"""
|
|
||||||
Initiate Authentik login flow.
|
|
||||||
This calls oauth.authentik.authorize_redirect(...)
|
|
||||||
The resulting redirect_uri must match what's in Authentik's application config.
|
|
||||||
"""
|
|
||||||
redirect_uri = request.url_for("auth")
|
|
||||||
return await oauth.authentik.authorize_redirect(request, redirect_uri)
|
|
||||||
|
|
||||||
@router.get("/auth")
|
if AUTH_ENABLED:
|
||||||
async def auth(request: Request):
|
@router.get("/login")
|
||||||
"""
|
async def login(request: Request):
|
||||||
Authentik callback endpoint. Exchanges code for token,
|
redirect_uri = request.url_for("auth")
|
||||||
puts user info in session, and redirects to /ui or wherever you want.
|
return await oauth.authentik.authorize_redirect(request, redirect_uri)
|
||||||
"""
|
|
||||||
token = await oauth.authentik.authorize_access_token(request)
|
|
||||||
userinfo = token.get("userinfo")
|
|
||||||
request.session["user"] = dict(userinfo)
|
|
||||||
|
|
||||||
# Get original destination or fallback
|
@router.get("/auth")
|
||||||
redirect_url = request.session.pop("redirect_after_login", "/ui")
|
async def auth(request: Request):
|
||||||
return RedirectResponse(url=redirect_url)
|
token = await oauth.authentik.authorize_access_token(request)
|
||||||
|
userinfo = token.get("userinfo")
|
||||||
|
request.session["user"] = dict(userinfo)
|
||||||
|
redirect_url = request.session.pop("redirect_after_login", "/upload")
|
||||||
|
return RedirectResponse(url=redirect_url)
|
||||||
|
|
||||||
|
@router.get("/logout")
|
||||||
|
async def logout(request: Request):
|
||||||
|
request.session.pop("user", None)
|
||||||
|
return RedirectResponse(url="/")
|
||||||
|
|
||||||
@router.get("/logout")
|
|
||||||
async def logout(request: Request):
|
|
||||||
"""Clears session and redirects home."""
|
|
||||||
request.session.pop("user", None)
|
|
||||||
return RedirectResponse(url="/")
|
|
||||||
|
|
||||||
@router.get("/private")
|
@router.get("/private")
|
||||||
@require_login
|
@require_login
|
||||||
|
|||||||
+4
-1
@@ -2,6 +2,7 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
from app.auth import require_login
|
||||||
import os
|
import os
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
@@ -14,7 +15,9 @@ frontend_folder = os.path.join(os.path.dirname(__file__), "..", "frontend")
|
|||||||
router.mount("/static", StaticFiles(directory=frontend_folder), name="static")
|
router.mount("/static", StaticFiles(directory=frontend_folder), name="static")
|
||||||
|
|
||||||
# 2) For the root route ("/"), return the index.html
|
# 2) For the root route ("/"), return the index.html
|
||||||
@router.get("/ui", response_class=FileResponse)
|
|
||||||
|
@router.get("/upload", response_class=FileResponse)
|
||||||
|
@require_login
|
||||||
def serve_ui():
|
def serve_ui():
|
||||||
return os.path.join(frontend_folder, "index.html")
|
return os.path.join(frontend_folder, "index.html")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user