Skip to content
Snippets Groups Projects
Verified Commit 71b3c2ad authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Make custom authentication backends configurable via site preferences

parent 4d8b48a3
No related branches found
No related tags found
1 merge request!334Resolve "Support custom authentication backends"
Pipeline #3071 failed
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()
......
......@@ -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")
......@@ -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",
......
{% 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 }}
......
......@@ -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
],
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment