Switch from UniAuth to OpenID Connect

This commit is contained in:
Edward Betts 2026-02-17 11:25:55 +00:00
parent 1f026c31ca
commit e0b9e4e719
3 changed files with 50 additions and 16 deletions

View file

@ -2,7 +2,6 @@
from flipflop import WSGIServer
import sys
sys.path.append('/home/edward/src/agenda') # isort:skip
sys.path.append("/home/edward/src/2024/UniAuth")
from web_view import app # isort:skip
if __name__ == '__main__':

View file

@ -87,7 +87,7 @@
</ul>
<ul class="navbar-nav ms-auto">
{% if g.user.is_authenticated %}
<li class="nav-item"><a class="nav-link" href="{{ url_for("logout", next=request.url) }}">Logout</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for("logout") }}">Logout</a></li>
{% else %}
<li class="nav-item"><a class="nav-link" href="{{ url_for("login", next=request.url) }}">Login</a></li>
{% endif %}

View file

@ -15,10 +15,11 @@ from collections import defaultdict
from datetime import date, datetime, timedelta, timezone
import flask
import UniAuth.auth
import werkzeug
import werkzeug.debug.tbtools
import yaml
from authlib.integrations.flask_client import OAuth
from werkzeug.middleware.proxy_fix import ProxyFix
import agenda.data
import agenda.error_mail
@ -36,14 +37,33 @@ from agenda.types import StrDict, Trip
app = flask.Flask(__name__)
app.debug = False
app.config.from_object("config.default")
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
agenda.error_mail.setup_error_mail(app)
oauth = OAuth(app)
authentik_url = app.config["AUTHENTIK_URL"]
oauth.register(
name="authentik",
client_id=app.config["AUTHENTIK_CLIENT_ID"],
client_secret=app.config["AUTHENTIK_CLIENT_SECRET"],
server_metadata_url=f"{authentik_url}/application/o/agenda/.well-known/openid-configuration",
client_kwargs={"scope": "openid email profile"},
)
class User:
"""Simple user object for template compatibility."""
def __init__(self, is_authenticated: bool) -> None:
"""Init."""
self.is_authenticated = is_authenticated
@app.before_request
def handle_auth() -> None:
"""Handle authentication and set global user."""
flask.g.user = UniAuth.auth.get_current_user()
"""Set global user from session."""
flask.g.user = User(is_authenticated=bool(flask.session.get("user")))
@app.errorhandler(werkzeug.exceptions.InternalServerError)
@ -831,23 +851,38 @@ def schengen_report() -> str:
return agenda.trip_schengen.flask_route_schengen_report()
@app.route("/callback")
def auth_callback() -> tuple[str, int] | werkzeug.Response:
"""Process the authentication callback."""
return UniAuth.auth.auth_callback()
@app.route("/login")
def login() -> werkzeug.Response:
"""Login."""
next_url = flask.request.args["next"]
return UniAuth.auth.redirect_to_login(next_url)
"""Redirect to Authentik for OIDC login."""
next_url = flask.request.args.get("next", flask.url_for("index"))
flask.session["login_next"] = next_url
redirect_uri = flask.url_for("auth_callback", _external=True)
return oauth.authentik.authorize_redirect(redirect_uri)
@app.route("/callback")
def auth_callback() -> werkzeug.Response:
"""Handle OIDC callback from Authentik."""
try:
token = oauth.authentik.authorize_access_token()
except Exception:
return flask.redirect(flask.url_for("login"))
userinfo = token.get("userinfo") or oauth.authentik.userinfo()
flask.session["user"] = {
"sub": userinfo["sub"],
"username": userinfo.get("preferred_username"),
"email": userinfo.get("email"),
}
next_url = flask.session.pop("login_next", flask.url_for("index"))
return flask.redirect(next_url)
@app.route("/logout")
def logout() -> werkzeug.Response:
"""Logout."""
return UniAuth.auth.redirect_to_logout(flask.request.args["next"])
"""Log out and redirect to Authentik end-session endpoint."""
flask.session.pop("user", None)
end_session_url = f"{authentik_url}/application/o/agenda/end-session/"
return flask.redirect(end_session_url)
if __name__ == "__main__":