mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-12 15:29:23 -05:00
e34a668ddc
Introduce AUTH_METHOD values ldap and all, with LDAP_* environment settings, ldap3-based LDAPService (search, optional groupOfNames checks, user bind, DB sync), and users.auth_provider (local|oidc|ldap) via migration 153_add_user_auth_provider. Login supports LDAP-only and combined all (local then LDAP where appropriate); OIDC callback sets auth_provider. Forgot/reset/change password flows skip LDAP-managed accounts. Admin System Settings gains a read-only LDAP summary and POST /admin/ldap/test. Production env validation requires core LDAP variables when LDAP is enabled; OIDC registration and docs recognize all. Documentation: new docs/admin/configuration/LDAP_SETUP.md; updates to OIDC_SETUP, GETTING_STARTED, Docker guides, Render deploy notes, docs README, and CHANGELOG. Tests: tests/test_ldap_auth.py; test_oidc_logout allows auth_method all.
230 lines
8.3 KiB
Plaintext
230 lines
8.3 KiB
Plaintext
# Flask settings
|
|
# CRITICAL: Change SECRET_KEY in production! Used for sessions, cookies, and CSRF tokens.
|
|
# Generate a secure key with: python -c "import secrets; print(secrets.token_hex(32))"
|
|
# The same key must be used across restarts and all app replicas.
|
|
SECRET_KEY=your-secret-key-here
|
|
FLASK_ENV=production
|
|
FLASK_DEBUG=false
|
|
|
|
# Database settings
|
|
DATABASE_URL=postgresql+psycopg2://timetracker:timetracker@db:5432/timetracker
|
|
POSTGRES_DB=timetracker
|
|
POSTGRES_USER=timetracker
|
|
POSTGRES_PASSWORD=timetracker
|
|
POSTGRES_HOST=db
|
|
|
|
# Docker Compose: nginx host port mappings (used by docker-compose.yml)
|
|
# Override when 80/443 are in use (e.g. behind Nginx Proxy Manager, Traefik, Caddy).
|
|
# Example: HTTP_PORT=8180 HTTPS_PORT=8443
|
|
# HTTP_PORT=80
|
|
# HTTPS_PORT=443
|
|
|
|
# Session settings
|
|
SESSION_COOKIE_SECURE=false
|
|
SESSION_COOKIE_HTTPONLY=true
|
|
PERMANENT_SESSION_LIFETIME=86400
|
|
|
|
# Application settings
|
|
TZ=Europe/Rome
|
|
CURRENCY=EUR
|
|
ROUNDING_MINUTES=1
|
|
SINGLE_ACTIVE_TIMER=true
|
|
IDLE_TIMEOUT_MINUTES=30
|
|
|
|
# Smart in-app notifications (session toasts; see docs/features/SMART_NOTIFICATIONS.md)
|
|
# SMART_NOTIFY_MAX_PER_DAY=2
|
|
# SMART_NOTIFY_NO_TRACKING_AFTER=16:00
|
|
# SMART_NOTIFY_SUMMARY_AT=18:00
|
|
# SMART_NOTIFY_LONG_TIMER_HOURS=4
|
|
# SMART_NOTIFY_SCHEDULER_SLOT_MINUTES=30
|
|
|
|
# AI helper (server-side; API keys are never sent to clients)
|
|
# AI_ENABLED=false
|
|
# AI_PROVIDER=ollama
|
|
# AI_BASE_URL=http://127.0.0.1:11434
|
|
# AI_MODEL=llama3.1
|
|
# AI_API_KEY=
|
|
# AI_TIMEOUT_SECONDS=30
|
|
# AI_CONTEXT_LIMIT=40
|
|
|
|
# API token rate limits (per token; Redis recommended for multi-worker)
|
|
# API_TOKEN_RATE_LIMIT_PER_MINUTE=100
|
|
# API_TOKEN_RATE_LIMIT_PER_HOUR=1000
|
|
|
|
# User management
|
|
ALLOW_SELF_REGISTER=true
|
|
# Comma-separated admin usernames. Only the first username is automatically created during database initialization.
|
|
# The default admin has no password—set it on first login (enter username + any password 8+ chars).
|
|
# Additional admin usernames must either self-register (if ALLOW_SELF_REGISTER=true) or be created manually.
|
|
# Example: ADMIN_USERNAMES=admin,manager - only "admin" is created automatically; "manager" must self-register or be created manually.
|
|
ADMIN_USERNAMES=admin
|
|
|
|
# Authentication
|
|
# Options: none | local | oidc | ldap | both | all
|
|
# none = No password authentication (username only)
|
|
# local = Password authentication required
|
|
# oidc = OIDC/Single Sign-On only
|
|
# ldap = LDAP bind only
|
|
# both = OIDC + local password (backwards compatible)
|
|
# all = local + OIDC + LDAP
|
|
AUTH_METHOD=local
|
|
|
|
# Security hardening (recommended)
|
|
# Settings secrets encryption-at-rest (mail passwords, OAuth secrets, Peppol token, AI key, 2FA secret).
|
|
# Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
# SETTINGS_ENCRYPTION_KEY=
|
|
# Or mount from file:
|
|
# SETTINGS_ENCRYPTION_KEY_FILE=/run/secrets/timetracker_settings_key
|
|
#
|
|
# Password reset link lifetime (seconds)
|
|
# PASSWORD_RESET_TOKEN_MAX_AGE_SECONDS=3600
|
|
#
|
|
# Require TOTP 2FA for admin accounts (admins will be prompted to enroll)
|
|
# REQUIRE_2FA_FOR_ADMINS=false
|
|
|
|
# LDAP Authentication (used when AUTH_METHOD=ldap or all)
|
|
# LDAP_HOST=ldap.example.com
|
|
# LDAP_PORT=389
|
|
# LDAP_USE_SSL=false
|
|
# LDAP_USE_TLS=false
|
|
# LDAP_BIND_DN=cn=serviceaccount,dc=example,dc=com
|
|
# LDAP_BIND_PASSWORD=secret
|
|
# LDAP_BASE_DN=dc=example,dc=com
|
|
# LDAP_USER_DN=ou=users
|
|
# LDAP_USER_OBJECT_CLASS=inetOrgPerson
|
|
# LDAP_USER_LOGIN_ATTR=uid
|
|
# LDAP_USER_EMAIL_ATTR=mail
|
|
# LDAP_USER_FNAME_ATTR=givenName
|
|
# LDAP_USER_LNAME_ATTR=sn
|
|
# LDAP_GROUP_DN=ou=groups
|
|
# LDAP_GROUP_OBJECT_CLASS=groupOfNames
|
|
# LDAP_ADMIN_GROUP=timetracker-admins
|
|
# LDAP_REQUIRED_GROUP=timetracker-users
|
|
# LDAP_TLS_CA_CERT_FILE=/certs/ldap-ca.crt
|
|
# LDAP_TIMEOUT=10
|
|
|
|
# OIDC (used when AUTH_METHOD=oidc, both, or all)
|
|
# OIDC_ISSUER=https://login.microsoftonline.com/<tenant>/v2.0
|
|
# OIDC_CLIENT_ID=
|
|
# OIDC_CLIENT_SECRET=
|
|
# OIDC_REDIRECT_URI=https://yourapp.example.com/auth/oidc/callback
|
|
# OIDC_SCOPES=openid profile email
|
|
# OIDC_USERNAME_CLAIM=preferred_username
|
|
# OIDC_FULL_NAME_CLAIM=name
|
|
# OIDC_EMAIL_CLAIM=email
|
|
# OIDC_GROUPS_CLAIM=groups
|
|
# OIDC_ADMIN_GROUP=
|
|
# OIDC_ADMIN_EMAILS=
|
|
# Optional: RP-Initiated Logout. Only set if your provider supports end_session_endpoint.
|
|
# If unset, logout will be local only (recommended for providers like Authelia).
|
|
# If set, TimeTracker will redirect to the provider's logout endpoint.
|
|
# OIDC_POST_LOGOUT_REDIRECT_URI=https://yourapp.example.com/
|
|
|
|
# Backup settings
|
|
BACKUP_RETENTION_DAYS=30
|
|
BACKUP_TIME=02:00
|
|
# Optional: override where backup archives are stored (default: <UPLOAD_FOLDER>/backups)
|
|
# BACKUP_FOLDER=/data/uploads/backups
|
|
|
|
# Email settings (Flask-Mail)
|
|
# Configure these to enable email notifications and features
|
|
# MAIL_SERVER=smtp.gmail.com
|
|
# MAIL_PORT=587
|
|
# MAIL_USE_TLS=true
|
|
# MAIL_USE_SSL=false
|
|
# MAIL_USERNAME=your-email@gmail.com
|
|
# MAIL_PASSWORD=your-app-password
|
|
# MAIL_DEFAULT_SENDER=noreply@yourdomain.com
|
|
# MAIL_MAX_EMAILS=100
|
|
|
|
# Peppol e-invoicing (optional)
|
|
# Requires an access point provider. This app uses a generic HTTP adapter.
|
|
# Enable:
|
|
# PEPPOL_ENABLED=true
|
|
#
|
|
# Sender identifiers (your company in Peppol)
|
|
# Example endpoint scheme ids: 0088 (GLN), 9906 (VAT), 0208 (LEI) depending on your country/AP rules
|
|
# PEPPOL_SENDER_ENDPOINT_ID=
|
|
# PEPPOL_SENDER_SCHEME_ID=
|
|
# Optional:
|
|
# PEPPOL_SENDER_COUNTRY=BE
|
|
#
|
|
# Access point adapter (HTTP JSON endpoint your AP exposes)
|
|
# PEPPOL_ACCESS_POINT_URL=
|
|
# PEPPOL_ACCESS_POINT_TOKEN=
|
|
# PEPPOL_ACCESS_POINT_TIMEOUT=30
|
|
# PEPPOL_PROVIDER=generic
|
|
|
|
# File upload settings
|
|
MAX_CONTENT_LENGTH=16777216
|
|
UPLOAD_FOLDER=/data/uploads
|
|
|
|
# CSRF protection
|
|
# IMPORTANT: Keep CSRF enabled in production for security
|
|
# Only disable for development/testing if needed
|
|
WTF_CSRF_ENABLED=true
|
|
WTF_CSRF_TIME_LIMIT=3600
|
|
|
|
# CSRF SSL Strict Mode
|
|
# Set to false if accessing via HTTP (localhost or IP address)
|
|
# Set to true only when using HTTPS in production
|
|
WTF_CSRF_SSL_STRICT=false
|
|
|
|
# CSRF Cookie Settings
|
|
# Only set these if you need to access the app via IP address or have cookie issues
|
|
# CSRF_COOKIE_SECURE=false # Set to false for HTTP access
|
|
# CSRF_COOKIE_SAMESITE=Lax # Options: Strict, Lax, None
|
|
# CSRF_COOKIE_DOMAIN= # Leave empty for single domain, set for subdomains
|
|
|
|
# Session Cookie Settings for IP Address Access
|
|
# If accessing via IP address (e.g., 192.168.1.100), use these settings:
|
|
# SESSION_COOKIE_SAMESITE=Lax # Change to 'None' only if needed for cross-site
|
|
# SESSION_COOKIE_SECURE=false # Must be false for HTTP
|
|
|
|
# TROUBLESHOOTING CSRF issues ("CSRF token missing or invalid" errors):
|
|
# 1. SECRET_KEY changed? All CSRF tokens become invalid when SECRET_KEY changes
|
|
# 2. Cookies blocked? Check browser settings and allow cookies from your domain
|
|
# 3. Behind a proxy? Ensure proxy forwards cookies and doesn't strip them
|
|
# 4. Token expired? Increase WTF_CSRF_TIME_LIMIT (in seconds)
|
|
# 5. Multiple app instances? All must use the SAME SECRET_KEY
|
|
# 6. Clock skew? Ensure server time is synchronized (use NTP)
|
|
# 7. Accessing via IP? Set WTF_CSRF_SSL_STRICT=false and SESSION_COOKIE_SECURE=false
|
|
# 8. Still broken? Try: docker-compose restart app
|
|
# 9. For testing only: Set WTF_CSRF_ENABLED=false (NOT for production!)
|
|
# See docs/CSRF_CONFIGURATION.md for detailed troubleshooting
|
|
|
|
# Logging
|
|
LOG_LEVEL=INFO
|
|
LOG_FILE=/data/logs/timetracker.log
|
|
|
|
# Analytics and Monitoring
|
|
# All analytics features are optional and disabled by default
|
|
|
|
# Sentry Error Monitoring (optional)
|
|
# Get your DSN from https://sentry.io/settings/projects/
|
|
# SENTRY_DSN=
|
|
# SENTRY_TRACES_RATE=0.0
|
|
|
|
# OTEL OTLP export (optional sink)
|
|
# Example endpoint: https://otlp-gateway-prod-eu-west-2.grafana.net/otlp
|
|
# OTEL_EXPORTER_OTLP_ENDPOINT=
|
|
# OTEL_EXPORTER_OTLP_TOKEN=
|
|
#
|
|
# OpenTelemetry SDK (traces + metrics to OTLP; uses same endpoint/token as above)
|
|
# When unset, tracing and metrics default to enabled if OTLP credentials are present.
|
|
# ENABLE_TRACING=true
|
|
# ENABLE_METRICS=true
|
|
# Optional: OTLP metrics export interval in milliseconds (default 60000)
|
|
# OTEL_METRICS_EXPORT_INTERVAL_MS=60000
|
|
#
|
|
# Tests only: in-memory tracing without network (pytest)
|
|
# OTEL_ENABLE_IN_TESTS=1
|
|
|
|
# Telemetry (optional, opt-in, anonymous)
|
|
# Sends anonymous installation data to Grafana OTLP (version/platform/install heartbeat)
|
|
# Requires OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_TOKEN
|
|
# Default: false (disabled)
|
|
# See docs/privacy.md for details
|
|
# ENABLE_TELEMETRY=true
|
|
# TELE_SALT=8f4a7b2e9c1d6f3a5e8b4c7d2a9f6e3b1c8d5a7f2e9b4c6d3a8f5e1b7c4d9a2f
|
|
# APP_VERSION= # Automatically read from setup.py, override only if needed |