Publish curated Unraid-AppOps-Gateway source from 68878c3167dacf2b424c16780e60e0d60815e477

This commit is contained in:
Public Source Publisher committed 2026-10-08 18:33:13 +00:00
1 parent 837c263cd8
commit 551de41e9f
18 files changed
+1183 -58

No files matched your search

+54 -3
View File
@@ -14,6 +14,7 @@ import re
import secrets
import uuid
from typing import Any, Literal
from urllib.parse import urlsplit, urlunsplit
from sqlalchemy.exc import IntegrityError
from sqlmodel import Session, select
@@ -30,6 +31,7 @@ from ..schemas.enrollment import (
EnrollmentTrustConfigV1,
)
from .audit_logger import log_event
from .enrollment_oidc_settings import bind_template
from .deployment_broker import DeploymentBrokerClient
from .enrollment_profiles import PROFILE_VERSION, profile_contract, profile_summary
from .secret_store import (
@@ -155,6 +157,22 @@ def _enrollment_secret_store_ready(storage: dict[str, Any]) -> bool:
return bool(storage.get("productionReady"))
def _application_oidc_issuer(issuer: str | None, application_id: str | None = None) -> str | None:
"""Bind Authentik's per-provider issuer to this application's own client."""
if not issuer:
return None
parsed = urlsplit(issuer)
path = parsed.path.rstrip('/')
if application_id is None:
if path not in {'', '/application/o'} and not re.fullmatch(r'/application/o/[a-z][a-z0-9-]{1,62}', path):
return None
return urlunsplit((parsed.scheme, parsed.netloc, path + '/', '', ''))
expected_path = f"/application/o/{application_id}"
if parsed.path.rstrip("/") not in {"", "/application/o", expected_path}:
return None
return urlunsplit((parsed.scheme, parsed.netloc, expected_path + "/", "", ""))
class EnrollmentPlane:
def __init__(
self,
@@ -222,6 +240,8 @@ class EnrollmentPlane:
def capabilities(self, session: Session) -> dict[str, Any]:
trust = self.get_trust_config(session)
if isinstance(self.authentik, AuthentikConnector):
bind_template(session, self.authentik)
storage = secret_storage_status()
configured = trust is not None
bootstrap = bool(trust and has_secret(session, trust.bootstrap_secret_ref))
@@ -335,11 +355,30 @@ class EnrollmentPlane:
oidc_configured = bool(
trust
and trust.oidc_issuer
and _application_oidc_issuer(trust.oidc_issuer)
and trust.administrator_group
and trust.support_agent_group
and trust.read_only_group
and self.authentik.is_configured()
)
if oidc_configured and trust is not None:
template = self.authentik.validate_deployment_oidc_template(
role_claim=trust.oidc_role_claim,
role_groups=(trust.administrator_group, trust.support_agent_group, trust.read_only_group),
)
groups = self.authentik.groups()
found_groups = {
str(group.get("name") or "")
for group in groups.get("items", [])
if isinstance(group, dict)
}
oidc_configured = bool(
template.get("status") == "ready"
and groups.get("success") is True
and {
trust.administrator_group, trust.support_agent_group, trust.read_only_group,
}.issubset(found_groups)
)
certificate_ready = bool(npm_ready)
def item(ready: bool, code: str) -> dict[str, str]:
@@ -464,6 +503,8 @@ class EnrollmentPlane:
def preflight(self, session: Session, plan: EnrollmentPlanV1) -> dict[str, Any]:
checks: list[dict[str, str]] = []
trust = self.get_trust_config(session)
if isinstance(self.authentik, AuthentikConnector):
bind_template(session, self.authentik)
profile = profile_contract(plan.profile)
if trust is None:
checks.append(_check("enrollment_trust_not_configured", "blocked", "Root enrollment trust boundaries are not configured."))
@@ -586,6 +627,13 @@ class EnrollmentPlane:
checks.append(_check("oidc_profile_unavailable", "blocked", "Configured OIDC profile or Authentik role groups are unavailable."))
else:
assert trust is not None and plan.authentication.roles is not None
issuer_matches = _application_oidc_issuer(trust.oidc_issuer, plan.application_id)
checks.append(_check(
"oidc_issuer" if issuer_matches else "oidc_issuer_mismatch",
"passed" if issuer_matches else "blocked",
"Authentik issuer is bound to this application's own provider."
if issuer_matches else "Configured issuer belongs to a different application or unsupported issuer path.",
))
expected_roles = {
"administrator": trust.administrator_group,
"support_agent": trust.support_agent_group,
@@ -603,8 +651,9 @@ class EnrollmentPlane:
if auth_status.get("status") != "connected":
checks.append(_check("oidc_provider", "blocked", "Authentik is unavailable."))
else:
template = self.authentik.deployment_oidc_template_status(
role_claim=trust.oidc_role_claim
template = self.authentik.validate_deployment_oidc_template(
role_claim=trust.oidc_role_claim,
role_groups=(trust.administrator_group, trust.support_agent_group, trust.read_only_group),
)
if template.get("status") != "ready":
checks.append(_check("oidc_profile_unavailable", "blocked", "The server-owned Authentik OIDC template is incomplete."))
@@ -978,6 +1027,8 @@ class EnrollmentPlane:
raise EnrollmentError("application identity or repository is already enrolled")
trust = self.get_trust_config(session)
if isinstance(self.authentik, AuthentikConnector):
bind_template(session, self.authentik)
if trust is None:
raise EnrollmentError("enrollment trust boundaries are not configured")
enrollment = self._create_enrollment(session, plan, plan_digest, trust)
@@ -1145,7 +1196,7 @@ class EnrollmentPlane:
runtime_values.update({
"OIDC_CLIENT_ID": plan.application_id,
"OIDC_CLIENT_SECRET": oidc_secret,
"OIDC_ISSUER": trust.oidc_issuer or "",
"OIDC_ISSUER": _application_oidc_issuer(trust.oidc_issuer, plan.application_id) or "",
"OIDC_ROLE_CLAIM": trust.oidc_role_claim,
})
if plan.profile == "repopulse-authenticated":