forked from val-lop20/Pagina-de-Asistencia-MAC
126 lines
4.0 KiB
Python
126 lines
4.0 KiB
Python
"""
|
|
Middleware de auditoría para capturar eventos de seguridad
|
|
"""
|
|
import re
|
|
from django.utils.deprecation import MiddlewareMixin
|
|
from authentication.audit import AuditLog
|
|
from django_ratelimit.exceptions import Ratelimited
|
|
|
|
|
|
class AuditMiddleware:
|
|
"""
|
|
Middleware para registrar eventos de seguridad automáticamente
|
|
"""
|
|
|
|
def __init__(self, get_response):
|
|
self.get_response = get_response
|
|
|
|
def __call__(self, request):
|
|
# Procesar la solicitud
|
|
response = self.get_response(request)
|
|
|
|
# Registrar eventos de seguridad basados en código de respuesta
|
|
self._log_security_events(request, response)
|
|
|
|
return response
|
|
|
|
def _log_security_events(self, request, response):
|
|
"""
|
|
Registrar eventos de seguridad basados en códigos de respuesta HTTP
|
|
"""
|
|
status_code = response.status_code
|
|
user = request.user if hasattr(request, 'user') and request.user.is_authenticated else None
|
|
|
|
# 401 Unauthorized - Acceso no autorizado
|
|
if status_code == 401:
|
|
AuditLog.log(
|
|
category='SECURITY',
|
|
action='ACCESS_DENIED',
|
|
message=f'Intento de acceso no autorizado a {request.path}',
|
|
request=request,
|
|
user=user,
|
|
severity='WARNING',
|
|
success=False,
|
|
status_code=401,
|
|
path=request.path,
|
|
method=request.method
|
|
)
|
|
|
|
# 403 Forbidden - Permisos insuficientes
|
|
elif status_code == 403:
|
|
AuditLog.log(
|
|
category='SECURITY',
|
|
action='ACCESS_DENIED',
|
|
message=f'Acceso denegado (permisos insuficientes) a {request.path}',
|
|
request=request,
|
|
user=user,
|
|
severity='WARNING',
|
|
success=False,
|
|
status_code=403,
|
|
path=request.path,
|
|
method=request.method
|
|
)
|
|
|
|
# 429 Too Many Requests - Rate limit exceeded
|
|
elif status_code == 429:
|
|
AuditLog.log(
|
|
category='SECURITY',
|
|
action='RATE_LIMITED',
|
|
message=f'Rate limit excedido para {request.path}',
|
|
request=request,
|
|
user=user,
|
|
severity='WARNING',
|
|
success=False,
|
|
status_code=429,
|
|
path=request.path,
|
|
method=request.method
|
|
)
|
|
|
|
def process_exception(self, request, exception):
|
|
"""
|
|
Capturar excepciones de rate limiting
|
|
"""
|
|
if isinstance(exception, Ratelimited):
|
|
user = request.user if hasattr(request, 'user') and request.user.is_authenticated else None
|
|
|
|
AuditLog.log(
|
|
category='SECURITY',
|
|
action='RATE_LIMITED',
|
|
message=f'Rate limit exception en {request.path}',
|
|
request=request,
|
|
user=user,
|
|
severity='WARNING',
|
|
success=False,
|
|
status_code=429,
|
|
path=request.path,
|
|
method=request.method,
|
|
exception=str(exception)
|
|
)
|
|
|
|
return None # Permitir que Django maneje la excepción normalmente
|
|
|
|
|
|
class DisableCSRFOnAPIMiddleware(MiddlewareMixin):
|
|
"""
|
|
Middleware para deshabilitar CSRF en rutas de API
|
|
Ya que usamos JWT para autenticación en la API REST
|
|
"""
|
|
|
|
def process_request(self, request):
|
|
"""
|
|
Marcar requests de API como exentos de CSRF
|
|
"""
|
|
from django.conf import settings
|
|
|
|
# Obtener patrones de exención de CSRF
|
|
csrf_exempt_urls = getattr(settings, 'CSRF_EXEMPT_URLS', [])
|
|
|
|
# Verificar si la ruta actual debe estar exenta
|
|
path = request.path_info.lstrip('/')
|
|
|
|
for pattern in csrf_exempt_urls:
|
|
if re.match(pattern, path):
|
|
setattr(request, '_dont_enforce_csrf_checks', True)
|
|
break
|
|
|
|
return None |