From f69de12c6d9922ee15138cab326f3cc7ab09dab8 Mon Sep 17 00:00:00 2001 From: bctiemann Date: Mon, 17 Mar 2025 13:02:18 -0400 Subject: [PATCH] Closes: #15842 - Option to hide local login form if SSO is in use (#18924) Closes: #15842 Branched from #18145 by @tobiasge Provides a new LOGIN_FORM_HIDDEN setting which allows the administrator to hide the local login form, intended only to be used when SSO is used exclusively for authentication. Note that this means local login will be impossible in the event of SSO provider issues, and can be remedied only through a change to the application config and a restart of the service. * #15842 - Hide login form This doesn't implement the full solution proposed in #15842 but enables administrators to hide the login form when users should only login with a SSO provider. To prevent a complete lockout when the SSO provider is having issues the GET parameter `skipsso` can be added to the login URL to show the form regardless. * Remove skipsso backdoor * Add warning --------- Co-authored-by: Tobias Genannt --- docs/configuration/security.md | 11 ++++ netbox/account/views.py | 2 + netbox/netbox/configuration_example.py | 3 ++ netbox/netbox/settings.py | 1 + netbox/templates/login.html | 73 ++++++++++++++------------ 5 files changed, 57 insertions(+), 33 deletions(-) diff --git a/docs/configuration/security.md b/docs/configuration/security.md index b97f31432..172034b4f 100644 --- a/docs/configuration/security.md +++ b/docs/configuration/security.md @@ -186,6 +186,17 @@ The lifetime (in seconds) of the authentication cookie issued to a NetBox user u --- +## LOGIN_FORM_HIDDEN + +Default: False + +Option to hide the login form when only SSO authentication is in use. + +!!! warning + If the SSO provider is unreachable, login to NetBox will be impossible if this option is enabled. The only recourse is to disable it in the local configuration and restart the NetBox service. + +--- + ## LOGOUT_REDIRECT_URL Default: `'home'` diff --git a/netbox/account/views.py b/netbox/account/views.py index 05f40df3f..3a2dc6b32 100644 --- a/netbox/account/views.py +++ b/netbox/account/views.py @@ -89,10 +89,12 @@ class LoginView(View): if request.user.is_authenticated: logger = logging.getLogger('netbox.auth.login') return self.redirect_to_next(request, logger) + login_form_hidden = settings.LOGIN_FORM_HIDDEN return render(request, self.template_name, { 'form': form, 'auth_backends': self.get_auth_backends(request), + 'login_form_hidden': login_form_hidden, }) def post(self, request): diff --git a/netbox/netbox/configuration_example.py b/netbox/netbox/configuration_example.py index 84ead5339..a07661208 100644 --- a/netbox/netbox/configuration_example.py +++ b/netbox/netbox/configuration_example.py @@ -164,6 +164,9 @@ LOGIN_REQUIRED = True # re-authenticate. (Default: 1209600 [14 days]) LOGIN_TIMEOUT = None +# Hide the login form. Useful when only allowing SSO authentication. +LOGIN_FORM_HIDDEN = False + # The view name or URL to which users are redirected after logging out. LOGOUT_REDIRECT_URL = 'home' diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index defc5d99b..0c8f7ca70 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -129,6 +129,7 @@ LOGGING = getattr(configuration, 'LOGGING', {}) LOGIN_PERSISTENCE = getattr(configuration, 'LOGIN_PERSISTENCE', False) LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', True) LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None) +LOGIN_FORM_HIDDEN = getattr(configuration, 'LOGIN_FORM_HIDDEN', False) LOGOUT_REDIRECT_URL = getattr(configuration, 'LOGOUT_REDIRECT_URL', 'home') MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media')).rstrip('/') METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False) diff --git a/netbox/templates/login.html b/netbox/templates/login.html index e50303911..079d66a67 100644 --- a/netbox/templates/login.html +++ b/netbox/templates/login.html @@ -34,48 +34,55 @@ {% endif %}
-
-

{% trans "Log In" %}

+ {% if not login_form_hidden %} +
+

{% trans "Log In" %}

- {# Login form #} -
- {% csrf_token %} + {# Login form #} + + {% csrf_token %} - {# Set post-login URL #} - {% if 'next' in request.GET %} - - {% elif 'next' in request.POST %} - - {% endif %} + {# Set post-login URL #} + {% if 'next' in request.GET %} + + {% elif 'next' in request.POST %} + + {% endif %} -
- - {{ form.username }} - {% for error in form.username.errors %} -
{{ error }}
- {% endfor %} -
+
+ + {{ form.username }} + {% for error in form.username.errors %} +
{{ error }}
+ {% endfor %} +
-
- - {{ form.password }} - {% for error in form.password.errors %} -
{{ error }}
- {% endfor %} -
+
+ + {{ form.password }} + {% for error in form.password.errors %} +
{{ error }}
+ {% endfor %} +
- -
-
+ + +
+ {% endif %} {# SSO login #} {% if auth_backends %} -
{% trans "Or" context "Denotes an alternative option" %}
+ {% if not login_form_hidden %} +
{% trans "Or" context "Denotes an alternative option" %}
+ {% endif %}
+ {% if login_form_hidden %} +

{% trans "Log In" %}

+ {% endif %}
{% for backend in auth_backends %}