Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ============================================
# CONFIGURACIÓN PARA LOCALHOST
# ============================================

# Backend - MT5 API
CUSTOM_USER=admin
PASSWORD=admin123
VNC_DOMAIN=mt5-vnc.localhost
API_DOMAIN=mt5-api.localhost
MT5_API_PORT=5001
SECRET_KEY=super-secret-key-for-jwt-localhost-dev

# Traefik (Reverse Proxy)
TRAEFIK_DOMAIN=traefik.localhost
TRAEFIK_USERNAME=admin
ACME_EMAIL=dev@localhost.com

# Backend - Django Web
MT5_API_URL=http://mt5:5001
DJANGO_DOMAIN=django.localhost

# Database PostgreSQL
POSTGRES_DB=mt5_trading
POSTGRES_USER=mt5_user
POSTGRES_PASSWORD=mt5_password
POSTGRES_HOST=postgres
POSTGRES_PORT=5432

# Redis & Celery
CELERY_BROKER_URL=redis://redis:6379/0
CELERY_RESULT_BACKEND=redis://redis:6379/0

# Monitoring
GRAFANA_DOMAIN=grafana.localhost
PROMETHEUS_VERSION=v2.37.9
GRAFANA_VERSION=9.1.0
LOKI_VERSION=2.8.0
PROMTAIL_VERSION=2.8.0
ALERTMANAGER_VERSION=v0.25.0DJANGO_DOMAIN=django.localhost
API_DOMAIN=mt5-api.localhost
VNC_DOMAIN=mt5-vnc.localhost
GRAFANA_DOMAIN=grafana.localhost
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ PASSWORD=1234
VNC_DOMAIN=vnc.mt5.example.com
API_DOMAIN=api.mt5.example.com
MT5_API_PORT=5001
# REQUIRED. Generate with:
# python -c 'import secrets; print(secrets.token_urlsafe(64))'
# The app refuses to start if this is empty or set to the example placeholder.
SECRET_KEY=
# Redis URL used by the MT5 API for session storage (DB 1 to avoid colliding with Celery on DB 0).
REDIS_URL=redis://redis:6379/1

# Traefik
TRAEFIK_DOMAIN=traefik.mt5.example.com
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ yarn-error.log*

# Local env files
.env*.local
.env

# Vercel
.vercel
Expand Down Expand Up @@ -91,4 +90,6 @@ logs
*.log

# Database
*.sqlite3
*.sqlite3

/config
88 changes: 88 additions & 0 deletions PROTECCION_ENDPOINTS_APLICADA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# ✅ Tarea 1.1.2: Protección de Endpoints Aplicada

## Resumen de Cambios

Se ha aplicado la protección de autenticación a todos los endpoints existentes en el servidor MT5.

### Archivos Modificados

#### 1. `routes/position.py`
- ✅ Importado middleware: `from routes.auth import require_auth`
- ✅ Protegidos 5 endpoints:
- `/close_position` (POST)
- `/close_all_positions` (POST)
- `/modify_sl_tp` (POST)
- `/get_positions` (GET)
- `/positions_total` (GET)

#### 2. `routes/symbol.py`
- ✅ Importado middleware: `from routes.auth import require_auth`
- ✅ Protegidos 2 endpoints:
- `/symbol_info_tick/<symbol>` (GET)
- `/symbol_info/<symbol>` (GET)

#### 3. `routes/data.py`
- ✅ Importado middleware: `from routes.auth import require_auth`
- ✅ Protegidos 2 endpoints:
- `/fetch_data_pos` (GET)
- `/fetch_data_range` (GET)

#### 4. `routes/order.py`
- ✅ Importado middleware: `from routes.auth import require_auth`
- ✅ Protegido 1 endpoint:
- `/order` (POST)

#### 5. `routes/history.py`
- ✅ Importado middleware: `from routes.auth import require_auth`
- ✅ Protegidos 4 endpoints:
- `/get_deal_from_ticket` (GET)
- `/get_order_from_ticket` (GET)
- `/history_deals_get` (GET)
- `/history_orders_get` (GET)

### Patrón Aplicado

Para cada endpoint se aplicó el siguiente patrón:

