Files
Remote-Control-Center/guacamole_test_11_26/docs/TOKEN_FIX_SUMMARY.md
2025-11-25 09:58:37 +03:00

9.9 KiB
Executable File
Raw Blame History

🔧 Token Issue Fix - Восстановление подключений

Проблема

При восстановлении подключений после logout/login возникала ошибка 403 Forbidden при переключении между подключениями.

Причина

Middleware получал Guacamole токен напрямую из JWT payload, а не из активной сессии в Redis.

ДО исправления:

# middleware.py (строка 77)
user_token = jwt_payload.get("guac_token")  # ❌ guac_token нет в JWT!

Проблема:

  • JWT содержит только session_id, а не guac_token
  • При логине создается новая сессия в Redis с новым Guacamole токеном
  • Но middleware не загружал сессию из Redis, поэтому user_token был None или старый

Решение

Исправление в middleware.py

Теперь middleware:

  1. Извлекает session_id из JWT
  2. Загружает актуальную сессию из Redis
  3. Получает текущий Guacamole токен из сессии

ПОСЛЕ исправления:

# middleware.py (строки 77-112)
session_id = jwt_payload.get("session_id")
if session_id:
    # Загружаем сессию из Redis
    from auth.session_storage import session_storage
    session_data = session_storage.get_session(session_id)
    
    if session_data:
        # ✅ Получаем актуальный Guacamole token из сессии
        user_token = session_data.get("guac_token")
    else:
        # Сессия истекла или удалена
        user_token = None
else:
    # Backwards compatibility
    user_token = jwt_payload.get("guac_token")

Как это работает

Схема аутентификации

┌─────────────────┐
│ 1. Пользователь │
│    логинится    │
└────────┬────────┘
         │
         ▼
┌────────────────────────────────────────────┐
│ 2. Guacamole возвращает auth_token         │
└────────┬───────────────────────────────────┘
         │
         ▼
┌────────────────────────────────────────────┐
│ 3. API создает Redis сессию:               │
│    - session_id: "abc123"                  │
│    - guac_token: "guac_token_xyz"          │
│    - user_info: {...}                      │
└────────┬───────────────────────────────────┘
         │
         ▼
┌────────────────────────────────────────────┐
│ 4. API создает JWT token:                 │
│    {                                       │
│      "username": "user",                   │
│      "role": "USER",                       │
│      "session_id": "abc123",  ← ТОЛЬКО ID! │
│      "exp": ...                            │
│    }                                       │
└────────┬───────────────────────────────────┘
         │
         ▼
┌────────────────────────────────────────────┐
│ 5. Клиент отправляет запросы с JWT         │
└────────┬───────────────────────────────────┘
         │
         ▼
┌────────────────────────────────────────────┐
│ 6. Middleware:                             │
│    - Извлекает session_id из JWT           │
│    - Загружает сессию из Redis ✅           │
│    - Получает актуальный guac_token ✅      │
└────────────────────────────────────────────┘

Восстановление подключений

User               API                Redis              Guacamole
  │                 │                   │                    │
  │─────LOGIN──────>│                   │                    │
  │                 │───AUTH───────────────────────────────>│
  │                 │<──guac_token_A────────────────────────│
  │                 │                   │                    │
  │                 │──CREATE SESSION──>│                    │
  │                 │  (guac_token_A)   │                    │
  │<─JWT(session_id)│                   │                    │
  │                 │                   │                    │
  │──CREATE CONN───>│                   │                    │
  │                 │──GET TOKEN───────>│                    │
  │                 │<─guac_token_A─────│                    │
  │                 │────CREATE CONNECTION─────────────────>│
  │<─connection_url─│                   │                    │
  │  (token_A)      │                   │                    │
  │                 │                   │                    │
  │────LOGOUT──────>│                   │                    │
  │                 │──DELETE SESSION──>│                    │
  │                 │                   │                    │
  │─────LOGIN──────>│                   │                    │
  │                 │───AUTH───────────────────────────────>│
  │                 │<──guac_token_B────────────────────────│ ← NEW TOKEN!
  │                 │                   │                    │
  │                 │──CREATE SESSION──>│                    │
  │                 │  (guac_token_B)   │                    │
  │<─JWT(session_id)│                   │                    │
  │                 │                   │                    │
  │──GET CONNECTIONS│                   │                    │
  │                 │──GET TOKEN───────>│                    │
  │                 │<─guac_token_B─────│ ✅ CURRENT TOKEN   │
  │<─URLs (token_B) │                   │                    │
  │  ✅ РАБОТАЕТ!   │                   │                    │

Применение исправления

cd GuacamoleRemoteAccess
docker-compose restart api

Проверка

После применения исправления:

  1. Логинитесь в клиент
  2. Создайте подключение к любой машине
  3. Сделайте logout
  4. Залогиньтесь снова
  5. Восстановите подключение
  6. Создайте новое подключение к другой машине
  7. Переключайтесь между подключениями → 403 ошибки больше нет! 🎉

Технические детали

JWT Payload (после логина)

{
  "username": "user",
  "role": "USER",
  "permissions": [],
  "session_id": "4edb****************************8c45",
  "token_type": "access",
  "exp": 1730721881,
  "iat": 1730718281,
  "iss": "remote-access-api"
}

Замечание: guac_token НЕ хранится в JWT по соображениям безопасности.

Redis Session (при логине)

{
  "user_info": {
    "username": "user",
    "role": "USER",
    "permissions": []
  },
  "guac_token": "589f****************************6edc",
  "ecdh_session_id": "abc123...",
  "created_at": "2025-11-04T14:24:41.123456Z",
  "expires_at": "2025-11-04T15:24:41.123456Z"
}

Backwards Compatibility

Исправление поддерживает старые JWT токены (если они содержат guac_token напрямую):

else:
    # Старый формат JWT с guac_token напрямую (backwards compatibility)
    user_token = jwt_payload.get("guac_token")

Это позволяет избежать проблем при rolling deployment.


Связанные файлы

  • GuacamoleRemoteAccess/api/auth/middleware.py - middleware для извлечения токена
  • GuacamoleRemoteAccess/api/auth/utils.py - создание JWT с session_id
  • GuacamoleRemoteAccess/api/auth/guacamole_auth.py - создание сессий в Redis
  • GuacamoleRemoteAccess/api/auth/session_storage.py - хранилище сессий
  • GuacamoleRemoteAccess/api/main.py - endpoint /connections для восстановления

Дата исправления

2025-11-04