init_guac

This commit is contained in:
root
2025-11-25 09:58:37 +03:00
parent 68c8f0e80d
commit 9d5bdd57a7
57 changed files with 18272 additions and 0 deletions

View File

@ -0,0 +1,328 @@
# 🔧 Delete Connection Fix - 500 Error
## Проблема
При попытке удалить активное подключение возникала ошибка:
```
DELETE /connections/38
500 (Internal Server Error)
[guacamole-service] Failed to delete connection |
context: {"connectionId":"38","error":{}}
```
---
## Причина
После исправления middleware (для решения проблемы с восстановлением сессий), возникла новая проблема:
### Что происходило:
1. **Пользователь создает подключение:**
- Guacamole выдает `auth_token_A`
- Сохраняется в Redis: `conn_data['auth_token'] = auth_token_A`
2. **Пользователь делает logout/login:**
- Guacamole выдает **НОВЫЙ** `auth_token_B`
- Старый `auth_token_A` становится **невалидным**
- Но в Redis для подключения все еще хранится `auth_token_A`
3. **Пользователь пытается удалить подключение:**
- Код пытается удалить используя `conn_data['auth_token']` (старый `auth_token_A`)
- Guacamole отклоняет запрос: **токен невалиден**
- Результат: **500 Internal Server Error**
---
## Решение
### 1. Для ручного удаления (`DELETE /connections/{id}`)
**Используем ТЕКУЩИЙ токен пользователя** из активной сессии:
**ДО (❌ НЕПРАВИЛЬНО):**
```python
@app.delete("/connections/{connection_id}")
async def delete_connection(connection_id: str, request: Request, ...):
user_info = get_current_user(request)
conn_data = redis_connection_storage.get_connection(connection_id)
# ❌ Использует СТАРЫЙ токен из Redis
if guacamole_client.delete_connection_with_user_token(
connection_id,
conn_data['auth_token'] # ← Старый, невалидный токен!
):
# ...
```
**ПОСЛЕ (✅ ПРАВИЛЬНО):**
```python
@app.delete("/connections/{connection_id}")
async def delete_connection(connection_id: str, request: Request, ...):
user_info = get_current_user(request)
# ✅ Получаем ТЕКУЩИЙ токен из активной сессии пользователя
current_user_token = get_current_user_token(request)
if not current_user_token:
raise HTTPException(status_code=401, detail="Authentication token not available")
conn_data = redis_connection_storage.get_connection(connection_id)
# ✅ Используем ТЕКУЩИЙ токен пользователя
if guacamole_client.delete_connection_with_user_token(
connection_id,
current_user_token # ← Актуальный токен!
):
# ...
```
---
### 2. Для автоматического cleanup (фоновая задача)
**Используем СИСТЕМНЫЙ токен** (не пользовательский):
**ДО (❌ НЕПРАВИЛЬНО):**
```python
def cleanup_expired_or_orphaned_connections(log_action: str = "expired"):
for conn_id in expired_connections:
conn_data = redis_connection_storage.get_connection(conn_id)
# ❌ Использует токен пользователя (может быть невалидным)
if guacamole_client.delete_connection_with_user_token(
conn_id,
conn_data['auth_token'] # ← Старый токен пользователя
):
# ...
```
**ПОСЛЕ (✅ ПРАВИЛЬНО):**
```python
def cleanup_expired_or_orphaned_connections(log_action: str = "expired"):
for conn_id in expired_connections:
conn_data = redis_connection_storage.get_connection(conn_id)
# ✅ Cleanup - системная операция, используем системный токен
if guacamole_client.delete_connection_with_system_token(conn_id):
# ...
```
**Почему системный токен:**
- Cleanup - это фоновая системная задача
- Не привязана к конкретному пользователю
- Системный токен всегда валиден
- Правильнее с точки зрения архитектуры
---
## Архитектура токенов
```
┌─────────────────────────────────────────────────────────────┐
│ Пользователь логинится │
└────────────┬────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Guacamole выдает auth_token_NEW │
└────────────┬────────────────────────────────────────────────┘
├─► Сохраняется в Redis Session (для middleware)
└─► СТАРЫЕ подключения все еще хранят auth_token_OLD
в Redis (невалидный!)
```
### Решение проблемы:
**Для операций от лица пользователя:**
```
Пользователь → JWT → Middleware → Redis Session → ТЕКУЩИЙ токен
Guacamole API ✅
```
**Для системных операций:**
```
Система (Cleanup) → Системный токен → Guacamole API ✅
```
---
## Изменённые файлы
### 1. `GuacamoleRemoteAccess/api/main.py`
**Строки 3111-3120** - Добавлено получение текущего токена:
```python
# ✅ КРИТИЧНО: Получаем ТЕКУЩИЙ токен пользователя для удаления
current_user_token = get_current_user_token(request)
if not current_user_token:
logger.error("No Guacamole token available for user",
username=user_info["username"],
connection_id=connection_id)
raise HTTPException(
status_code=401,
detail="Authentication token not available"
)
```
**Строки 3156-3158** - Используется текущий токен:
```python
# ✅ КРИТИЧНО: Удаляем из Guacamole используя ТЕКУЩИЙ токен пользователя
# Не используем conn_data['auth_token'] так как он может быть невалидным после logout/login
if guacamole_client.delete_connection_with_user_token(connection_id, current_user_token):
```
**Строки 1295-1297** - Cleanup использует системный токен:
```python
# ✅ КРИТИЧНО: Удаляем из Guacamole используя СИСТЕМНЫЙ токен
# Cleanup - это системная операция, не используем auth_token пользователя
if guacamole_client.delete_connection_with_system_token(conn_id):
```
---
## Как это работает
### Сценарий 1: Пользователь удаляет подключение
```
Client API Redis Session Guacamole
│ │ │ │
│───DELETE /conn/38─>│ │ │
│ JWT Token │ │ │
│ │──get_current_user_token>│ │
│ │<─current_token──────────│ │
│ │ │ │
│ │────DELETE connection────────────────────>│
│ │ (current_token) │ │
│ │<───200 OK───────────────────────────────│
│<──200 OK───────────│ │ │
│ Success │ │ │
```
**Ключевой момент:** Используется `current_token` из активной сессии, а НЕ `auth_token` из Redis подключения!
---
### Сценарий 2: Cleanup удаляет истекшие подключения
```
Background Task API Guacamole
│ │ │
│─cleanup()────>│ │
│ │──get_system_token()──>│
│ │<─system_token─────────│
│ │ │
│ │──DELETE connections──>│
│ │ (system_token) │
│ │<─200 OK──────────────│
│<─complete─────│ │
```
**Ключевой момент:** Используется `system_token`, не токен какого-либо пользователя!
---
## Связь с предыдущими исправлениями
### 1. Middleware Fix (исправление восстановления сессий)
**Проблема:** JWT содержал `session_id`, но не `guac_token`
**Решение:** Middleware загружает токен из Redis сессии
**Побочный эффект:** Токены в старых подключениях становятся невалидными после logout/login
---
### 2. Delete Connection Fix (это исправление)
**Проблема:** Удаление использовало старый токен из `conn_data['auth_token']`
**Решение:** Удаление использует **текущий токен** из активной сессии
---
## Проверка исправления
### 1. Перезапустить API
```bash
cd GuacamoleRemoteAccess
docker-compose restart api
```
### 2. Протестировать удаление подключения
```bash
# 1. Залогиниться
curl -X POST https://mc.exbytestudios.com/auth/login-ecdh \
-H "Content-Type: application/json" \
-d '{"username":"user","password":"pass","session_id":"..."}' \
> login_response.json
# Извлечь JWT
JWT=$(jq -r '.access_token' login_response.json)
# 2. Создать подключение
curl -X POST https://mc.exbytestudios.com/connect \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{"hostname":"test","protocol":"ssh"}' \
> connection.json
# Извлечь connection_id
CONN_ID=$(echo $connection | jq -r '.connection_id')
# 3. Удалить подключение
curl -X DELETE https://mc.exbytestudios.com/connections/$CONN_ID \
-H "Authorization: Bearer $JWT"
# Должен вернуть:
# HTTP/1.1 200 OK
# {"message":"Connection deleted successfully"}
```
### 3. Проверить логи
```bash
docker-compose logs api | grep -i "delete"
# Должно быть:
# [info] Connection deleted successfully
# НЕ должно быть:
# [error] Failed to delete connection
```
---
## ✅ Результат
После исправления:
- ✅ Удаление подключения работает даже после logout/login
- ✅ Используется актуальный токен из активной сессии
- ✅ Cleanup использует системный токен (более правильно)
- ✅ Нет 500 ошибок при удалении
- ✅ Логика токенов консистентна
---
## 📝 Checklist
- [x] Добавлено получение `current_user_token` в `delete_connection`
- [x] `delete_connection` использует `current_user_token` вместо `auth_token`
- [x] Cleanup использует `delete_connection_with_system_token`
- [ ] Перезапущен API: `docker-compose restart api`
- [ ] Протестировано удаление подключения
- [ ] Проверены логи (нет ошибок)
---
**Дата исправления:** 2025-11-04
**Связанные исправления:** Middleware Fix, CORS Duplicate Fix
**Статус:** 🟢 **ИСПРАВЛЕНО**