""" Configuration Management für OIDC Server Unterstützt verschiedene Umgebungen: Development, Testing, Production """ import os from dotenv import load_dotenv # Load .env file if it exists load_dotenv() class Config: """Base Configuration - Gemeinsame Settings für alle Umgebungen""" # Flask SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-please-change-in-production' # Database SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ECHO = False # SQL Logging # OIDC Server OIDC_ISSUER = os.environ.get('OIDC_ISSUER') or 'http://localhost:5000' OIDC_JWT_ALGORITHM = 'RS256' OIDC_JWT_PRIVATE_KEY_PATH = os.environ.get('OIDC_JWT_PRIVATE_KEY_PATH', 'instance/jwt_private.pem') OIDC_JWT_PUBLIC_KEY_PATH = os.environ.get('OIDC_JWT_PUBLIC_KEY_PATH', 'instance/jwt_public.pem') # Load JWT keys from files - this runs at class definition time try: with open(OIDC_JWT_PRIVATE_KEY_PATH, 'r') as f: OIDC_JWT_PRIVATE_KEY = f.read() with open(OIDC_JWT_PUBLIC_KEY_PATH, 'r') as f: OIDC_JWT_PUBLIC_KEY = f.read() except FileNotFoundError: # Keys not found - will be validated in ProductionConfig OIDC_JWT_PRIVATE_KEY = None OIDC_JWT_PUBLIC_KEY = None # Client Credentials (später durch DB ersetzen mit Multi-Client Support) OIDC_CLIENT_ID = os.environ.get('OIDC_CLIENT_ID') or 'test-client' OIDC_CLIENT_SECRET = os.environ.get('OIDC_CLIENT_SECRET') or 'test-secret' # Token Lifetimes (in Sekunden) ACCESS_TOKEN_LIFETIME = int(os.environ.get('ACCESS_TOKEN_LIFETIME', 3600)) # 1 Stunde AUTHORIZATION_CODE_LIFETIME = int(os.environ.get('AUTHORIZATION_CODE_LIFETIME', 600)) # 10 Minuten ID_TOKEN_LIFETIME = int(os.environ.get('ID_TOKEN_LIFETIME', 3600)) # 1 Stunde # Session SESSION_COOKIE_SECURE = False # Über HTTPS erzwingen (Production: True) SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'Lax' # Pagination USERS_PER_PAGE = 50 class DevelopmentConfig(Config): """Development Configuration""" DEBUG = True TESTING = False # Database - SQLite für Development SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///oidc.db' # SQL Logging aktiviert SQLALCHEMY_ECHO = True # OIDC Issuer OIDC_ISSUER = 'http://localhost:5000' class TestingConfig(Config): """Testing Configuration""" DEBUG = False TESTING = True # In-Memory SQLite für Tests SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:' # Disable CSRF for testing WTF_CSRF_ENABLED = False class ProductionConfig(Config): """Production Configuration""" DEBUG = False TESTING = False # Database - PostgreSQL für Production SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') # OIDC Issuer OIDC_ISSUER = os.environ.get('OIDC_ISSUER') # Secret Key SECRET_KEY = os.environ.get('SECRET_KEY') # Secure Cookies über HTTPS SESSION_COOKIE_SECURE = True # Client Credentials OIDC_CLIENT_ID = os.environ.get('OIDC_CLIENT_ID') OIDC_CLIENT_SECRET = os.environ.get('OIDC_CLIENT_SECRET') # Validate required production settings at class definition time if not SQLALCHEMY_DATABASE_URI: raise ValueError("DATABASE_URL environment variable must be set for production!") if not OIDC_ISSUER: raise ValueError("OIDC_ISSUER environment variable must be set for production!") if not SECRET_KEY: raise ValueError("SECRET_KEY environment variable must be set for production!") if not OIDC_CLIENT_ID or not OIDC_CLIENT_SECRET: raise ValueError("OIDC_CLIENT_ID and OIDC_CLIENT_SECRET must be set for production!") # Note: JWT keys are inherited from Config class and validated there # Config Dictionary für einfachen Zugriff config = { 'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig, 'default': DevelopmentConfig } def get_config(env=None): """ Gibt die Config-Klasse für die angegebene Umgebung zurück Args: env: Environment name ('development', 'testing', 'production') Falls None, wird FLASK_ENV aus Umgebungsvariablen gelesen Returns: Config-Klasse """ if env is None: env = os.environ.get('FLASK_ENV', 'development') return config.get(env, config['default'])