```python
@route_bp.route('/endpoint', methods=['METHOD'])
@require_auth # ✅ Middleware de autenticación
@swag_from({
'tags': ['Tag'],
'security': [{'ApiKeyAuth': []}], # ✅ Documentación Swagger
# ... resto de configuración
})
def endpoint_function():
# ... código existente
```

### Total de Endpoints Protegidos: 14

#### Por Categoría:
- **Position**: 5 endpoints
- **Symbol**: 2 endpoints
- **Data**: 2 endpoints
- **Order**: 1 endpoint
- **History**: 4 endpoints

### Funcionalidad de Seguridad

Todos los endpoints ahora requieren:
1. **Token JWT válido** en header `Authorization: Bearer <token>`
2. **Sesión activa** no expirada
3. **Documentación Swagger actualizada** con `security: [{'ApiKeyAuth': []}]`

### Próximos Pasos

Los endpoints están listos para:
- Autenticación mediante login (`/login`)
- Verificación automática de tokens
- Manejo de sesiones con timeout
- Documentación de seguridad en Swagger UI

### Notas Técnicas

- Se mantuvieron todas las funcionalidades existentes
- Los endpoints sin protección seguirán funcionando hasta que se requiera autenticación
- La protección es transparente para clientes autenticados
- Los errores de autenticación devuelven códigos HTTP 401 con mensajes descriptivos
175 changes: 175 additions & 0 deletions SISTEMA_LOGIN_MT5_COMPLETO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# 🔐 Sistema de Autenticación MT5 Sin Credenciales Hardcodeadas

## ✅ Implementación Completa

### 🏗️ Arquitectura Implementada

```
📊 Usuario
🌐 Django Frontend (Login Form)
↓ (Credenciales del usuario)
🔄 MT5Client (Sin credenciales fijas)
↓ (HTTP POST /login)
🖥️ Flask MT5 API (Servidor MT5)
↓ (mt5.login())
📈 MetaTrader 5 Terminal
```

### 📁 Archivos Creados/Modificados

#### 1. **Cliente MT5 Corregido** ✅
- `backend/django/app/utils/api/mt5_client.py`
- ❌ **ELIMINADO**: Credenciales hardcodeadas
- ✅ **AÑADIDO**: Método `login(login, password, server)`
- ✅ **AÑADIDO**: Gestión de tokens JWT por sesión
- ✅ **AÑADIDO**: Verificación automática de autenticación

#### 2. **Formulario Django** ✅
- `backend/django/app/quant/forms.py`
- ✅ Campos: Login, Password, Server
- ✅ Bootstrap styling incluido
- ✅ Validación de formulario

#### 3. **Vistas Django** ✅
- `backend/django/app/quant/views.py`
- ✅ `mt5_login_view`: Maneja login con API MT5
- ✅ `mt5_logout_view`: Cierra sesión completa
- ✅ `dashboard_view`: Dashboard protegido con datos MT5

#### 4. **Templates HTML** ✅
- `backend/django/app/templates/quant/mt5_login.html`
- `backend/django/app/templates/quant/dashboard.html`
- ✅ Bootstrap 5 responsive
- ✅ Mensajes de estado
- ✅ Formulario seguro con CSRF

#### 5. **URLs Django** ✅
- `backend/django/app/quant/urls.py`
- `backend/django/app/app/urls.py` (actualizado)
- ✅ Rutas: `/login/`, `/logout/`, `/` (dashboard)

#### 6. **Middleware de Seguridad** ✅
- `backend/django/app/quant/middleware.py`
- ✅ Protección automática de rutas
- ✅ Redirección a login si no autenticado

### 🔄 Flujo de Usuario Completo

1. **Usuario visita** → `https://django.mt5.example.com/login/`
2. **Ingresa credenciales** → Login: `123456789`, Password: `****`, Server: `MetaQuotes-Demo`
3. **Django envía** → Credenciales a API Flask MT5
4. **API Flask** → Intenta `mt5.login()` con esas credenciales
5. **Si exitoso** → API devuelve token JWT + info cuenta
6. **Django almacena** → Token en sesión del usuario
7. **Usuario accede** → Dashboard y funcionalidades MT5

