feat: add OIDC sign-in, roles, sessions and client address rule

Authorization-code flow with PKCE through an idp adapter (with a fake), ID
token validation, identity and roles resolved from the directory with a short
cache, refusal of unknown, disabled and locked accounts with one generic page,
sessions that end when the account becomes unavailable, sign-out that ends the
server-side session, role decorators and the trusted-proxy client address rule.
Adds the OIDC_* and PUBLIC_BASE_URL configuration.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N3t4WL7bd9bdHHNjEsxzqC
This commit is contained in:
2026-10-17 19:19:51 +02:00
co-authored by Claude Sonnet 5.5
parent 7458a2a815
commit 3c69c2a156
32 changed files with 1692 additions and 14 deletions
+7 -1
View File
@@ -19,11 +19,12 @@ BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = _config.secret_key
DEBUG = _config.debug
ALLOWED_HOSTS = _config.allowed_hosts
# Reserved for the client-IP rule in a later entry; currently has no effect.
# The client-IP rule (AD-7) trusts X-Forwarded-For only from these peers.
TRUSTED_PROXIES = _config.trusted_proxies
DATA_DIR = _config.data_dir
DISPLAY_TIME_ZONE = _config.default_timezone
DIRECTORY = _config.directory
OIDC = _config.oidc
INSTALLED_APPS = [
"django.contrib.contenttypes",
@@ -36,11 +37,13 @@ INSTALLED_APPS = [
MIDDLEWARE = [
"portal.config.middleware.RequestIdMiddleware",
"portal.accounts.middleware.ClientIpMiddleware",
"portal.config.middleware.SecurityHeadersMiddleware",
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"portal.accounts.middleware.AbsoluteSessionLimitMiddleware",
"portal.accounts.middleware.CurrentUserMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
@@ -99,10 +102,13 @@ SESSION_ENGINE = "portal.accounts.session_store"
SESSION_COOKIE_AGE = 60 * 60 # idle limit: 1 hour, renewed on every request
SESSION_SAVE_EVERY_REQUEST = True
SESSION_ABSOLUTE_SECONDS = 4 * 60 * 60 # absolute limit: 4 hours
# How long roles and account state are trusted before the directory is asked again (AD-5).
ROLE_CACHE_SECONDS = 60
SESSION_COOKIE_SECURE = not DEBUG
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
CSRF_COOKIE_SECURE = not DEBUG
CSRF_TRUSTED_ORIGINS = [OIDC.public_base_url]
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = "Lax"