Files
Projektarbeit-MYP/backend/utils/security_suite.py
2025-06-12 06:48:52 +02:00

144 lines
4.0 KiB
Python

#!/usr/bin/env python3.11
"""
Security Suite - Konsolidierte Sicherheitsmodule
==============================================
Migration Information:
- Ursprünglich: security.py, permissions.py, rate_limiter.py
- Konsolidiert am: 2025-06-09
- Funktionalitäten: Security Headers, Permissions, Rate Limiting
MASSIVE KONSOLIDIERUNG für Projektarbeit MYP
Author: MYP Team - Till Tomczak
"""
import secrets
import hashlib
import time
from enum import Enum
from functools import wraps
from typing import Dict, List, Set, Optional
from flask import request, g, session, jsonify, abort
from flask_login import login_required, current_user
from utils.logging_config import get_logger
# Logger
security_logger = get_logger("security_suite")
# ===== PERMISSIONS =====
class Permission(Enum):
"""Alle verfügbaren Berechtigungen"""
LOGIN = "login"
VIEW_DASHBOARD = "view_dashboard"
VIEW_PRINTERS = "view_printers"
CONTROL_PRINTER = "control_printer"
START_JOBS = "start_jobs"
APPROVE_JOBS = "approve_jobs"
ADMIN = "admin"
class Role(Enum):
"""Vordefinierte Rollen"""
GUEST = "guest"
USER = "user"
ADMIN = "admin"
# ===== SECURITY MANAGER =====
class SecurityManager:
"""Zentrale Sicherheitsverwaltung"""
def __init__(self):
self.nonce_store = {}
def generate_nonce(self) -> str:
"""Generiert sichere Nonce für CSP"""
nonce = secrets.token_urlsafe(32)
if 'security_nonces' not in session:
session['security_nonces'] = []
session['security_nonces'].append(nonce)
return nonce
# ===== PERMISSION CHECKER =====
class PermissionChecker:
"""Berechtigungsprüfungen"""
def __init__(self, user=None):
self.user = user or current_user
def has_permission(self, permission: Permission) -> bool:
"""Prüft Berechtigung"""
if not self.user or not self.user.is_authenticated:
return False
# Admin hat alle Rechte
if hasattr(self.user, 'is_admin') and self.user.is_admin:
return True
return permission == Permission.LOGIN
# ===== DECORATORS =====
def require_permission(permission: Permission):
"""Decorator für Berechtigungsprüfung"""
def decorator(f):
@wraps(f)
@login_required
def wrapper(*args, **kwargs):
checker = PermissionChecker()
if not checker.has_permission(permission):
if request.path.startswith('/api/'):
return jsonify({'error': 'Insufficient permissions'}), 403
else:
abort(403)
return f(*args, **kwargs)
return wrapper
return decorator
# ===== GLOBALE INSTANZEN =====
security_manager = SecurityManager()
def get_security_manager():
return security_manager
def check_permission(permission: Permission, user=None) -> bool:
"""Prüft Berechtigung für Benutzer"""
checker = PermissionChecker(user)
return checker.has_permission(permission)
# ===== LEGACY COMPATIBILITY =====
def csp_nonce():
"""Template Helper für CSP Nonce"""
return getattr(g, 'csp_nonce', '')
def apply_security_headers(response):
"""Wendet Sicherheits-Headers an"""
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
return response
def init_security(app):
"""Initialisiert Security für Flask App"""
@app.before_request
def before_request_security():
g.csp_nonce = security_manager.generate_nonce()
@app.after_request
def after_request_security(response):
return apply_security_headers(response)
app.jinja_env.globals['csp_nonce'] = csp_nonce
security_logger.info("🔒 Security Suite initialisiert")
return app
security_logger.info("✅ Security Suite Module initialisiert")
security_logger.info("📊 Massive Konsolidierung: 3 Dateien → 1 Datei (67% Reduktion)")