### 🔒 Características de Seguridad

✅ **Credenciales no están en código ni variables de entorno**
✅ **Tokens JWT con expiración automática (30 min)**
✅ **Sesiones Django para manejo de estado**
✅ **CSRF protection en formularios**
✅ **Logout limpia sesión completa**
✅ **Middleware protege rutas automáticamente**
✅ **Verificación de tokens antes de cada request**

### 🚀 Configuración para Producción

#### Variables de Entorno
```bash
# Solo la URL del servidor MT5 es necesaria
MT5_API_URL=http://mt5:5001
```

#### Settings Django
```python
# backend/django/app/app/settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
# ... otros middlewares ...
'quant.middleware.MT5AuthMiddleware', # ✅ Añadir al final
]

# Configuración de sesiones
SESSION_COOKIE_AGE = 1800 # 30 minutos
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
```

### 🧪 Pruebas de Funcionamiento

#### 1. Login Exitoso
```bash
curl -X POST http://localhost:8000/login/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "login=123456789&password=mypassword&server=MetaQuotes-Demo"
```

#### 2. Dashboard Protegido
```bash
# Sin sesión -> Redirige a /login/
curl -I http://localhost:8000/

# Con sesión -> Muestra dashboard
curl -b "sessionid=abc123" http://localhost:8000/
```

#### 3. Logout
```bash
curl -X GET http://localhost:8000/logout/ \
-b "sessionid=abc123"
```

### 📊 Estados de la Aplicación

#### Estado No Autenticado
- ❌ No hay token en sesión
- ❌ Acceso bloqueado al dashboard
- ✅ Solo acceso a `/login/`

#### Estado Autenticado
- ✅ Token JWT válido en sesión
- ✅ Información de cuenta disponible
- ✅ Acceso completo a funcionalidades MT5
- ✅ Auto-renovación de token

#### Estado Token Expirado
- ⚠️ Token JWT caducado
- 🔄 Auto-redirección a login
- 🧹 Limpieza automática de sesión

### 🔧 Extensiones Futuras

#### API Endpoints Adicionales
- `POST /api/orders/` - Crear nuevas órdenes
- `DELETE /api/positions/{id}/` - Cerrar posiciones
- `GET /api/market-data/{symbol}/` - Datos de mercado
- `WebSocket` - Updates en tiempo real

#### Funcionalidades UI
- 📊 Gráficos de trading interactivos
- ⚡ Órdenes rápidas desde dashboard
- 📈 Historial de trades
- 🔔 Notificaciones push

### ⚠️ Notas Importantes

1. **Seguridad**: Las credenciales viajan por HTTPS únicamente
2. **Sesiones**: Se limpian automáticamente al cerrar navegador
3. **Tokens**: Renovación automática antes de expirar
4. **Errores**: Manejo robusto de errores de conexión
5. **Logging**: Todos los eventos de auth se registran

### 🎯 Resultado Final

**ANTES**:
- ❌ Credenciales en variables de entorno
- ❌ Todos los usuarios usan la misma cuenta
- ❌ Sin interfaz de login

**DESPUÉS**:
- ✅ Cada usuario ingresa sus propias credenciales
- ✅ Sesiones individuales por usuario
- ✅ Interfaz completa de login/dashboard
- ✅ Seguridad robusta con JWT + Django sessions
24 changes: 24 additions & 0 deletions backend/django/app/app/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
URL configuration for app project.

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('nexus.urls')),
path('', include('quant.urls')), # URLs de la app quant para MT5
]
25 changes: 25 additions & 0 deletions backend/django/app/quant/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from django import forms

class MT5LoginForm(forms.Form):
login = forms.IntegerField(
label="Login MT5",
widget=forms.NumberInput(attrs={
'class': 'form-control',
'placeholder': '123456789'
})
)
password = forms.CharField(
label="Password",
widget=forms.PasswordInput(attrs={
'class': 'form-control',
'placeholder': '••••••••'
})
)
server = forms.CharField(
label="Servidor",
max_length=100,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'MetaQuotes-Demo'
})
)
Loading