diff --git a/package.json b/package.json
index 149e113..3b4a606 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ipwhitelist",
- "version": "0.5.157",
+ "version": "0.5.158",
"description": "IP WhiteList microservice for cloud provider",
"main": "server.js",
"scripts": {
diff --git a/v2/server.js b/v2/server.js
index c261f12..3ff792f 100644
--- a/v2/server.js
+++ b/v2/server.js
@@ -145,25 +145,42 @@ function createV2Router() {
const { createExportRouter } = require('./src/export');
router.use('/export', createExportRouter());
- // ── GET /v2/logout — редирект на основной выход ─────────────────────
+ // ── GET /v2/logout — выход только из whitelist (без KC SSO) ─────────
router.get('/logout', (req, res) => {
const ua = (req.headers['user-agent'] || '').toLowerCase();
const isBrowser = ua.includes('mozilla') || ua.includes('chrome') || ua.includes('safari');
- if (isBrowser) {
- res.set('Content-Type', 'text/html; charset=utf-8');
- return res.send('
Выход'
- + ''
- + 'Выход из приложения
'
- + 'Выход завершит сессию во всех сервисах Nubes (Keycloak SSO).
Вы уверены?
'
- + 'Да, выйти'
- + 'Отмена'
- + '');
+ if (!isBrowser) {
+ req.session.destroy(() => res.redirect('/v2/login'));
+ return;
}
- res.redirect('/logout');
+
+ if (req.query.confirm === 'yes') {
+ req.session.destroy(() => {
+ res.set('Content-Type', 'text/html; charset=utf-8');
+ res.send('Выход'
+ + ''
+ + 'Вы вышли из сервиса
'
+ + 'Сессия whitelist завершена.
Сессия в других сервисах Nubes сохранена.
'
+ + 'Войти снова'
+ + '');
+ });
+ return;
+ }
+
+ res.set('Content-Type', 'text/html; charset=utf-8');
+ res.send('Выход'
+ + ''
+ + 'Выход из сервиса
'
+ + 'Вы будете выведены только из whitelist.
Сессия в других сервисах Nubes сохранится.
'
+ + 'Выйти'
+ + 'Отмена'
+ + '');
});
return router;
diff --git a/v2/src/router/index.js b/v2/src/router/index.js
index 8201ea2..6df03ba 100644
--- a/v2/src/router/index.js
+++ b/v2/src/router/index.js
@@ -1,18 +1,27 @@
const https = require('https');
const config = require('../config');
-function resolveContext(req, res, next) {
+/**
+ * Express middleware — извлекает контекст из сессии.
+ * При 401 от IAM — чистит сессию и редиректит на логин (SSO).
+ */
+async function resolveContext(req, res, next) {
const u = req.session && req.session.user;
-
- // Нет сессии — нет доступа
if (!u) return res.redirect('/v2/login');
- // ── Проверка имперсонации через IAM ──────────────────────────────
- // Если есть токен — запрашиваем свежие данные, чтобы обнаружить имперсонацию
- // которая могла начаться после логина (ЛК сессия отдельно от whitelist).
const token = req.session && req.session.token;
if (token) {
- checkImpersonation(token, req, u).catch(() => { /* fallback — тихо */ });
+ try {
+ await checkImpersonation(token, req, u);
+ } catch (e) {
+ const msg = (e.message || '');
+ // 401 — токен протух, чистим сессию → SSO даст свежий
+ if (msg.startsWith('401')) {
+ req.session.destroy(() => res.redirect('/v2/login'));
+ return;
+ }
+ // Другие ошибки IAM — игнорируем, используем старые данные
+ }
}
applyContext(req, u);
@@ -21,6 +30,7 @@ function resolveContext(req, res, next) {
/**
* Запрашивает IAM и обновляет сессию если имперсонация изменилась.
+ * Бросает ошибку при 401 — вызывающий обработает.
*/
async function checkImpersonation(token, req, u) {
const url = config.iamApiBase + '/auth/user';