GSSO — Потребители и контракт потребителя
| Код документа | SPEC-GSSO-2026 / Отчёт 03 |
| Версия | 0.1-draft (исходный текст EN, имеющий преимущественную силу) |
| Дата | 2026-10-05 |
| Статус | Черновик |
| Сопутствующие отчёты | 00 ТЗ · 01 ADR · 02 Требования · 04 Техническая документация · 05 Дорожная карта |
История изменений
Section titled “История изменений”| Версия | Дата | Изменения |
|---|---|---|
| 0.1-draft | 2026-10-05 | Перечень потребителей (по состоянию на 2026-10-05), целевые realm/клиент/роль для каждого приложения, пути миграции, контракт API/событий/starter, чек-лист подключения |
1. Текущие схемы интеграции
Section titled “1. Текущие схемы интеграции”| Схема | Описание | Проблема |
|---|---|---|
| A — двойная аутентификация с выпуском собственного token | oauth2Login через Keycloak, затем OidcAppTokenSuccessHandler выпускает собственный JWT приложения HS512 (копируя ROLE_*) и возвращает его SPA через /oidc-callback#id_token=. Локальный вход admin/admin по-прежнему работает | Локальный ключ подписи и пароли; нет SSO-выхода; отзыв в Keycloak не действует; два источника идентичности |
| B — resource server | Приложение проверяет token RS256 Keycloak через issuer/JWKS; SPA использует PKCE или OAuth2 JHipster | Корректно, но у каждого приложения свой код и своё сопоставление ролей |
| C — локальный JWT (+ MPass SAML) | Собственные пользователи и пароли; MPass через SAML непосредственно в приложении | Нет SSO с gStack |
| D — спроектировано, не реализовано | Приложения по playbook: шлюз BFF + микросервисы с OAuth2 через GSSO | Требуются CAP-GSSO-01..07 |
Цель для всех: GSSO-ADR-009. Это означает шлюз/BFF или resource server через gsso-spring-boot-starter, SPA через @gstack/gsso-angular и отсутствие локальных паролей и самостоятельно выпускаемых token.
2. Перечень потребителей и миграция
Section titled “2. Перечень потребителей и миграция”Realm interdictii — текущий общий realm. «Целевой» означает realm gstack, если не указано иное.
| Приложение | Вид | Сегодня (realm / клиент / схема) | Целевые клиенты | Целевые роли (примеры) | Примечания к миграции | Фаза |
|---|---|---|---|---|---|---|
| saas_interdictii | SaaS | interdictii / interdictii-web confidential / A (незакоммиченный ручной патч, JHipster 8.11 jwt) | interdictii-web (confidential, BFF) или interdictii-spa (PKCE) + interdictii-api (bearer) | INTERDICTII_ADMIN, INTERDICTII_EMITENT, INTERDICTII_APROBATOR, INTERDICTII_CONSULTANT, INTERDICTII_AUDITOR | Заменить OidcAppTokenSuccessHandler на resource server через starter; убрать локальные пароли; сопоставить RolUser ADMIN/EMITENT с ролями; публичный API консультаций → сервисные клиенты для банков/ANAF в realm tenant- или gstack | S4 |
| cancelarie | SaaS | interdictii / cancelarie confidential / B (JHipster oauth2, собственная подготовка учётных записей в identity/) | cancelarie (confidential), cancelarie-api | CANCELARIA_REGISTRATOR, _SEF, _EXECUTOR, _CONTROLOR, _AUDITOR, _ADMIN | Подключение сотрудников вызывает запросы на предоставление доступа api/v1/app (GSSO-FR-051) вместо локального допуска; локальный dev-realm jhipster заменяется compose-стеком GSSO | S4 |
| gregistry | SaaS | interdictii / gregistry-web public PKCE / B (ADR-002) | идентификаторы без изменений, перенесены в gstack | GREGISTRY_ADMIN, GREGISTRY_OPERATOR | Пилот starter (уже схема B); сохраняет только локальный выход, пока не потребуется единый выход (single logout) | S3 |
| gdocs | SaaS | gdocs (профиль oidc) / gdocs-web / A | gdocs-web, gdocs-api, gdocs-service | GDOCS_ADMIN, GDOCS_EDITOR, GDOCS_CITITOR | Как для interdictii; realm gdocs выводится из эксплуатации | S4 |
| saas_drumuri | SaaS | локальный JWT + MPass SAML в приложении / env фронтенда ошибочно указывает на glog-web / C | сотрудники: drumuri-web в gstack; граждане: drumuri-public в cetatean | DRUMURI_ADMIN, DRUMURI_OPERATOR, DRUMURI_INSPECTOR | MPass переносится из приложения в брокер cetatean; немедленно исправить env фронтенда (неверный client id); отдельный хост routes.tech.esempla.systems → redirect URI | S4 |
| saas_crm | SaaS | только проект / D | crm-gateway (confidential), по одному сервисному клиенту на микросервис (crm-core, crm-clienti, crm-comercial, crm-interactiuni, crm-suport, crm-contracte, crm-operational, crm-taskuri, crm-strategie, crm-integrare, crm-cautare, crm-ai), crm-integration-1c | CRM_* (из отчёта CRM 02) | CAP-GSSO-01 — блокер для CRM F0; token exchange в gDocFlow/gTenders (CAP-GSSO-07) | S1–S3 |
| saas_gdocflow | SaaS | проект / D | gdocflow-gateway, сервисные клиенты | GDOCFLOW_* | Цель и источник token exchange | S3 |
| saas_gtenders | SaaS | проект / D | gtenders-gateway, сервисные клиенты | GTENDERS_* | Token exchange | S3 |
| saas_gnotify | SaaS/PaaS | realm gnotify (не создан) / OIDC отключён / A; использует учётные данные клиента glog-ingest | gnotify-web, gnotify-service | GNOTIFY_ADMIN, GNOTIFY_OPERATOR; scope notify:send для вызывающих сторон | Включить через starter; GSSO использует GNotify через scope gnotify-service | S4 |
| glog | PaaS | interdictii / glog-web PKCE (жёстко заданный mapper tenant=demo) + сервис glog-ingest / B (профиль dualauth) | glog-web, glog-api, ingest-клиенты для каждой вызывающей стороны (<app>-glog) | GLOG_ADMIN, GLOG_AUDITOR; client scope audit:write, audit:read | Заменить сопоставление роль→scope в GlogJwtAuthConverter на starter + явные scope; claim tenant из mapper GSSO; сам GSSO становится ingest-клиентом | S3 |
| paas_gstorage | PaaS | realm gstorage / gstorage-web, gstorage-ingest; альтернатива — API-ключ | gstorage-web, gstorage-api, сервисные клиенты <app>-gstorage | GSTORAGE_ADMIN, GSTORAGE_ARCHIVIST; scope `storage:read | write | admin` |
| paas_gflow | PaaS | проект / D | gflow-gateway, gflow-server, сервисные principal для каждого приложения (<app>-gflow) | GFLOW_ADMIN; группы-кандидаты = роли потребителей | Использует GET /api/v1/app/roluri/{cod}/utilizatori (GSSO-FR-103); без token exchange | S3 |
| gportal / GDS | PaaS | без аутентификации (заглушки) | gportal-web (PKCE) | ROLE_USER | Использует @gstack/gsso-angular | S4 |
| platform (docs/RAG) | внутреннее | interdictii / gstack-platform PKCE; Python PyJWT + JWKS, требует ROLE_ADMIN | gstack-platform | PLATFORM_ADMIN | Изменить проверку роли с ROLE_ADMIN на PLATFORM_ADMIN | S4 |
| gsso_mob (GovSign) | мобильное | realm gstack / gstack-govsign-app public PKCE, redirect com.govsign.app://callback; подтверждение по QR для каждого сайта | govsign-app (public PKCE) в gstack и cetatean | ROLE_USER | Удалить KEYCLOAK_CLIENT_SECRET из конфигурации публичного клиента; вход по QR как аутентификатор Keycloak (GSSO-FR-068) | S5 |
Сайты whitelabel (ultra-b2b, ultra-ecom, bts-licitatii, bts-integrare, esempla-govstec, esempla-sistembancar) | сайты | realm ultra / gstack-ultra (не подтверждено) | по одному realm tenant-<code> на сайт, из шаблона | для каждого сайта | Создаются через GSSO из шаблона; endpoint подтверждения по QR сохраняется до GSSO-FR-068 | S4 |
| qa_platform | инструмент | нет (только целевые учётные данные) | сервисный клиент qa-runner для каждого окружения | QA_RUNNER | Тестовые пользователи создаются через API GSSO в непродуктивных realm | S5 |
2.1 Порядок миграции приложения со схемой A
Section titled “2.1 Порядок миграции приложения со схемой A”- Зарегистрировать платформу, клиентов и роли в GSSO или принять их из
interdictii(GSSO-FR-007). - Создать предоставления доступа, воспроизводящие текущих обладателей ролей (
AtribuireAccesс источникомADOPTAT). - Добавить
gsso-spring-boot-starter. На переходный период задатьgsso.issuer-uri,gsso.audienceиgsso.role-aliases(например,ROLE_ADMIN: INTERDICTII_ADMIN). - Удалить обработчик выпуска собственных token, локальный секрет JWT, локальный вход по паролю и маршрут
/oidc-callback. Для SPA монолита перейти на@gstack/gsso-angularв режиме BFF или PKCE. - Прогнать E2E-тесты приложения на compose-стеке GSSO, затем развернуть за feature flag, который на один релиз сохраняет старый клиент параллельно.
- Удалить
role-aliasesи устаревшее сопоставлениеROLE_ADMIN, затем удалить старый клиент.
3. Контракт API (сводка)
Section titled “3. Контракт API (сводка)”Базовый путь: https://gsso.gstack.esempla.systems/api/v1 (через gsso-gateway).
Соглашения:
- JSON, ошибки по RFC 7807;
Idempotency-Keyв каждом POST;- постраничная выдача через
page,size,sortиX-Total-Countв ответе; - имена полей предметной области — на румынском.
3.1 Зона app — приложения-потребители (client credentials, scope gsso:app)
Section titled “3.1 Зона app — приложения-потребители (client credentials, scope gsso:app)”| Метод | Путь | Назначение | Треб. |
|---|---|---|---|
GET | /app/platforma | собственная платформа с клиентами и ролями | FR-098 |
PUT | /app/platforma | самостоятельная регистрация / обновление собственной платформы, клиентов, ролей (только для помеченных клиентов) | FR-099 |
GET | /app/utilizatori?sub=&username=&email=&idnp= | поиск (IDNP — только при наличии разрешения) | FR-100 |
GET | /app/utilizatori/{sub} | статус (enabled, MFA, последний вход), имя, e-mail, организационная единица, locale | FR-101 |
GET | /app/utilizatori/{sub}/roluri | эффективные роли вызывающей платформы с областями действия и сроком действия | FR-101 |
DELETE | /app/utilizatori/{sub}/sesiuni | завершить сессии пользователя | FR-102 |
GET | /app/roluri/{cod}/utilizatori | пользователи, имеющие роль вызывающей платформы (постранично) | FR-103 |
POST | /app/atribuiri | запросить предоставление доступа пользователю на вызывающей платформе ({sub, rol, orgUnit?, validPana?, motiv}) → SOLICITATA | FR-051 |
GET | /app/atribuiri/{id} | статус предоставления доступа | FR-051 |
3.2 Зона admin — консоль (пользовательская сессия через gsso-gateway)
Section titled “3.2 Зона admin — консоль (пользовательская сессия через gsso-gateway)”Ниже перечислены ресурсы; полная спецификация OpenAPI — по адресу /api/v1/openapi.json:
/admin/realms,/admin/realms/{realm}/adoptie,/admin/realms/{realm}/reconciliere/admin/platforme,/admin/platforme/{cod}/clienti,/admin/platforme/{cod}/roluri/admin/clienti/{id}/secret(ротация)/admin/realms/{realm}/utilizatori,…/{sub},…/{sub}/credentiale,…/{sub}/sesiuni,…/{sub}/actiuni(обязательные действия),…/{sub}/deblocare/admin/atribuiri(с/{id}/aprobare,/{id}/respingere,/{id}/revocare)/admin/unitati/admin/realms/{realm}/politica-autentificare/admin/sincronizare/joburi(с/{id}/reincercare,/{id}/acceptare-drift)/admin/evenimente,/admin/evenimente/verificare-lant/admin/tablou(агрегаты для панели мониторинга)/admin/rapoarte/acces
3.3 Эксплуатационные endpoint
Section titled “3.3 Эксплуатационные endpoint”/health/live, /health/ready, /metrics, /info, /api/v1/openapi.json.
3.4 Контракт token (realm gstack)
Section titled “3.4 Контракт token (realm gstack)”| Claim | Содержимое | Примечания |
|---|---|---|
iss | https://sso.gstack.esempla.systems/realms/gstack | |
sub | UUID, стабильный | GSSO-FR-032 |
aud | audience целевой платформы (одна или несколько) | audience mapper для каждой платформы |
azp | client id | |
preferred_username, name, email | профиль | |
roles | плоский массив эффективных ролей realm (с префиксом платформы) + ROLE_USER | фильтруется по audience с помощью scope gsso-roles-filtered |
roles_scoped | { "<ROLE>": ["<org_unit>", …] } только для предоставлений доступа с областью действия | GSSO-FR-055 |
org_unit, org_unit_path | организационная единица пользователя | GSSO-FR-054 |
locale | ro / ru / en | |
idnp | только с опциональным client scope idnp | Q-GSSO-13 |
acr | 1 / 2 / 3 | GSSO-FR-070 |
act | { "sub": "<calling client>" } в token, полученных через exchange | GSSO-ADR-012 |
tenant | код realm для realm tenant-* (заменяет жёстко заданный mapper glog) |
Срок жизни access token: 5 мин (2 мин для чувствительных клиентов). Подпись: RS256, ключи публикуются по адресу /protocol/openid-connect/certs.
4. Использование starter
Section titled “4. Использование starter”<dependency> <groupId>systems.esempla.gsso</groupId> <artifactId>gsso-spring-boot-starter</artifactId></dependency># application.yml of a consuming servicegsso: issuer-uri: https://sso.gstack.esempla.systems/realms/gstack audience: crm role-aliases: # transition only (report 03 §2.1) ROLE_ADMIN: CRM_ADMIN client: # optional: outgoing calls id: crm-comercial secret: ${GSSO_CLIENT_SECRET} revocation: kafka-topic: gsso.access-revoked.v1 # deny-list, GSSO-ADR-013@PreAuthorize("hasAuthority('CRM_ADMIN')")public void delete(...) { ... }
GssoPrincipal p = GssoPrincipal.current(); // sub, username, orgUnit, localeRestClient docs = gsso.exchangeClient("gdocflow"); // token exchange (on-behalf-of)RestClient glog = gsso.serviceClient("glog"); // client credentialsAngular:
provideGsso({ mode: 'bff', loginUrl: '/oauth2/authorization/oidc', logoutUrl: '/api/logout' })// or { mode: 'pkce', issuer, clientId }// route guard: canActivate: [gssoRole('CRM_ADMIN')]// template: <button *gssoHasRole="'CRM_ADMIN'">…</button>5. Контракт событий
Section titled “5. Контракт событий”Все события — CloudEvents в бинарном режиме в Kafka, с source = gsso и subject = <realm>/<sub>.
| Topic | Производитель | Тип | Полезная нагрузка (data) | Потребители |
|---|---|---|---|---|
gsso.kc-events.v1 | расширение Keycloak gsso-kafka | md.gstack.gsso.kc.user.<TYPE> / md.gstack.gsso.kc.admin.<OPERATION> | поля события Keycloak (type, realm, client, user, ip, error, details / resource type, path, representation без секретов) | только gsso |
gsso.access-revoked.v1 | gsso | md.gstack.gsso.access.revoked | {sub, realm, roluri[], platforme[], notBefore, motiv} | starter в каждом приложении |
gsso.user-changed.v1 | gsso | md.gstack.gsso.user.changed | {sub, realm, campuri[], enabled} | приложения, кэширующие данные пользователей |
gsso.grant.v1 | gsso | md.gstack.gsso.grant.<STARE> | {id, sub, rol, platforma, orgUnit, validDe, validPana, stare} | приложения, зеркалирующие права (например, gFlow) |
Ключ = <realm>:<sub>. Доставка — at-least-once, поэтому потребители должны быть идемпотентны по id. У каждой группы потребителей есть DLQ-topic <topic>.dlq.<group>.
6. Соглашения об именовании
Section titled “6. Соглашения об именовании”| Объект | Соглашение | Пример |
|---|---|---|
| Код платформы | строчные буквы, [a-z][a-z0-9-]* | crm, interdictii, glog |
| Роль | <PLATFORM_UPPER>_<ROLE> (дефисы заменяются на _) | CRM_ADMIN, INTERDICTII_EMITENT |
| Клиент SPA | <platform>-web (PKCE) или <platform>-gateway (BFF) | glog-web, crm-gateway |
| Клиент бэкенда | <platform>-api (bearer-only) | cancelarie-api |
| Сервисный клиент | <service> или <caller>-<callee> | crm-comercial, gnotify-glog |
| Client scope (сервисный) | <platform>:<verb> или <object>:<verb> | audit:write, storage:read |
| Realm арендатора | tenant-<code> | tenant-ultra-b2b |
| Audience | код платформы | crm |
7. Квоты и уровень обслуживания
Section titled “7. Квоты и уровень обслуживания”| Параметр | Значение по умолчанию |
|---|---|
Ограничение частоты запросов API app | 50 запросов/с на клиента, пик 100 |
| Самостоятельная регистрация | не более 20 клиентов и 200 ролей на платформу |
| Запросы на предоставление доступа от приложения | 1 000 в сутки на платформу |
| Предлагаемая доступность | Keycloak 99,9 %, консоль/API 99,5 % (NFR-AVL) |
| Поддержка | команда платформы, в рабочее время; недоступность Keycloak = P1 |
| Версионирование | api/v1 стабилен; несовместимое изменение = v2 с параллельной работой в течение 6 месяцев |
8. Чек-лист подключения нового приложения
Section titled “8. Чек-лист подключения нового приложения”- Назначен владелец платформы; выбран код платформы (§6).
- Роли перечислены с описаниями на RO/RU/EN; чувствительные роли помечены; составные роли определены.
- Клиенты объявлены: тип доступа, redirect URI (точные), web origins, URL back-channel logout.
- Сервисные клиенты объявлены для каждого вызывающего сервиса, со scope; при необходимости перечислены цели token exchange.
- Платформа зарегистрирована в GSSO (через консоль или
PUT /api/v1/app/platforma), её статус синхронизации — in sync. - Приложение использует
gsso-spring-boot-starter(и@gstack/gsso-angular). Локальных паролей и самостоятельно выпускаемых token нет. - Проверка audience включена. Авторизация использует только роли платформы.
- Приложение подписано на
gsso.access-revoked.v1(через starter). - Первоначальные предоставления доступа запрошены и одобрены; тестовые пользователи существуют в непродуктивных realm.
- CSP разрешает
sso.gstack.esempla.systemsвconnect-srcиform-action. - E2E-тест входа проходит на compose-стеке GSSO. Проверка матрицы авторизации (
/gtestgen) проходит. - Приложение добавлено в §2 настоящего отчёта и в отчёт о доступе.