Files
oicd/config.py
2025-11-30 00:07:24 +01:00

146 lines
4.3 KiB
Python

"""
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'])