hobo/debian/debian_config_common.py

413 lines
13 KiB
Python

# This file is sourced by "execfile" from django settings
# Example of django settings.py:
#
# (...)
# PROJECT_NAME = 'name'
# INSTALLED_APPS += ('mellon',) # SAML2 authentication
# execfile('/usr/lib/hoho/debian_config_common.py')
# execfile('/etc/%s/settings.py' % PROJECT_NAME)
import os
import warnings
import django
from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured
import hobo.logger
DEBUG = False
with open('/etc/%s/secret' % PROJECT_NAME) as fd:
SECRET_KEY = fd.read().strip()
ADMINS = (('Tous', 'root@localhost'),)
EMAIL_SUBJECT_PREFIX = ''
# sockets default timeout can be set to a small value in another thread by kombu
# https://github.com/celery/kombu/issues/838
# This prevents sockets created in smtplib to rely on the default timeout
# by setting their timeout value to 10 seconds.
EMAIL_TIMEOUT = 10.0
# send the SMTP Date header of email messages in the local time zone
# (since Django 1.11)
EMAIL_USE_LOCALTIME = True
# For high availability installations with multiple instances of Publik
# components, one should disable cron jobs execution on secondary servers;
# set the following variable True disables all tenant_commands launched with
# option "--all-tenants".
DISABLE_CRON_JOBS = False
# mode for newly updated files
FILE_UPLOAD_PERMISSIONS = 0o644
DEBUG_LOG_PATH = '/var/log/%s/debug' % PROJECT_NAME
DEBUG_LOG_FORMAT = (
'%(asctime)s \x1f%(tenant)s \x1f%(ip)s \x1f%(user)r \x1f%(request_id)s \x1f'
'%(levelname)s \x1f%(name)s \x1f%(message)s'
)
DEBUG_PROVISIONNING_LOG_PATH = '/var/log/%s/provisionning-debug' % PROJECT_NAME
DISABLE_GLOBAL_HANDLERS = os.environ.get('DISABLE_GLOBAL_HANDLERS') == '1'
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
'request_context': {
'()': 'hobo.logger.RequestContextFilter',
},
'force_debug': {
'()': 'hobo.logger.ForceDebugFilter',
},
'debug_log': {
'()': 'hobo.logger.DebugLogFilter',
},
'clamp_to_warning': {
'()': 'hobo.logger.ClampLogLevel',
'level': 'WARNING',
},
},
'formatters': {
'syslog': {
'format': '%(application)s %(levelname)s %(tenant)s %(ip)s %(user)s %(request_id)s'
' %(message)s',
},
'debug': {
'format': DEBUG_LOG_FORMAT,
},
'syslog_no_filter': {
'format': '%(levelname)s %(message)s',
},
},
'handlers': {
'syslog': {
'level': 'INFO',
'address': '/dev/log',
'class': 'logging.handlers.SysLogHandler',
'formatter': 'syslog',
'filters': ['request_context'],
},
'syslog_no_filter': {
'level': 'INFO',
'address': '/dev/log',
'class': 'logging.handlers.SysLogHandler',
'formatter': 'syslog_no_filter',
},
'mail_admins': {
'level': 'ERROR',
'class': 'hobo.multitenant.log.AdminEmailHandler',
'include_html': True,
},
'null': {
'class': 'logging.NullHandler',
},
'debug': {
'level': 'DEBUG',
'class': 'hobo.logger.TimedRotatingFileHandler',
'formatter': 'debug',
'filename': DEBUG_LOG_PATH,
'when': 'midnight',
'backupCount': 1,
'interval': 1,
'filters': ['request_context', 'debug_log'],
},
},
'loggers': {
'django.db': {
# even when debugging seeing SQL queries is too much
'level': 'INFO',
},
'django': {
# Override Django default values
'handlers': [],
'level': 'NOTSET',
'propagate': True,
},
'django.server': {
# Override Django 1.8 default values
'handlers': [],
'level': 'NOTSET',
'propagate': True,
},
'django.request': {
# Override Django default values
'handlers': [],
'level': 'NOTSET',
'propagate': True,
},
'django.security': {
# Override Django default values
'handlers': [],
'level': 'NOTSET',
'propagate': True,
},
'django.security.SuspiciousFileOperation': {
'filters': ['clamp_to_warning'],
},
'django.security.DisallowedRedirect': {
'filters': ['clamp_to_warning'],
},
'django.core.exceptions.DisallowedHost': {
'filters': ['clamp_to_warning'],
},
'django.template': {
# too much logs on DEBUG level
'handlers': [],
'level': 'INFO',
'propagate': True,
},
# lasso has the bad habit of logging everything as errors
'Lasso': {
'filters': ['force_debug'],
},
'libxml2': {
'filters': ['force_debug'],
},
'libxmlsec': {
'filters': ['force_debug'],
},
# log py.warnings to syslog
'py.warnings': {
'handlers': [] if DISABLE_GLOBAL_HANDLERS else ['syslog_no_filter'],
'level': 'WARNING',
'propagate': False,
},
'': {
'level': 'DEBUG',
'filters': ['request_context'],
'handlers': ([] if DISABLE_GLOBAL_HANDLERS else ['syslog']) + ['mail_admins', 'debug'],
},
},
}
# Journald support
if os.path.exists('/run/systemd/journal/socket') and not DISABLE_GLOBAL_HANDLERS:
try:
from systemd import journal
except ImportError:
pass
else:
LOGGING['handlers']['journald'] = {
'level': 'INFO',
'class': 'hobo.journal.JournalHandler',
'filters': ['request_context'],
'formatter': 'syslog',
}
LOGGING['loggers']['']['handlers'].remove('syslog')
LOGGING['loggers']['']['handlers'].append('journald')
elif not os.path.exists('/dev/log') and not DISABLE_GLOBAL_HANDLERS:
# if three's no syslog (for example when building a docker image), remove
# those loggers.
LOGGING['loggers']['']['handlers'].remove('syslog')
LOGGING['loggers']['py.warnings']['handlers'].remove('syslog_no_filter')
del LOGGING['handlers']['syslog']
del LOGGING['handlers']['syslog_no_filter']
ETC_DIR = '/etc/%s' % PROJECT_NAME
VAR_DIR = '/var/lib/%s' % PROJECT_NAME
# collecstatic destination
STATIC_ROOT = os.path.join(VAR_DIR, 'collectstatic')
# template settings
assert len(TEMPLATES)
assert TEMPLATES[0]['BACKEND'] == 'django.template.backends.django.DjangoTemplates'
if not 'loaders' in TEMPLATES[0]['OPTIONS']:
TEMPLATES[0]['APP_DIRS'] = False
TEMPLATES[0]['OPTIONS']['loaders'] = [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]
if PROJECT_NAME != 'wcs':
TEMPLATES[0]['OPTIONS']['loaders'].insert(0, 'hobo.multitenant.template_loader.FilesystemLoader')
if not 'django.template.context_processors.request' in TEMPLATES[0]['OPTIONS']['context_processors']:
TEMPLATES[0]['OPTIONS']['context_processors'].insert(0, 'django.template.context_processors.request')
TEMPLATES[0]['OPTIONS']['context_processors'] = [
'hobo.context_processors.template_vars',
'hobo.context_processors.theme_base',
'hobo.context_processors.portal_agent_url',
'hobo.context_processors.user_urls',
] + TEMPLATES[0]['OPTIONS']['context_processors']
# needed by hobo.context_processors.theme_base:
# THEME_SKELETON_URL = 'https://www.example.net/__skeleton__'
# Browsers may ensure that cookies are only sent under an HTTPS connection
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 36000 # 10h
CSRF_COOKIE_SAMESITE = None
# Apply sessionNotOnOrAfter on session expiration date
SESSION_ENGINE = 'mellon.sessions_backends.cached_db'
# make it easier to use runserver behind nginx as reverse proxy
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
if 'MIDDLEWARE' not in globals():
MIDDLEWARE = global_settings.MIDDLEWARE
MIDDLEWARE = (
'hobo.middleware.VersionMiddleware', # /__version__
'hobo.middleware.cors.CORSMiddleware',
'hobo.middleware.maintenance.MaintenanceMiddleware',
) + MIDDLEWARE
if PROJECT_NAME != 'wcs':
MIDDLEWARE = ('hobo.middleware.RobotsTxtMiddleware',) + MIDDLEWARE
if PROJECT_NAME != 'wcs' and 'authentic2' not in INSTALLED_APPS:
MIDDLEWARE = MIDDLEWARE + (
'mellon.middleware.PassiveAuthenticationMiddleware',
'hobo.provisionning.middleware.ProvisionningMiddleware',
)
if 'authentic2' in INSTALLED_APPS:
MIDDLEWARE = MIDDLEWARE + ('hobo.agent.authentic2.middleware.ProvisionningMiddleware',)
# Allow big provisionning messages
DATA_UPLOAD_MAX_MEMORY_SIZE = 50_000_000
if PROJECT_NAME != 'wcs':
# multitenant adaptations
TENANT_BASE = os.path.join(VAR_DIR, 'tenants')
TENANT_MODEL = 'multitenant.Tenant'
MIDDLEWARE = (
'hobo.multitenant.middleware.TenantMiddleware',
'hobo.middleware.CookiesSameSiteFixMiddleware',
'hobo.middleware.debug.InternalIPMiddleware',
) + MIDDLEWARE
DATABASES = {
'default': {
'ENGINE': 'tenant_schemas.postgresql_backend',
'NAME': PROJECT_NAME.replace('-', '_'),
}
}
DATABASE_ROUTERS = ('tenant_schemas.routers.TenantSyncRouter',)
TENANT_SETTINGS_LOADERS = (
'hobo.multitenant.settings_loaders.TemplateVars',
'hobo.multitenant.settings_loaders.KnownServices',
'hobo.multitenant.settings_loaders.LegacyURLSSettings',
'hobo.multitenant.settings_loaders.ThemeSettings',
'hobo.multitenant.settings_loaders.CORSSettings',
'hobo.multitenant.settings_loaders.SharedThemeSettings',
'hobo.multitenant.settings_loaders.Mellon',
'hobo.multitenant.settings_loaders.SiteBaseUrl',
'hobo.multitenant.settings_loaders.CookieNames',
'hobo.multitenant.settings_loaders.SettingsJSON',
'hobo.multitenant.settings_loaders.SettingsVars',
'hobo.multitenant.settings_loaders.BackofficeLoginHint',
)
# templates in <tenant>/templates
TENANT_TEMPLATE_DIRS = (TENANT_BASE,)
# /media in <tenant>/media
DEFAULT_FILE_STORAGE = 'hobo.multitenant.storage.TenantFileSystemStorage'
# cache by tenant
CACHES = {
'default': {
'BACKEND': 'hobo.multitenant.cache.TenantCache',
# add a real Django cache backend, with its parameters if needed
'REAL_BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
# haystack by tenant
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'hobo.multitenant.haystack.WhooshEngine',
}
}
# multitenant SHARED_APPS/TENANT_APPS/INSTALLED_APPS organization
SHARED_APPS = ()
INSTALLED_APPS = ('hobo.agent.common',) + INSTALLED_APPS
TENANT_APPS = INSTALLED_APPS
INSTALLED_APPS = ('hobo.multitenant',) + INSTALLED_APPS
# SAML2: search IdP in <tenant>
if 'authentic2' not in INSTALLED_APPS:
MELLON_ADAPTER = ('hobo.multitenant.mellon.MellonAdapter',)
if PROJECT_NAME in ('wcs', 'combo'):
TEMPLATES[0]['OPTIONS'].setdefault('builtins', []).append('hobo.templatetags.hobo')
if 'authentic2' not in INSTALLED_APPS:
MELLON_DEFAULT_ASSERTION_CONSUMER_BINDING = 'artifact'
MELLON_OPENED_SESSION_COOKIE_NAME = 'A2_OPENED_SESSION'
MELLON_ADD_AUTHNREQUEST_NEXT_URL_EXTENSION = True
MIDDLEWARE = (
'hobo.middleware.utils.StoreRequestMiddleware',
'hobo.middleware.xforwardedfor.XForwardedForMiddleware',
) + MIDDLEWARE
MIDDLEWARE = MIDDLEWARE + ('hobo.middleware.PrometheusStatsMiddleware',)
HOBO_MANAGER_HOMEPAGE_URL_VAR = 'portal_agent_url'
HOBO_MANAGER_HOMEPAGE_TITLE_VAR = 'portal_agent_title'
# Authentic2 role attributes for Publik
A2_MANAGER_ROLE_FORM_CLASS = 'hobo.agent.authentic2.role_forms.RoleForm'
# Locale and timezone
LANGUAGE_CODE = 'fr-fr'
TIME_ZONE = 'Europe/Paris'
LANGUAGES = (('fr', u'Fran\xe7ais'),)
USE_L10N = True
USE_TZ = True
# Celery configuration
BROKER_URL = 'amqp://'
BROKER_TASK_EXPIRES = 600
STATICS_HASH_COUNTER = '/var/lib/publik/statics-counter'
# Django Rest Framework: allow only Publik-signed URLs
if 'rest_framework' in INSTALLED_APPS:
if 'REST_FRAMEWORK' not in globals():
REST_FRAMEWORK = {}
REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = ('hobo.rest_authentication.PublikAuthentication',)
REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'] = ('rest_framework.permissions.IsAuthenticated',)
REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'] = ('rest_framework.renderers.JSONRenderer',)
HOBO_ANONYMOUS_SERVICE_USER_CLASS = 'hobo.rest_authentication.AnonymousAdminServiceUser'
THEMES_DIRECTORY = '/usr/share/publik/themes/'
USE_X_FORWARDED_FOR = True
EMAIL_BACKEND = 'hobo.emails.backend.EmailBackend'