#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.
This commit is contained in:
Tobias Genannt 2024-12-03 15:48:30 +01:00
parent ce365dab0a
commit a324a5e951
5 changed files with 54 additions and 33 deletions

View File

@ -186,6 +186,14 @@ 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. Appending `skipsso` as GET parameter shows the login form in case there is a problem with the SSO provider.
---
## LOGOUT_REDIRECT_URL ## LOGOUT_REDIRECT_URL
Default: `'home'` Default: `'home'`

View File

@ -89,10 +89,12 @@ class LoginView(View):
if request.user.is_authenticated: if request.user.is_authenticated:
logger = logging.getLogger('netbox.auth.login') logger = logging.getLogger('netbox.auth.login')
return self.redirect_to_next(request, logger) return self.redirect_to_next(request, logger)
login_form_hidden = settings.LOGIN_FORM_HIDDEN and "skipsso" not in request.GET
return render(request, self.template_name, { return render(request, self.template_name, {
'form': form, 'form': form,
'auth_backends': self.get_auth_backends(request), 'auth_backends': self.get_auth_backends(request),
'login_form_hidden': login_form_hidden,
}) })
def post(self, request): def post(self, request):

View File

@ -164,6 +164,9 @@ LOGIN_REQUIRED = True
# re-authenticate. (Default: 1209600 [14 days]) # re-authenticate. (Default: 1209600 [14 days])
LOGIN_TIMEOUT = None 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. # The view name or URL to which users are redirected after logging out.
LOGOUT_REDIRECT_URL = 'home' LOGOUT_REDIRECT_URL = 'home'

View File

@ -127,6 +127,7 @@ LOGGING = getattr(configuration, 'LOGGING', {})
LOGIN_PERSISTENCE = getattr(configuration, 'LOGIN_PERSISTENCE', False) LOGIN_PERSISTENCE = getattr(configuration, 'LOGIN_PERSISTENCE', False)
LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', True) LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', True)
LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None) 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') LOGOUT_REDIRECT_URL = getattr(configuration, 'LOGOUT_REDIRECT_URL', 'home')
MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media')).rstrip('/') MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media')).rstrip('/')
METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False) METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False)

View File

@ -34,48 +34,55 @@
{% endif %} {% endif %}
<div class="card card-md"> <div class="card card-md">
<div class="card-body"> {% if not login_form_hidden %}
<h2 class="text-center mb-4">{% trans "Log In" %}</h2> <div class="card-body">
<h2 class="text-center mb-4">{% trans "Log In" %}</h2>
{# Login form #} {# Login form #}
<form action="{% url 'login' %}" method="post"> <form action="{% url 'login' %}" method="post">
{% csrf_token %} {% csrf_token %}
{# Set post-login URL #} {# Set post-login URL #}
{% if 'next' in request.GET %} {% if 'next' in request.GET %}
<input type="hidden" name="next" value="{{ request.GET.next }}" /> <input type="hidden" name="next" value="{{ request.GET.next }}" />
{% elif 'next' in request.POST %} {% elif 'next' in request.POST %}
<input type="hidden" name="next" value="{{ request.POST.next }}" /> <input type="hidden" name="next" value="{{ request.POST.next }}" />
{% endif %} {% endif %}
<div class="form-group mb-3"> <div class="form-group mb-3">
<label for="id_username" class="form-label">{{ form.username.label }}</label> <label for="id_username" class="form-label">{{ form.username.label }}</label>
{{ form.username }} {{ form.username }}
{% for error in form.username.errors %} {% for error in form.username.errors %}
<div class="alert alert-danger">{{ error }}</div> <div class="alert alert-danger">{{ error }}</div>
{% endfor %} {% endfor %}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="id_password" class="form-label">{{ form.password.label }}</label> <label for="id_password" class="form-label">{{ form.password.label }}</label>
{{ form.password }} {{ form.password }}
{% for error in form.password.errors %} {% for error in form.password.errors %}
<div class="alert alert-danger">{{ error }}</div> <div class="alert alert-danger">{{ error }}</div>
{% endfor %} {% endfor %}
</div> </div>
<div class="form-footer"> <div class="form-footer">
<button type="submit" class="btn btn-primary w-100"> <button type="submit" class="btn btn-primary w-100">
{% trans "Sign In" %} {% trans "Sign In" %}
</button> </button>
</div> </div>
</form> </form>
</div> </div>
{% endif %}
{# SSO login #} {# SSO login #}
{% if auth_backends %} {% if auth_backends %}
<div class="hr-text">{% trans "Or" context "Denotes an alternative option" %}</div> {% if not login_form_hidden %}
<div class="hr-text">{% trans "Or" context "Denotes an alternative option" %}</div>
{% endif %}
<div class="card-body"> <div class="card-body">
{% if login_form_hidden %}
<h2 class="text-center mb-4">{% trans "Log In" %}</h2>
{% endif %}
<div class="row"> <div class="row">
{% for backend in auth_backends %} {% for backend in auth_backends %}
<div class="col"> <div class="col">