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 from typing import Any, List, Optional, Tuple
import django.apps import django.apps
from django.conf import settings
from django.http import HttpRequest from django.http import HttpRequest
from django.utils.module_loading import autodiscover_modules from django.utils.module_loading import autodiscover_modules
...@@ -12,7 +13,7 @@ from .registries import ( ...@@ -12,7 +13,7 @@ from .registries import (
site_preferences_registry, site_preferences_registry,
) )
from .util.apps import AppConfig 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 from .util.sass_helpers import clean_scss
...@@ -48,6 +49,18 @@ class CoreConfig(AppConfig): ...@@ -48,6 +49,18 @@ class CoreConfig(AppConfig):
preference_models.register(personpreferencemodel, person_preferences_registry) preference_models.register(personpreferencemodel, person_preferences_registry)
preference_models.register(grouppreferencemodel, group_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( def preference_updated(
self, self,
sender: Any, sender: Any,
...@@ -57,6 +70,9 @@ class CoreConfig(AppConfig): ...@@ -57,6 +70,9 @@ class CoreConfig(AppConfig):
new_value: Optional[Any] = None, new_value: Optional[Any] = None,
**kwargs, **kwargs,
) -> None: ) -> None:
if section == "auth" and name == "backends":
self._refresh_authentication_backends()
if section == "theme": if section == "theme":
if name in ("primary", "secondary"): if name in ("primary", "secondary"):
clean_scss() clean_scss()
......
...@@ -3,7 +3,12 @@ from django.forms import EmailField, ImageField, URLField ...@@ -3,7 +3,12 @@ from django.forms import EmailField, ImageField, URLField
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from dynamic_preferences.preferences import Section 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 .models import Person
from .registries import person_preferences_registry, site_preferences_registry from .registries import person_preferences_registry, site_preferences_registry
...@@ -16,6 +21,7 @@ mail = Section("mail") ...@@ -16,6 +21,7 @@ mail = Section("mail")
notification = Section("notification") notification = Section("notification")
footer = Section("footer") footer = Section("footer")
account = Section("account") account = Section("account")
auth = Section("auth", verbose_name=_("Authentication"))
@site_preferences_registry.register @site_preferences_registry.register
...@@ -178,3 +184,12 @@ class SchoolNameOfficial(StringPreference): ...@@ -178,3 +184,12 @@ class SchoolNameOfficial(StringPreference):
default = "" default = ""
required = False required = False
verbose_name = _("Official name of the school, e.g. as given by supervisory authority") 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): ...@@ -282,13 +282,14 @@ if _settings.get("ldap.uri", None):
"is_superuser" "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 # Add ModelBckend last so all other backends get a chance
# to verify passwords first # to verify passwords first
AUTHENTICATION_BACKENDS.append("django.contrib.auth.backends.ModelBackend") 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 = [] ALTERNATIVE_LOGIN_VIEWS = []
merge_app_settings("ALTERNATIVE_LOGIN_VIEWS", ALTERNATIVE_LOGIN_VIEWS, True) merge_app_settings("ALTERNATIVE_LOGIN_VIEWS", ALTERNATIVE_LOGIN_VIEWS, True)
...@@ -386,7 +387,7 @@ TEMPLATED_EMAIL_BACKEND = "templated_email.backends.vanilla_django" ...@@ -386,7 +387,7 @@ TEMPLATED_EMAIL_BACKEND = "templated_email.backends.vanilla_django"
TEMPLATED_EMAIL_AUTO_PLAIN = True TEMPLATED_EMAIL_AUTO_PLAIN = True
TEMPLATE_VISIBLE_SETTINGS = ["ADMINS", "DEBUG", "ALTERNATIVE_LOGIN_VIEWS"] TEMPLATE_VISIBLE_SETTINGS = ["ADMINS", "DEBUG"]
DYNAMIC_PREFERENCES = { DYNAMIC_PREFERENCES = {
"REGISTRY_MODULE": "preferences", "REGISTRY_MODULE": "preferences",
......
{% if ALTERNATIVE_LOGIN_VIEWS %} {% if ALTERNATIVE_LOGIN_VIEWS %}
<p> <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 %}"> <a class="btn-large waves-effect waves-light primary" href="{% url url %}">
<i class="material-icons left">{{ icon }}</i> <i class="material-icons left">{{ icon }}</i>
{{ text }} {{ text }}
......
...@@ -323,6 +323,9 @@ def custom_information_processor(request: HttpRequest) -> dict: ...@@ -323,6 +323,9 @@ def custom_information_processor(request: HttpRequest) -> dict:
return { return {
"FOOTER_MENU": CustomMenu.get_default("footer"), "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