Skip to content

Commit f69de12

Browse files
bctiemanntobiasge
andauthored
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 <[email protected]>
1 parent 1b4e00a commit f69de12

File tree

5 files changed

+57
-33
lines changed

5 files changed

+57
-33
lines changed

docs/configuration/security.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,17 @@ The lifetime (in seconds) of the authentication cookie issued to a NetBox user u
186186

187187
---
188188

189+
## LOGIN_FORM_HIDDEN
190+
191+
Default: False
192+
193+
Option to hide the login form when only SSO authentication is in use.
194+
195+
!!! warning
196+
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.
197+
198+
---
199+
189200
## LOGOUT_REDIRECT_URL
190201

191202
Default: `'home'`

netbox/account/views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,12 @@ def get(self, request):
8989
if request.user.is_authenticated:
9090
logger = logging.getLogger('netbox.auth.login')
9191
return self.redirect_to_next(request, logger)
92+
login_form_hidden = settings.LOGIN_FORM_HIDDEN
9293

9394
return render(request, self.template_name, {
9495
'form': form,
9596
'auth_backends': self.get_auth_backends(request),
97+
'login_form_hidden': login_form_hidden,
9698
})
9799

98100
def post(self, request):

netbox/netbox/configuration_example.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@
164164
# re-authenticate. (Default: 1209600 [14 days])
165165
LOGIN_TIMEOUT = None
166166

167+
# Hide the login form. Useful when only allowing SSO authentication.
168+
LOGIN_FORM_HIDDEN = False
169+
167170
# The view name or URL to which users are redirected after logging out.
168171
LOGOUT_REDIRECT_URL = 'home'
169172

netbox/netbox/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
LOGIN_PERSISTENCE = getattr(configuration, 'LOGIN_PERSISTENCE', False)
130130
LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', True)
131131
LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None)
132+
LOGIN_FORM_HIDDEN = getattr(configuration, 'LOGIN_FORM_HIDDEN', False)
132133
LOGOUT_REDIRECT_URL = getattr(configuration, 'LOGOUT_REDIRECT_URL', 'home')
133134
MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media')).rstrip('/')
134135
METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False)

netbox/templates/login.html

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,48 +34,55 @@ <h4 class="alert-heading">{% trans "Errors" %}</h4>
3434
{% endif %}
3535

3636
<div class="card card-md">
37-
<div class="card-body">
38-
<h2 class="text-center mb-4">{% trans "Log In" %}</h2>
37+
{% if not login_form_hidden %}
38+
<div class="card-body">
39+
<h2 class="text-center mb-4">{% trans "Log In" %}</h2>
3940

40-
{# Login form #}
41-
<form action="{% url 'login' %}" method="post">
42-
{% csrf_token %}
41+
{# Login form #}
42+
<form action="{% url 'login' %}" method="post">
43+
{% csrf_token %}
4344

44-
{# Set post-login URL #}
45-
{% if 'next' in request.GET %}
46-
<input type="hidden" name="next" value="{{ request.GET.next }}" />
47-
{% elif 'next' in request.POST %}
48-
<input type="hidden" name="next" value="{{ request.POST.next }}" />
49-
{% endif %}
45+
{# Set post-login URL #}
46+
{% if 'next' in request.GET %}
47+
<input type="hidden" name="next" value="{{ request.GET.next }}" />
48+
{% elif 'next' in request.POST %}
49+
<input type="hidden" name="next" value="{{ request.POST.next }}" />
50+
{% endif %}
5051

51-
<div class="form-group mb-3">
52-
<label for="id_username" class="form-label">{{ form.username.label }}</label>
53-
{{ form.username }}
54-
{% for error in form.username.errors %}
55-
<div class="alert alert-danger">{{ error }}</div>
56-
{% endfor %}
57-
</div>
52+
<div class="form-group mb-3">
53+
<label for="id_username" class="form-label">{{ form.username.label }}</label>
54+
{{ form.username }}
55+
{% for error in form.username.errors %}
56+
<div class="alert alert-danger">{{ error }}</div>
57+
{% endfor %}
58+
</div>
5859

59-
<div class="form-group">
60-
<label for="id_password" class="form-label">{{ form.password.label }}</label>
61-
{{ form.password }}
62-
{% for error in form.password.errors %}
63-
<div class="alert alert-danger">{{ error }}</div>
64-
{% endfor %}
65-
</div>
60+
<div class="form-group">
61+
<label for="id_password" class="form-label">{{ form.password.label }}</label>
62+
{{ form.password }}
63+
{% for error in form.password.errors %}
64+
<div class="alert alert-danger">{{ error }}</div>
65+
{% endfor %}
66+
</div>
6667

67-
<div class="form-footer">
68-
<button type="submit" class="btn btn-primary w-100">
69-
{% trans "Sign In" %}
70-
</button>
71-
</div>
72-
</form>
73-
</div>
68+
<div class="form-footer">
69+
<button type="submit" class="btn btn-primary w-100">
70+
{% trans "Sign In" %}
71+
</button>
72+
</div>
73+
</form>
74+
</div>
75+
{% endif %}
7476

7577
{# SSO login #}
7678
{% if auth_backends %}
77-
<div class="hr-text">{% trans "Or" context "Denotes an alternative option" %}</div>
79+
{% if not login_form_hidden %}
80+
<div class="hr-text">{% trans "Or" context "Denotes an alternative option" %}</div>
81+
{% endif %}
7882
<div class="card-body">
83+
{% if login_form_hidden %}
84+
<h2 class="text-center mb-4">{% trans "Log In" %}</h2>
85+
{% endif %}
7986
<div class="row">
8087
{% for backend in auth_backends %}
8188
<div class="col">

0 commit comments

Comments
 (0)