feat: v6.7.0 — SSO/SAML + OIDC entreprise (SP SAML signé + OIDC PKCE, auto-provisioning, groupes IdP → rôles workspace, SSO only, onglet Settings « SSO / Enterprise », API /api/v2/sso/*, help, migration 23, docs + OpenAPI 439 chemins) · 802 tests verts
This commit is contained in:
@@ -983,3 +983,87 @@ def _migration_row_content_pages(conn: sqlite3.Connection) -> None:
|
||||
"CREATE INDEX IF NOT EXISTS idx_pages_row "
|
||||
"ON pages(collection_row_id) WHERE collection_row_id IS NOT NULL"
|
||||
)
|
||||
|
||||
|
||||
@register(23, "v6.7.0: SSO/SAML enterprise auth")
|
||||
def _migration_sso_enterprise_auth(conn: sqlite3.Connection) -> None:
|
||||
"""v6.7.0 — SSO/SAML 2.0 + OIDC enterprise authentication.
|
||||
|
||||
``sso_config`` — single active SSO provider (SAML or OIDC), managed
|
||||
from Settings → Admin → SSO / Enterprise. Secrets
|
||||
(``client_secret``, SP private key) are encrypted at
|
||||
rest by ``app.services.sso_provisioning``.
|
||||
``sso_login_history`` — audit trail of every SSO login attempt (successes
|
||||
AND rejections — signature failure, replay, no
|
||||
local account…).
|
||||
``sso_requests`` — single-use anti-replay store: AuthnRequest ids and
|
||||
OIDC states, CSRF relay tokens, PKCE verifiers and
|
||||
the post-login redirect target. One row is consumed
|
||||
by exactly one callback.
|
||||
"""
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS sso_config (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
workspace_id INTEGER REFERENCES workspaces(id) ON DELETE CASCADE,
|
||||
provider_type TEXT NOT NULL DEFAULT 'saml',
|
||||
name TEXT NOT NULL DEFAULT 'Company SSO',
|
||||
entity_id TEXT NOT NULL DEFAULT '',
|
||||
sso_url TEXT NOT NULL DEFAULT '',
|
||||
slo_url TEXT DEFAULT '',
|
||||
x509_certificate TEXT NOT NULL DEFAULT '',
|
||||
issuer_url TEXT DEFAULT '',
|
||||
client_id TEXT DEFAULT '',
|
||||
client_secret TEXT DEFAULT '',
|
||||
scope TEXT DEFAULT 'openid profile email',
|
||||
attribute_mapping TEXT NOT NULL DEFAULT '{}',
|
||||
groups_mapping TEXT NOT NULL DEFAULT '[]',
|
||||
auto_provision INTEGER NOT NULL DEFAULT 1,
|
||||
sso_only INTEGER NOT NULL DEFAULT 0,
|
||||
sign_requests INTEGER NOT NULL DEFAULT 0,
|
||||
default_workspace_id INTEGER REFERENCES workspaces(id) ON DELETE SET NULL,
|
||||
sp_private_key TEXT DEFAULT '',
|
||||
sp_certificate TEXT DEFAULT '',
|
||||
active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INTEGER REFERENCES users(id)
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS sso_login_history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
provider_type TEXT NOT NULL,
|
||||
provider_name TEXT NOT NULL DEFAULT 'SSO',
|
||||
sso_identifier TEXT,
|
||||
ip_address TEXT DEFAULT '',
|
||||
user_agent TEXT DEFAULT '',
|
||||
success INTEGER NOT NULL DEFAULT 0,
|
||||
error_message TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_sso_history_user "
|
||||
"ON sso_login_history(user_id, created_at)"
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS sso_requests (
|
||||
id TEXT PRIMARY KEY,
|
||||
kind TEXT NOT NULL,
|
||||
relay_state TEXT NOT NULL DEFAULT '',
|
||||
code_verifier TEXT NOT NULL DEFAULT '',
|
||||
next_path TEXT NOT NULL DEFAULT '/workspaces',
|
||||
used INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_sso_requests_created ON sso_requests(created_at)"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user