АРХ - NODEDC PLATFORM: fix Authentik JWKS signing

This commit is contained in:
Codex 2026-05-04 11:52:13 +03:00
parent 4a10726b2e
commit 1d37acdb83
3 changed files with 35 additions and 4 deletions

View File

@ -6,6 +6,23 @@
Launcher, Plane и будущие приложения не хранят пароли пользователей и не становятся главным источником truth по логину. Launcher, Plane и будущие приложения не хранят пароли пользователей и не становятся главным источником truth по логину.
## User journey
Целевой production flow:
```text
nodedc.ru marketing site
-> Войти на платформу
-> platform login
-> NODE.DC Launcher
-> application tiles
-> Task Manager / future apps
```
UI платформы не должен показывать пользователю название identity-провайдера. В пользовательских кнопках и текстах используется нейтральное "Войти", "Вход на платформу", "Сессия NODE.DC".
Прямые ссылки на приложения остаются допустимым пользовательским сценарием. Если session нет, приложение или внешний proxy/auth layer должен увести пользователя в login flow и после успешного входа вернуть к исходному приложению.
## Required claims ## Required claims
Минимальный normalized user object: Минимальный normalized user object:
@ -40,16 +57,15 @@ nodedc:superadmin
Launcher: Launcher:
```text ```text
nodedc:launcher:access
nodedc:launcher:admin nodedc:launcher:admin
nodedc:launcher:user-manager nodedc:launcher:user
``` ```
Task Manager: Task Manager:
```text ```text
nodedc:taskmanager:access
nodedc:taskmanager:admin nodedc:taskmanager:admin
nodedc:taskmanager:user
``` ```
Future apps: Future apps:
@ -67,6 +83,8 @@ nodedc:dm:access
Отвечает на вопрос, можно ли открыть приложение. Отвечает на вопрос, можно ли открыть приложение.
Launcher показывает каталог приложений как витрину, а не скрывает все недоступные плитки. Для приложения без доступа кнопка перехода отключена и отображается состояние "Нет доступа". Это важно для продаж, onboarding и понимания доступных модулей платформы.
Уровень 2: Launcher admin roles. Уровень 2: Launcher admin roles.
Отвечает на вопрос, можно ли управлять пользователями, группами, app registry и audit. Отвечает на вопрос, можно ли управлять пользователями, группами, app registry и audit.

View File

@ -18,12 +18,14 @@
## Current local apps ## Current local apps
Launcher сейчас запускается как Vite app из: Launcher сейчас запускается как Vite app + local BFF из:
```text ```text
/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher /Users/dcconstructions/Downloads/mnt/data/nodedc_launcher
``` ```
В dev режиме `npm run dev` запускает BFF на `:5173`; Vite подключен как middleware. Чистый Vite режим сохранен как `npm run dev:vite`.
Task Manager сейчас доступен как Plane self-host runtime: Task Manager сейчас доступен как Plane self-host runtime:
```text ```text
@ -116,6 +118,8 @@ This creates:
- `NODE.DC Task Manager` application with OAuth2/OIDC provider; - `NODE.DC Task Manager` application with OAuth2/OIDC provider;
- group bindings for application access. - group bindings for application access.
OIDC providers must have a signing key. Without it Authentik returns an empty JWKS (`{}`), and Launcher callback fails token validation.
The script fills missing `LAUNCHER_OIDC_CLIENT_SECRET` and `PLANE_OIDC_CLIENT_SECRET` values in ignored `infra/.env`. Secrets are not committed. The script fills missing `LAUNCHER_OIDC_CLIENT_SECRET` and `PLANE_OIDC_CLIENT_SECRET` values in ignored `infra/.env`. Secrets are not committed.
Проверка: Проверка:

View File

@ -4,6 +4,7 @@ from django.db import transaction
from authentik.common.oauth.constants import SubModes from authentik.common.oauth.constants import SubModes
from authentik.core.models import Application, Group, User from authentik.core.models import Application, Group, User
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow from authentik.flows.models import Flow
from authentik.policies.models import PolicyBinding from authentik.policies.models import PolicyBinding
from authentik.providers.oauth2.models import ( from authentik.providers.oauth2.models import (
@ -127,6 +128,13 @@ def default_scope_mappings():
def ensure_provider(spec, mappings): def ensure_provider(spec, mappings):
authorization_flow = Flow.objects.get(slug="default-provider-authorization-implicit-consent") authorization_flow = Flow.objects.get(slug="default-provider-authorization-implicit-consent")
invalidation_flow = Flow.objects.get(slug="default-provider-invalidation-flow") invalidation_flow = Flow.objects.get(slug="default-provider-invalidation-flow")
signing_key = (
CertificateKeyPair.objects.filter(name="authentik Self-signed Certificate").first()
or CertificateKeyPair.objects.first()
)
if signing_key is None:
raise RuntimeError("No Authentik CertificateKeyPair exists for OIDC signing")
provider = OAuth2Provider.objects.filter(name=spec["provider_name"]).first() provider = OAuth2Provider.objects.filter(name=spec["provider_name"]).first()
if provider is None: if provider is None:
@ -146,6 +154,7 @@ def ensure_provider(spec, mappings):
provider.issuer_mode = IssuerMode.PER_PROVIDER provider.issuer_mode = IssuerMode.PER_PROVIDER
provider.authorization_flow = authorization_flow provider.authorization_flow = authorization_flow
provider.invalidation_flow = invalidation_flow provider.invalidation_flow = invalidation_flow
provider.signing_key = signing_key
provider.save() provider.save()
provider.property_mappings.set(mappings) provider.property_mappings.set(mappings)
return provider return provider