From eadb42f82c0ae84dcd9ba2960f5249fd24e7fa35 Mon Sep 17 00:00:00 2001 From: Matthias Dellweg Date: Fri, 24 Apr 2026 11:24:49 +0200 Subject: [PATCH] Add saml2 as an optional dependency Activate SAML2 endpoints in case a SAML_CONFIG is provided. --- CHANGES/+saml2.feature | 1 + docs/admin/reference/settings.md | 12 ++++++++++++ pulpcore/app/settings.py | 17 ++++++++++++++++- pulpcore/app/urls.py | 3 +++ pyproject.toml | 3 ++- 5 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 CHANGES/+saml2.feature diff --git a/CHANGES/+saml2.feature b/CHANGES/+saml2.feature new file mode 100644 index 00000000000..6b7141f76bc --- /dev/null +++ b/CHANGES/+saml2.feature @@ -0,0 +1 @@ +Added `saml2` as a dependency option accompanied by the `SAML_CONFIG` setting. diff --git a/docs/admin/reference/settings.md b/docs/admin/reference/settings.md index cd30c2ae374..3fbc10a6d82 100644 --- a/docs/admin/reference/settings.md +++ b/docs/admin/reference/settings.md @@ -31,6 +31,16 @@ By default, Pulp has two types of authentication enabled, and they fall back for To change the authentication types Pulp will use, modify the `AUTHENTICATION_BACKENDS` settings. See the [Django authentication documentation] for more information. +#### SAML2 + +When installed with the `[saml2]` option, and the `SAML_CONFIG` is set, +SSO authentification according to the SAML2 protocols is available. + +See [django] and [pysaml2] for details. + +!!! warning + This is in feature-preview. + ### DATABASES By default, Pulp uses PostgreSQL on localhost. @@ -602,6 +612,7 @@ Defaults to `pulpcore.tasking.status`. [Django database settings]: https://docs.djangoproject.com/en/4.2/ref/settings/#databases [Django documentation on logging]: https://docs.djangoproject.com/en/4.2/topics/logging/#configuring-logging [django-guid settings documentation]: https://django-guid.readthedocs.io/en/latest/settings.html +[djangosaml2]: https://djangosaml2.readthedocs.io [Django secret key]: https://docs.djangoproject.com/en/4.2/ref/settings/#secret-key [Django setting]: https://docs.djangoproject.com/en/4.2/ref/settings/ [django-storages]: https://django-storages.readthedocs.io/en/latest/index.html @@ -609,6 +620,7 @@ Defaults to `pulpcore.tasking.status`. [Enabling Debug Logging]: site:pulpcore/docs/admin/guides/troubleshooting/#enabling-debug-logging [librdkafka configuration documentation]: https://github.com/confluentinc/librdkafka/blob/master/CONFIGURATION.md [on-demand and streaming limitations]: site:pulpcore/docs/user/learn/on-demand-downloading/#on-demand-and-streamed-limitations +[pysaml2]: https://pysaml2.readthedocs.io [recommended by aiohttp]: https://docs.aiohttp.org/en/stable/third_party.html#approved-third-party-libraries [task diagnostics documentation]: site:pulpcore/docs/dev/learn/tasks/diagnostics.md [uvloop]: https://github.com/MagicStack/uvloop diff --git a/pulpcore/app/settings.py b/pulpcore/app/settings.py index e79a2f26ad4..6961b88f302 100644 --- a/pulpcore/app/settings.py +++ b/pulpcore/app/settings.py @@ -604,6 +604,21 @@ def otel_middleware_hook(settings): return data +def saml2_settings_hook(settings): + data = {"dynaconf_merge": True} + if "SAML_CONFIG" in settings: + data["INSTALLED_APPS"] = ["djangosaml2"] + data["MIDDLEWARE"] = ["djangosaml2.middleware.SamlSessionMiddleware"] + data["AUTHENTICATION_BACKENDS"] = ["djangosaml2.backends.Saml2Backend"] + if "LOGIN_URL" not in settings: + data["LOGIN_URL"] = "/saml2/login/" + if "SESSION_COOKIE_SECURE" not in settings: + data["SESSION_COOKIE_SECURE"] = True + if "SESSION_EXPIRE_AT_BROWSER_CLOSE" not in settings: + data["SESSION_EXPIRE_AT_BROWSER_CLOSE"] = True + return data + + del preload_settings settings = DjangoDynaconf( @@ -628,7 +643,7 @@ def otel_middleware_hook(settings): otel_metrics_dispatch_interval_validator, distributed_publication_retention_period_validator, ], - post_hooks=(otel_middleware_hook,), + post_hooks=(otel_middleware_hook, saml2_settings_hook), ) _logger = getLogger(__name__) diff --git a/pulpcore/app/urls.py b/pulpcore/app/urls.py index 2c2649ad82c..caf90bfb67b 100644 --- a/pulpcore/app/urls.py +++ b/pulpcore/app/urls.py @@ -243,6 +243,9 @@ class NoSchema(p.callback.cls): path("", include("social_django.urls", namespace=settings.SOCIAL_AUTH_URL_NAMESPACE)) ) +if "djangosaml2" in settings.INSTALLED_APPS: + urlpatterns.append(path("saml2/", include("djangosaml2.urls"))) + #: The Pulp Platform v3 API router, which can be used to manually register ViewSets with the API. root_router = PulpDefaultRouter() diff --git a/pyproject.toml b/pyproject.toml index a67c4fb44da..41cdff4c6ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ dependencies = [ "drf-access-policy>=1.1.2,<1.5.1", "drf-nested-routers>=0.93.4,<=0.95.0", "drf-spectacular>=0.27.2,<0.30", # We monkeypatch this so we may need a very narrow requirement string. - "dynaconf>=3.2.5,<3.3.0", + "dynaconf>=3.3.0,<3.4", # Probably semver. "GitPython>=3.1.24,<3.2", "gunicorn>=22.0,<26.1.0", "jinja2>=3.1,<=3.1.6", @@ -72,6 +72,7 @@ s3 = ["django-storages[boto3]==1.14.6"] google = ["django-storages[google]==1.14.6"] azure = ["django-storages[azure]==1.14.6"] prometheus = ["django-prometheus"] +saml2 = ["djangosaml2>=1.12.0,<1.13"] kafka = [ # Pinned because project warns "things might (and will) break with every update" "cloudevents==1.11.0",