diff --git a/aleksis/core/apps.py b/aleksis/core/apps.py index aeda609326941428e483e05cabd6e5412b2832f7..54c6d4f5b52626bc21e33eb5c6fea8e1c47c54ab 100644 --- a/aleksis/core/apps.py +++ b/aleksis/core/apps.py @@ -1,6 +1,7 @@ from typing import Any, List, Optional, Tuple import django.apps +from django.conf import settings from django.http import HttpRequest from django.utils.module_loading import autodiscover_modules @@ -12,7 +13,7 @@ from .registries import ( site_preferences_registry, ) from .util.apps import AppConfig -from .util.core_helpers import has_person +from .util.core_helpers import get_site_preferences, has_person, lazy_preference from .util.sass_helpers import clean_scss @@ -48,6 +49,18 @@ class CoreConfig(AppConfig): preference_models.register(personpreferencemodel, person_preferences_registry) preference_models.register(grouppreferencemodel, group_preferences_registry) + self._refresh_authentication_backends() + + def _refresh_authentication_backends(self): + """Refresh config list of enabled authentication backends.""" + from .preferences import AuthenticationBackends # noqa + + idx = settings.AUTHENTICATION_BACKENDS.index("django.contrib.auth.backends.ModelBackend") + + for backend in get_site_preferences()["auth__backends"]: + settings._wrapped.AUTHENTICATION_BACKENDS.insert(idx, backend) + idx += 1 + def preference_updated( self, sender: Any, @@ -57,6 +70,9 @@ class CoreConfig(AppConfig): new_value: Optional[Any] = None, **kwargs, ) -> None: + if section == "auth" and name == "backends": + self._refresh_authentication_backends() + if section == "theme": if name in ("primary", "secondary"): clean_scss() diff --git a/aleksis/core/preferences.py b/aleksis/core/preferences.py index 6693aff1fba605180b6f83e7741fe1cb005267fe..cf3d574c3619ed57afa517d8dbf7ed8d11a36881 100644 --- a/aleksis/core/preferences.py +++ b/aleksis/core/preferences.py @@ -3,7 +3,12 @@ from django.forms import EmailField, ImageField, URLField from django.utils.translation import gettext_lazy as _ from dynamic_preferences.preferences import Section -from dynamic_preferences.types import ChoicePreference, FilePreference, StringPreference +from dynamic_preferences.types import ( + ChoicePreference, + FilePreference, + MultipleChoicePreference, + StringPreference, +) from .models import Person from .registries import person_preferences_registry, site_preferences_registry @@ -16,6 +21,7 @@ mail = Section("mail") notification = Section("notification") footer = Section("footer") account = Section("account") +auth = Section("auth", verbose_name=_("Authentication")) @site_preferences_registry.register @@ -178,3 +184,12 @@ class SchoolNameOfficial(StringPreference): default = "" required = False verbose_name = _("Official name of the school, e.g. as given by supervisory authority") + + +@site_preferences_registry.register +class AuthenticationBackends(MultipleChoicePreference): + section = auth + name = "backends" + default = None + choices = [(b, b) for b in settings.CUSTOM_AUTHENTICATION_BACKENDS] + verbose_name = _("Enabled custom authentication backends") diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index 8eff3ef210c7c47a965fab761cf7d3f99cdcda92..98c233088c3a4aebd1a4c575efcbbd15b5c2b0df 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -282,13 +282,14 @@ if _settings.get("ldap.uri", None): "is_superuser" ] -merge_app_settings("AUTHENTICATION_BACKENDS", AUTHENTICATION_BACKENDS) +CUSTOM_AUTHENTICATION_BACKENDS = [] +merge_app_settings("AUTHENTICATION_BACKENDS", CUSTOM_AUTHENTICATION_BACKENDS) # Add ModelBckend last so all other backends get a chance # to verify passwords first AUTHENTICATION_BACKENDS.append("django.contrib.auth.backends.ModelBackend") -# Structure of items: URL name, icon name, button title +# Structure of items: backend, URL name, icon name, button title ALTERNATIVE_LOGIN_VIEWS = [] merge_app_settings("ALTERNATIVE_LOGIN_VIEWS", ALTERNATIVE_LOGIN_VIEWS, True) @@ -386,7 +387,7 @@ TEMPLATED_EMAIL_BACKEND = "templated_email.backends.vanilla_django" TEMPLATED_EMAIL_AUTO_PLAIN = True -TEMPLATE_VISIBLE_SETTINGS = ["ADMINS", "DEBUG", "ALTERNATIVE_LOGIN_VIEWS"] +TEMPLATE_VISIBLE_SETTINGS = ["ADMINS", "DEBUG"] DYNAMIC_PREFERENCES = { "REGISTRY_MODULE": "preferences", diff --git a/aleksis/core/templates/core/partials/alternative_login_options.html b/aleksis/core/templates/core/partials/alternative_login_options.html index f9198e5a826b6762d7207ac0b0a8849485d9418e..24d36e9ef76f3da11554169106fc1eafd3c7ac46 100644 --- a/aleksis/core/templates/core/partials/alternative_login_options.html +++ b/aleksis/core/templates/core/partials/alternative_login_options.html @@ -1,6 +1,6 @@ {% if ALTERNATIVE_LOGIN_VIEWS %} <p> - {% for url, icon, text in ALTERNATIVE_LOGIN_VIEWS %} + {% for backend, url, icon, text in ALTERNATIVE_LOGIN_VIEWS %} <a class="btn-large waves-effect waves-light primary" href="{% url url %}"> <i class="material-icons left">{{ icon }}</i> {{ text }} diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py index ba28f66292217b77a8d15eb1988774bbe09776fb..8302d51db5ba5d361eff95c9a5927e6c993526ab 100644 --- a/aleksis/core/util/core_helpers.py +++ b/aleksis/core/util/core_helpers.py @@ -323,6 +323,9 @@ def custom_information_processor(request: HttpRequest) -> dict: return { "FOOTER_MENU": CustomMenu.get_default("footer"), + "ALTERNATIVE_LOGIN_VIEWS": [ + a for a in settings.ALTERNATIVE_LOGIN_VIEWS if a[0] in settings.AUTHENTICATION_BACKENDS + ], }