From ac13330fdb298d9788b158fe0f8fde1ff50de0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Fri, 12 Jun 2026 15:58:17 +0400 Subject: [PATCH] =?UTF-8?q?v2:=20=D0=B8=D0=B7=D0=BE=D0=BB=D1=8F=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=E2=80=94=20=D1=81=D0=B2=D0=BE=D0=B8=20V2=5F*=20?= =?UTF-8?q?env,=20v2/.env,=20=D0=BD=D0=B5=20=D1=82=D1=80=D0=BE=D0=B3=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D1=8B=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- v2/history/2026-06-12.md | 119 +++++++++++++++++++++++++++++++++++++++ v2/src/config/index.js | 36 +++--------- 3 files changed, 127 insertions(+), 30 deletions(-) create mode 100644 v2/history/2026-06-12.md diff --git a/package.json b/package.json index 15a84d6..932fda7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipwhitelist", - "version": "0.5.58", + "version": "0.5.59", "description": "IP WhiteList microservice for cloud provider", "main": "server.js", "scripts": { diff --git a/v2/history/2026-06-12.md b/v2/history/2026-06-12.md new file mode 100644 index 0000000..d55f656 --- /dev/null +++ b/v2/history/2026-06-12.md @@ -0,0 +1,119 @@ +# V2 — история 2026-06-12 + +## Цель +Перепроектирование ipwhitelist-app. Начали с модуля аутентификации: Keycloak OIDC → IAM API → готовый sessionUser. + +## Архитектура + +### Принцип +Один вызов `login()` при логине. После этого ни Keycloak, ни IAM не нужны. +Переключение компаний — только в сессии (не через IAM switchProfile). + +### Ответ IAM (`/api/v1/auth/user`) +См. `Files/architect.md` — задокументированы все поля. + +### Два стенда +| Стенд | URL | Keycloak | IAM | +|-------|-----|----------|-----| +| Production | `whitelist.nodejsk8s.services.ngcloud.ru` | prod-KC | ✅ | +| VM (тест) | `italo.kube5s.ru` | локальный KC на :8080 | ❌ | + +### clientId vs companyId +- `clientId` = WZ01112 (W-номер) — идентификатор компании в БД +- `companyId` = внутренний ID IAM, не W-формат, почти не используется +- `allClientIds` = массив всех W-номеров (собираем из `profiles[].client_id`) + +## Созданные файлы + +``` +v2/ +├── server.js # createV2Router() — монтируется в server.js как /v2 +├── src/ +│ ├── config/index.js # приоритет: V2_KC_* → KC_* → умолчания +│ └── auth/index.js # login(), fetchIamUser(), exchangeCode(), buildAuthUrl(), generateState() +└── history/ + └── 2026-06-12.md # этот файл +``` + +## v2/src/auth/index.js — функции + +| Функция | Что | Вызывается | +|---------|-----|-----------| +| `buildAuthUrl(config)` | URL редиректа на Keycloak | `GET /v2/login` | +| `exchangeCode(code, config)` | code → access_token | внутри `login()` | +| `fetchIamUser(token, iamUrl)` | IAM → профиль | внутри `login()` | +| `generateState()` | CSRF-токен | `GET /v2/login` | +| `login(code, oidcConfig, iamUrl)` | оркестратор: всё сразу | `GET /v2/callback` | + +## v2/src/config/index.js — приоритет + +``` +V2_KC_BASE_URL → KC_BASE_URL → https://italo.kube5s.ru/realms/ipwhitelist +V2_KC_CLIENT_ID → KC_CLIENT_ID → ipwhitelist +V2_KC_CLIENT_SECRET → KC_CLIENT_SECRET → '' +V2_APP_URL → APP_URL → https://italo.kube5s.ru +V2_IAM_API_URL → IAM_API_URL → https://auth-api-dev.ngcloud.ru +``` + +## v2/server.js — роуты + +| Путь | Что | +|------|-----| +| `GET /v2/` | главная: IAM-данные или редирект на /v2/login | +| `GET /v2/login` | → Keycloak | +| `GET /v2/callback` | Keycloak → code → login() → сессия → /v2/ | +| `GET /v2/logout` | сброс v2_ ключей сессии | + +Сессионные ключи с префиксом `v2_`: `v2_user`, `v2_token`, `v2_idToken`, `v2_oidcState`. +Не пересекаются с основным приложением. + +## server.js — изменения + +Добавлено перед UI-роутером: +```js +const { createV2Router } = require('./v2/server'); +app.use('/v2', createV2Router()); +``` + +Порядок: `/healthz` → OIDC → `/api/v1/*` → `/v2/*` → UI (`/*`) + +## Что сделано на VM (italo.kube5s.ru) + +### Keycloak +- Realm `ipwhitelist`, frontendUrl=`https://italo.kube5s.ru` +- Client `ipwhitelist`, redirectUris=`['https://italo.kube5s.ru/v2/callback']` +- Пользователь: `test` / `test` +- Client secret: `40bpIZvumq6jttIB5QtTLcl9AJvAHxlw` +- Доступ через nginx: `/realms/*` → Keycloak:8080 + +### .env на ВМ +Добавлено: `V2_KC_CLIENT_SECRET=40bpIZvumq6jttIB5QtTLcl9AJvAHxlw` + +### Деплой +```bash +rsync -az -e "ssh ..." /home/naeel/ipwhitelist-app/v2 naeel@5.172.178.213:~/ipwhitelist/ +ssh ... 'pm2 restart ipwhitelist' +``` + +## Git +- Версия: `0.5.57` → `0.5.58` +- Коммит: `5c09844` — v2: модуль аутентификации + роутер /v2 +- Запушено в `master` на gitea.services.ngcloud.ru + +## Ошибки в процессе + +1. `rsync v2/` с trailing slash → содержимое v2/ скопировалось в `~/ipwhitelist/`, v2/server.js перезаписал основной server.js + - Fix: rsync без trailing slash (`rsync ... v2`) +2. `sed` заменил оба вхождения `italo.kube5s.ru` в конфиге (kcBaseUrl и appUrl) + - Fix: переписал файл полностью +3. `kcBaseUrl` без `/realms/ipwhitelist` → редирект на неверный URL Keycloak + - Fix: `https://italo.kube5s.ru/realms/ipwhitelist` +4. На ВМ старый `ui/index.js` с багом (дубликат catch) → краш приложения + - Fix: rsync --force ui/index.js + +## Что дальше + +1. Дождаться редеплоя на production (Nubes UI) +2. Проверить `https://whitelist.nodejsk8s.services.ngcloud.ru/v2/login` +3. Если prod-KC не разрешает `/v2/callback` → добавить в VM-шный KC и задать V2_KC_BASE_URL на production +4. Реализовать IAM-фолбэк (если IAM недоступен → JWT claims) diff --git a/v2/src/config/index.js b/v2/src/config/index.js index 4167f90..0ad2dc2 100644 --- a/v2/src/config/index.js +++ b/v2/src/config/index.js @@ -1,35 +1,13 @@ // ═══════════════════════════════════════════════════════════════════════════════ -// Конфигурация V2 -// -// Приоритет: V2_* → основные → умолчания (локальный KC на ВМ) +// Конфигурация V2 — свои переменные (V2_*), не трогает основные // ═══════════════════════════════════════════════════════════════════════════════ -require('dotenv').config({ path: require('path').join(__dirname, '..', '..', '..', '.env') }); +require('dotenv').config({ path: require('path').join(__dirname, '..', '..', '.env') }); module.exports = { - // Keycloak OIDC - kcBaseUrl: process.env.V2_KC_BASE_URL - || process.env.KC_BASE_URL - || 'https://italo.kube5s.ru/realms/ipwhitelist', - - kcClientId: process.env.V2_KC_CLIENT_ID - || process.env.KC_CLIENT_ID - || 'ipwhitelist', - - kcClientSecret: process.env.V2_KC_CLIENT_SECRET - || process.env.KC_CLIENT_SECRET - || '', - - // IAM API - iamUrl: process.env.V2_IAM_API_URL - || process.env.IAM_API_URL - || 'https://auth-api-dev.ngcloud.ru', - - // Наше приложение (НЕ Keycloak!) - appUrl: process.env.V2_APP_URL - || process.env.APP_URL - || 'https://italo.kube5s.ru', - - // Админ - adminClientId: process.env.ADMIN_CLIENT_ID || 'WZ01112', + kcBaseUrl: process.env.V2_KC_BASE_URL || 'https://italo.kube5s.ru/realms/ipwhitelist', + kcClientId: process.env.V2_KC_CLIENT_ID || 'ipwhitelist', + kcClientSecret: process.env.V2_KC_CLIENT_SECRET || '', + iamUrl: process.env.V2_IAM_API_URL || 'https://auth-api-dev.ngcloud.ru', + appUrl: process.env.V2_APP_URL || 'https://italo.kube5s.ru', };