feat: Authorization Code Flow (KK) + session middleware + dev-login
- src/auth.js: OIDC mode (KC_CLIENT_ID/KC_CLIENT_SECRET), session-based middleware, legacy jwt-cookie migration, httpGet/httpPost без внешних зав. - src/routes/auth.js: GET /callback (OIDC), GET+POST /dev-login (backdoor), session-based login/logout для обоих режимов - server.js: express-session (8h, httpOnly, sameSite lax), trust proxy в prod - views/dev-login.ejs: форма с пресетами MOCK_USERS + произвольные поля - views/login.ejs: ссылка на /dev-login если devLoginEnabled - tests: +5 тестов (session middleware), 50 PASS / 0 FAIL Env-переменные: KC_CLIENT_ID, KC_CLIENT_SECRET, KC_BASE_URL, APP_URL — OIDC режим SESSION_SECRET — секрет сессии DEV_MODE=true — /dev-login без пароля DEV_SECRET=xyz — /dev-login с ?key=xyz
This commit is contained in:
+31
-18
@@ -127,40 +127,53 @@ test('overlap exact match', overlaps('192.168.0.0/24', '192.168.0.0/24'), true);
|
||||
test('no overlap public', overlaps('8.8.8.0/24', '9.9.9.0/24'), false);
|
||||
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
// 4. src/auth.js — DEV_MODE (без JWT, без БД)
|
||||
// 4. src/auth.js — session middleware (без JWT, без БД)
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
section('auth.js (DEV_MODE)');
|
||||
section('auth.js (session middleware)');
|
||||
|
||||
process.env.DEV_MODE = 'true';
|
||||
process.env.DEV_ADMIN = 'true';
|
||||
process.env.ADMIN_CLIENT_ID = 'WZ01112';
|
||||
|
||||
const { initAuth, requireAdmin } = require('../src/auth');
|
||||
|
||||
try {
|
||||
const auth = initAuth();
|
||||
test('middleware is function', typeof auth.middleware, 'function');
|
||||
test('jwksHandler present in DEV_MODE', typeof auth.jwksHandler, 'function');
|
||||
test('middleware is function', typeof auth.middleware, 'function');
|
||||
test('jwksHandler present (mock mode)', typeof auth.jwksHandler, 'function');
|
||||
test('devLoginEnabled when DEV_MODE', auth.devLoginEnabled, true);
|
||||
test('isOidc false (no KC creds)', auth.isOidc, false);
|
||||
|
||||
// DEV_MODE: middleware выставляет req.user без JWT
|
||||
const req = { headers: {}, cookies: {} };
|
||||
const res = { redirect: () => {} };
|
||||
// ── Пользователь из session ──
|
||||
const mockUser = { clientId: 'WZ01325', companyId: 'test-uuid', companyName: 'Test', email: 'test@test.local', isAdmin: false };
|
||||
const reqSess = { headers: {}, cookies: {}, session: { user: mockUser } };
|
||||
let nextCalled = false;
|
||||
auth.middleware(req, res, () => { nextCalled = true; });
|
||||
test('DEV_MODE: next() called', nextCalled, true);
|
||||
test('DEV_MODE: req.user set', !!req.user, true);
|
||||
test('DEV_MODE: req.user.isAdmin = true (DEV_ADMIN=true)', req.user.isAdmin, true);
|
||||
auth.middleware(reqSess, {}, () => { nextCalled = true; });
|
||||
test('session user: next() called', nextCalled, true);
|
||||
test('session user: req.user set', !!reqSess.user, true);
|
||||
test('session user: clientId match', reqSess.user.clientId, 'WZ01325');
|
||||
|
||||
// requireAdmin: пропускает admin
|
||||
const reqAdmin = { user: { isAdmin: true } };
|
||||
// ── Admin user из session ──
|
||||
const adminUser = { clientId: 'WZ01112', isAdmin: true };
|
||||
const reqAdmin = { headers: {}, cookies: {}, session: { user: adminUser } };
|
||||
let adminNext = false;
|
||||
auth.middleware(reqAdmin, {}, () => { adminNext = true; });
|
||||
test('admin session: next() called', adminNext, true);
|
||||
test('admin session: isAdmin=true', reqAdmin.user.isAdmin, true);
|
||||
|
||||
// ── Нет аутентификации → редирект ──
|
||||
let redirectUrl = null;
|
||||
const reqNone = { headers: {}, cookies: {}, session: {}, method: 'GET', originalUrl: '/some-page' };
|
||||
auth.middleware(reqNone, { redirect: (url) => { redirectUrl = url; } }, () => {});
|
||||
test('no auth: redirected to /login', redirectUrl !== null && redirectUrl.startsWith('/login'), true);
|
||||
|
||||
// ── requireAdmin: admin проходит ──
|
||||
let adminPassed = false;
|
||||
requireAdmin(reqAdmin, {}, () => { adminPassed = true; });
|
||||
requireAdmin({ user: { isAdmin: true } }, {}, () => { adminPassed = true; });
|
||||
test('requireAdmin: admin passes', adminPassed, true);
|
||||
|
||||
// requireAdmin: блокирует не-admin
|
||||
const reqUser = { user: { isAdmin: false } };
|
||||
// ── requireAdmin: не-admin блокируется ──
|
||||
let blockedStatus = null;
|
||||
requireAdmin(reqUser, {
|
||||
requireAdmin({ user: { isAdmin: false } }, {
|
||||
status: (s) => { blockedStatus = s; return { send: () => {} }; },
|
||||
}, () => {});
|
||||
test('requireAdmin: non-admin blocked (403)', blockedStatus, 403);
|
||||
|
||||
Reference in New Issue
Block a user