Import urls.py and settings.py #1

Merged
Georg merged 2 commits from libertacasa-saml into libertacasa-master 2022-12-18 17:30:04 +01:00
2 changed files with 130 additions and 27 deletions

View File

@ -12,9 +12,12 @@ import sentry_sdk
from pydantic import AnyUrl, BaseSettings, EmailStr, Field, validator from pydantic import AnyUrl, BaseSettings, EmailStr, Field, validator
from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.integrations.django import DjangoIntegration
from takahe import __version__ from takahe.takahe import __version__
BASE_DIR = Path(__file__).resolve().parent.parent import saml2
from saml2.saml import NAMEID_FORMAT_PERSISTENT
BASE_DIR = '/srv/takahe'
class CacheBackendUrl(AnyUrl): class CacheBackendUrl(AnyUrl):
@ -59,7 +62,7 @@ class Settings(BaseSettings):
#: The currently running environment, used for things such as sentry #: The currently running environment, used for things such as sentry
#: error reporting. #: error reporting.
ENVIRONMENT: Environments = "development" ENVIRONMENT: Environments = "production"
#: Should django run in debug mode? #: Should django run in debug mode?
DEBUG: bool = False DEBUG: bool = False
@ -99,7 +102,7 @@ class Settings(BaseSettings):
ERROR_EMAILS: list[EmailStr] | None = None ERROR_EMAILS: list[EmailStr] | None = None
MEDIA_URL: str = "/media/" MEDIA_URL: str = "/media/"
MEDIA_ROOT: str = str(BASE_DIR / "media") MEDIA_ROOT: str = os.path.join(BASE_DIR, "media")
MEDIA_BACKEND: MediaBackendUrl | None = None MEDIA_BACKEND: MediaBackendUrl | None = None
#: Maximum filesize when uploading images. Increasing this may increase memory utilization #: Maximum filesize when uploading images. Increasing this may increase memory utilization
@ -147,7 +150,7 @@ class Settings(BaseSettings):
class Config: class Config:
env_prefix = "TAKAHE_" env_prefix = "TAKAHE_"
env_file = str(BASE_DIR / TAKAHE_ENV_FILE) env_file = '/etc/sysconfig/takahe'
env_file_encoding = "utf-8" env_file_encoding = "utf-8"
# Case sensitivity doesn't work on Windows, so might as well be # Case sensitivity doesn't work on Windows, so might as well be
# consistent from the get-go. # consistent from the get-go.
@ -179,16 +182,17 @@ INSTALLED_APPS = [
"django.contrib.staticfiles", "django.contrib.staticfiles",
"django_htmx", "django_htmx",
"corsheaders", "corsheaders",
"core", "takahe.core",
"activities", "takahe.activities",
"api", "takahe.api",
"mediaproxy", "takahe.mediaproxy",
"stator", "takahe.stator",
"users", "takahe.users",
"djangosaml2",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
"core.middleware.SentryTaggingMiddleware", "takahe.core.middleware.SentryTaggingMiddleware",
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"corsheaders.middleware.CorsMiddleware", "corsheaders.middleware.CorsMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware",
@ -199,19 +203,20 @@ MIDDLEWARE = [
"django.contrib.messages.middleware.MessageMiddleware", "django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware",
"django_htmx.middleware.HtmxMiddleware", "django_htmx.middleware.HtmxMiddleware",
"core.middleware.HeadersMiddleware", "takahe.core.middleware.HeadersMiddleware",
"core.middleware.ConfigLoadingMiddleware", "takahe.core.middleware.ConfigLoadingMiddleware",
"api.middleware.ApiTokenMiddleware", "takahe.api.middleware.ApiTokenMiddleware",
"users.middleware.IdentityMiddleware", "takahe.users.middleware.IdentityMiddleware",
"activities.middleware.EmojiDefaultsLoadingMiddleware", "takahe.activities.middleware.EmojiDefaultsLoadingMiddleware",
"djangosaml2.middleware.SamlSessionMiddleware",
] ]
ROOT_URLCONF = "takahe.urls" ROOT_URLCONF = "takahe.takahe.urls"
TEMPLATES = [ TEMPLATES = [
{ {
"BACKEND": "django.template.backends.django.DjangoTemplates", "BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], "DIRS": [os.path.join(BASE_DIR, "templates")],
"APP_DIRS": True, "APP_DIRS": True,
"OPTIONS": { "OPTIONS": {
"context_processors": [ "context_processors": [
@ -219,13 +224,13 @@ TEMPLATES = [
"django.template.context_processors.request", "django.template.context_processors.request",
"django.contrib.auth.context_processors.auth", "django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages", "django.contrib.messages.context_processors.messages",
"core.context.config_context", "takahe.core.context.config_context",
], ],
}, },
}, },
] ]
WSGI_APPLICATION = "takahe.wsgi.application" WSGI_APPLICATION = "takahe.takahe.wsgi.application"
if SETUP.DATABASE_SERVER: if SETUP.DATABASE_SERVER:
DATABASES = { DATABASES = {
@ -272,7 +277,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
AUTH_USER_MODEL = "users.User" AUTH_USER_MODEL = "users.User"
LOGIN_URL = "/auth/login/" LOGIN_URL = "/saml2/login/"
LOGOUT_URL = "/auth/logout/" LOGOUT_URL = "/auth/logout/"
LOGIN_REDIRECT_URL = "/" LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/" LOGOUT_REDIRECT_URL = "/"
@ -282,7 +287,7 @@ STATICFILES_FINDERS = [
"django.contrib.staticfiles.finders.AppDirectoriesFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder",
] ]
STATICFILES_DIRS = [BASE_DIR / "static"] STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
@ -290,7 +295,7 @@ SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
WHITENOISE_MAX_AGE = 3600 WHITENOISE_MAX_AGE = 3600
STATIC_ROOT = BASE_DIR / "static-collected" STATIC_ROOT = os.path.join(BASE_DIR, "static-collected")
ALLOWED_HOSTS = SETUP.ALLOWED_HOSTS ALLOWED_HOSTS = SETUP.ALLOWED_HOSTS
@ -355,14 +360,14 @@ if SETUP.MEDIA_BACKEND:
parsed = urllib.parse.urlparse(SETUP.MEDIA_BACKEND) parsed = urllib.parse.urlparse(SETUP.MEDIA_BACKEND)
query = urllib.parse.parse_qs(parsed.query) query = urllib.parse.parse_qs(parsed.query)
if parsed.scheme == "gs": if parsed.scheme == "gs":
DEFAULT_FILE_STORAGE = "core.uploads.TakaheGoogleCloudStorage" DEFAULT_FILE_STORAGE = "takahe.core.uploads.TakaheGoogleCloudStorage"
GS_BUCKET_NAME = parsed.path.lstrip("/") GS_BUCKET_NAME = parsed.path.lstrip("/")
GS_QUERYSTRING_AUTH = False GS_QUERYSTRING_AUTH = False
if parsed.hostname is not None: if parsed.hostname is not None:
port = parsed.port or 443 port = parsed.port or 443
GS_CUSTOM_ENDPOINT = f"https://{parsed.hostname}:{port}" GS_CUSTOM_ENDPOINT = f"https://{parsed.hostname}:{port}"
elif parsed.scheme == "s3": elif parsed.scheme == "s3":
DEFAULT_FILE_STORAGE = "core.uploads.TakaheS3Storage" DEFAULT_FILE_STORAGE = "takahe.core.uploads.TakaheS3Storage"
AWS_STORAGE_BUCKET_NAME = parsed.path.lstrip("/") AWS_STORAGE_BUCKET_NAME = parsed.path.lstrip("/")
AWS_QUERYSTRING_AUTH = False AWS_QUERYSTRING_AUTH = False
AWS_DEFAULT_ACL = "public-read" AWS_DEFAULT_ACL = "public-read"
@ -393,3 +398,97 @@ TAKAHE_USER_AGENT = (
f"python-httpx/{httpx.__version__} " f"python-httpx/{httpx.__version__} "
f"(Takahe/{__version__}; +https://{SETUP.MAIN_DOMAIN}/)" f"(Takahe/{__version__}; +https://{SETUP.MAIN_DOMAIN}/)"
) )
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'djangosaml2.backends.Saml2Backend',
)
SAML_SESSION_COOKIE_NAME = 'takahe_test_session'
SESSION_COOKIE_SECURE = False
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SAML_DJANGO_USER_MAIN_ATTRIBUTE = 'email'
SAML_ATTRIBUTE_MAPPING = {
'email': ('email', ),
}
SAML_CONFIG = {
# full path to the xmlsec1 binary programm
'xmlsec_binary': '/usr/bin/xmlsec1',
# your entity id, usually your subdomain plus the url to the metadata view
'entityid': 'https://__REPLACE_ME__/saml2/metadata/',
'attribute_map_dir': os.path.join(BASE_DIR, 'attribute-maps'),
'allow_unknown_attributes': False,
'service': {
'sp' : {
'name': 'Federated Takahe sample SP',
'name_id_format': saml2.saml.NAMEID_FORMAT_PERSISTENT,
'endpoints': {
'assertion_consumer_service': [
('https://__REPLACE_ME__/saml2/acs/',
saml2.BINDING_HTTP_POST),
],
'single_logout_service': [
('https://__REPLACE_ME__/saml2/ls/',
saml2.BINDING_HTTP_REDIRECT),
('https://__REPLACE_ME__/saml2/ls/post',
saml2.BINDING_HTTP_POST),
],
},
'signing_algorithm': saml2.xmldsig.SIG_RSA_SHA256,
'digest_algorithm': saml2.xmldsig.DIGEST_SHA256,
'force_authn': False,
'name_id_format_allow_create': False,
'required_attributes': ['uid',
'email'],
'want_response_signed': True,
'authn_requests_signed': True,
'logout_requests_signed': True,
'want_assertions_signed': True,
'only_use_keys_in_metadata': True,
'allow_unsolicited': False,
'metadata': {
# in production, use local file
# 'local': [os.path.join(BASE_DIR, 'remote_metadata.xml')],
'remote': [{"url": "https://libsso.net/realms/LibertaCasa/protocol/saml/descriptor"},],
},
'debug': 0,
'key_file': '__REPLACE_ME__', # private part
'cert_file': '__REPLACE_ME__', # public part
# Encryption
# 'encryption_keypairs': [{
# 'key_file': '__REPLACE_ME__', # private part
# 'cert_file': '__REPLACE_ME__', # public part
# }],
}
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'root': {
'handlers': ['console'],
'level': 'INFO',
},
}

View File

@ -9,6 +9,9 @@ from mediaproxy import views as mediaproxy
from stator import views as stator from stator import views as stator
from users.views import activitypub, admin, auth, identity, report, settings from users.views import activitypub, admin, auth, identity, report, settings
from django.conf.urls import include
from django.views.generic.base import RedirectView
urlpatterns = [ urlpatterns = [
path("", core.homepage), path("", core.homepage),
path("manifest.json", core.AppManifest.as_view()), path("manifest.json", core.AppManifest.as_view()),
@ -174,7 +177,7 @@ urlpatterns = [
path("@<handle>/posts/<int:post_id>/report/", report.SubmitReport.as_view()), path("@<handle>/posts/<int:post_id>/report/", report.SubmitReport.as_view()),
path("@<handle>/posts/<int:post_id>/edit/", compose.Compose.as_view()), path("@<handle>/posts/<int:post_id>/edit/", compose.Compose.as_view()),
# Authentication # Authentication
path("auth/login/", auth.Login.as_view(), name="login"), path("auth/login/", RedirectView.as_view(url='/saml2/login', permanent=False), name='login'),
path("auth/logout/", auth.Logout.as_view(), name="logout"), path("auth/logout/", auth.Logout.as_view(), name="logout"),
path("auth/signup/", auth.Signup.as_view(), name="signup"), path("auth/signup/", auth.Signup.as_view(), name="signup"),
path("auth/reset/", auth.TriggerReset.as_view(), name="trigger_reset"), path("auth/reset/", auth.TriggerReset.as_view(), name="trigger_reset"),
@ -248,4 +251,5 @@ urlpatterns = [
core.custom_static_serve, core.custom_static_serve,
kwargs={"document_root": djsettings.MEDIA_ROOT}, kwargs={"document_root": djsettings.MEDIA_ROOT},
), ),
path('saml2/', include('djangosaml2.urls')),
] ]