diff --git a/package.json b/package.json index 73f86eb..1e28012 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipwhitelist", - "version": "0.5.73", + "version": "0.5.74", "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 index d55f656..64b9050 100644 --- a/v2/history/2026-06-12.md +++ b/v2/history/2026-06-12.md @@ -1,119 +1,77 @@ -# V2 — история 2026-06-12 +# V2 — история 2026-06-12 (финал) -## Цель -Перепроектирование ipwhitelist-app. Начали с модуля аутентификации: Keycloak OIDC → IAM API → готовый sessionUser. +## V2 — это тестовый стенд для модулей -## Архитектура +Код в `v2/` — НЕ production. Это полигон для отладки модулей. +Каждый модуль тестируется изолированно, затем будет интегрирован в основной код. -### Принцип -Один вызов `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`) - -## Созданные файлы +## Текущее состояние (0.5.73) ``` v2/ -├── server.js # createV2Router() — монтируется в server.js как /v2 +├── server.js # createV2Router() → /v2/login, /v2/iam, /v2/logout ├── src/ -│ ├── config/index.js # приоритет: V2_KC_* → KC_* → умолчания -│ └── auth/index.js # login(), fetchIamUser(), exchangeCode(), buildAuthUrl(), generateState() +│ ├── auth/index.js # fetchIamUser(), login(), exchangeCode(), buildAuthUrl() +│ ├── config/index.js # iamUrl, appUrl, version (без KC — пока не нужен) +│ ├── crud/index.js # createCrudRouter() — НЕ монтирован (будет позже) +│ ├── db/ +│ │ ├── index.js # pg pool +│ │ ├── queries.js # CRUD SQL +│ │ └── schema.js # ensureSchema(pool) — автосоздание v2_* таблиц +│ └── validators/index.js # CIDR validate, overlaps, BLOCKED_RANGES └── history/ - └── 2026-06-12.md # этот файл + └── 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` | +1. `/v2/login` → редирект на `/login?returnTo=/v2/iam` +2. Основной OIDC: production-KC → `/callback` → сессия → редирект на `/v2/iam` +3. `/v2/iam` → показывает IAM-данные из `req.session.user` -## v2/src/config/index.js — приоритет +V2 НЕ делает свой OIDC. Использует готовую сессию основного приложения. +Никаких своих KC-настроек. Никакого `/v2/callback`. -``` -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 -``` +## Модуль auth/index.js — готов, но не используется -## v2/server.js — роуты +Функции готовы к production: +- `buildAuthUrl(config)` — URL редиректа на KC +- `exchangeCode(code, config)` — обмен code → токен +- `fetchIamUser(token, iamUrl)` — IAM → профиль +- `generateState()` — CSRF +- `login(code, oidcConfig, iamUrl)` — оркестратор -| Путь | Что | -|------|-----| -| `GET /v2/` | главная: IAM-данные или редирект на /v2/login | -| `GET /v2/login` | → Keycloak | -| `GET /v2/callback` | Keycloak → code → login() → сессия → /v2/ | -| `GET /v2/logout` | сброс v2_ ключей сессии | +Не тестировались: нужен `/v2/callback` в redirect URIs production-KC. -Сессионные ключи с префиксом `v2_`: `v2_user`, `v2_token`, `v2_idToken`, `v2_oidcState`. -Не пересекаются с основным приложением. +## Модуль crud/ — готов, не монтирован -## server.js — изменения +Функции: +- `createCrudRouter()` — роутер с выбором компании (всегда список, даже если одна) +- CRUD через `db/queries.js` -Добавлено перед UI-роутером: -```js -const { createV2Router } = require('./v2/server'); -app.use('/v2', createV2Router()); -``` +Таблицы: v2_companies, v2_entries, v2_audit (автосоздание через schema.js). -Порядок: `/healthz` → OIDC → `/api/v1/*` → `/v2/*` → UI (`/*`) +## Модуль db/ — готов -## Что сделано на VM (italo.kube5s.ru) +- `db/index.js` — pg pool +- `db/queries.js` — getOrCreateCompany, listEntries, createEntry, updateEntry, deleteEntry, getAudit, ... +- `db/schema.js` — ensureSchema(pool) — CREATE TABLE IF NOT EXISTS -### 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 +## Модуль validators/ — готов -### .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 +CIDR validate, overlaps, cidrToRange, aggregateCIDRs, BLOCKED_RANGES. ## Что дальше -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) +1. fio в fetchIamUser — возвращать строку (сейчас объект) +2. Добавить `/v2/callback` в redirect URIs production-KC +3. Протестировать auth/login() с production-KC +4. Подключить crud модуль +5. Админка, экспорт + +## Ключевые решения + +- V2 НЕ трогает основной код (server.js — только app.use('/v2', ...)) +- Каждый модуль — отдельная папка в src/ +- env-переменные — через process.env, без .env/dotenv +- Умолчания — хардкод, переопределяются через V2_* env diff --git a/v2/src/auth/index.js b/v2/src/auth/index.js index 3718f05..f40f7dc 100644 --- a/v2/src/auth/index.js +++ b/v2/src/auth/index.js @@ -184,7 +184,7 @@ async function fetchIamUser(token, iamUrl) { companyId: ui.companyId || '', // внутр. ID IAM (не W-формат) companyName: ui.company || activeProfile.company_name || '', isAdmin: !!ui.isAdmin, - fio: ui.fio || null, + fio: (ui.fio && ui.fio.fullName) || ui.fio || null, // ── из profiles ── profiles, // все компании (массив) diff --git a/v2/src/config/index.js b/v2/src/config/index.js index be5f108..30d90ab 100644 --- a/v2/src/config/index.js +++ b/v2/src/config/index.js @@ -6,7 +6,7 @@ // ═══════════════════════════════════════════════════════════════════════════════ module.exports = { - version: '0.5.73', + version: '0.5.74', iamUrl: process.env.V2_IAM_API_URL || 'https://auth-api.ngcloud.ru', appUrl: process.env.V2_APP_URL || 'https://whitelist.nodejsk8s.services.ngcloud.ru', };