АРХ - NODEDC PLATFORM: fix Authentik JWKS signing
This commit is contained in:
parent
4a10726b2e
commit
1d37acdb83
|
|
@ -6,6 +6,23 @@
|
|||
|
||||
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
|
||||
|
||||
Минимальный normalized user object:
|
||||
|
|
@ -40,16 +57,15 @@ nodedc:superadmin
|
|||
Launcher:
|
||||
|
||||
```text
|
||||
nodedc:launcher:access
|
||||
nodedc:launcher:admin
|
||||
nodedc:launcher:user-manager
|
||||
nodedc:launcher:user
|
||||
```
|
||||
|
||||
Task Manager:
|
||||
|
||||
```text
|
||||
nodedc:taskmanager:access
|
||||
nodedc:taskmanager:admin
|
||||
nodedc:taskmanager:user
|
||||
```
|
||||
|
||||
Future apps:
|
||||
|
|
@ -67,6 +83,8 @@ nodedc:dm:access
|
|||
|
||||
Отвечает на вопрос, можно ли открыть приложение.
|
||||
|
||||
Launcher показывает каталог приложений как витрину, а не скрывает все недоступные плитки. Для приложения без доступа кнопка перехода отключена и отображается состояние "Нет доступа". Это важно для продаж, onboarding и понимания доступных модулей платформы.
|
||||
|
||||
Уровень 2: Launcher admin roles.
|
||||
|
||||
Отвечает на вопрос, можно ли управлять пользователями, группами, app registry и audit.
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@
|
|||
|
||||
## Current local apps
|
||||
|
||||
Launcher сейчас запускается как Vite app из:
|
||||
Launcher сейчас запускается как Vite app + local BFF из:
|
||||
|
||||
```text
|
||||
/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:
|
||||
|
||||
```text
|
||||
|
|
@ -116,6 +118,8 @@ This creates:
|
|||
- `NODE.DC Task Manager` application with OAuth2/OIDC provider;
|
||||
- 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.
|
||||
|
||||
Проверка:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from django.db import transaction
|
|||
|
||||
from authentik.common.oauth.constants import SubModes
|
||||
from authentik.core.models import Application, Group, User
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.policies.models import PolicyBinding
|
||||
from authentik.providers.oauth2.models import (
|
||||
|
|
@ -127,6 +128,13 @@ def default_scope_mappings():
|
|||
def ensure_provider(spec, mappings):
|
||||
authorization_flow = Flow.objects.get(slug="default-provider-authorization-implicit-consent")
|
||||
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()
|
||||
if provider is None:
|
||||
|
|
@ -146,6 +154,7 @@ def ensure_provider(spec, mappings):
|
|||
provider.issuer_mode = IssuerMode.PER_PROVIDER
|
||||
provider.authorization_flow = authorization_flow
|
||||
provider.invalidation_flow = invalidation_flow
|
||||
provider.signing_key = signing_key
|
||||
provider.save()
|
||||
provider.property_mappings.set(mappings)
|
||||
return provider
|
||||
|
|
|
|||
Loading…
Reference in New Issue