mirror of
https://github.com/sissbruecker/linkding.git
synced 2026-02-27 22:43:15 +08:00
Add option to disable login form (#1269)
This commit is contained in:
@@ -24,6 +24,8 @@ LD_AUTH_PROXY_USERNAME_HEADER=
|
|||||||
# The URL that linkding should redirect to after a logout, when using an auth proxy
|
# The URL that linkding should redirect to after a logout, when using an auth proxy
|
||||||
# See docs/Options.md for more details
|
# See docs/Options.md for more details
|
||||||
LD_AUTH_PROXY_LOGOUT_URL=
|
LD_AUTH_PROXY_LOGOUT_URL=
|
||||||
|
# Disables the login form, useful to enforce OIDC authentication
|
||||||
|
LD_DISABLE_LOGIN_FORM=False
|
||||||
# List of trusted origins from which to accept POST requests
|
# List of trusted origins from which to accept POST requests
|
||||||
# See docs/Options.md for more details
|
# See docs/Options.md for more details
|
||||||
LD_CSRF_TRUSTED_ORIGINS=
|
LD_CSRF_TRUSTED_ORIGINS=
|
||||||
|
|||||||
@@ -180,6 +180,13 @@ HUEY = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Disable login form if configured
|
||||||
|
LD_DISABLE_LOGIN_FORM = os.getenv("LD_DISABLE_LOGIN_FORM", False) in (
|
||||||
|
True,
|
||||||
|
"True",
|
||||||
|
"true",
|
||||||
|
"1",
|
||||||
|
)
|
||||||
|
|
||||||
# Enable OICD support if configured
|
# Enable OICD support if configured
|
||||||
LD_ENABLE_OIDC = os.getenv("LD_ENABLE_OIDC", False) in (True, "True", "true", "1")
|
LD_ENABLE_OIDC = os.getenv("LD_ENABLE_OIDC", False) in (True, "True", "true", "1")
|
||||||
|
|||||||
4
bookmarks/styles/auth.css
Normal file
4
bookmarks/styles/auth.css
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.auth-page {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 350px;
|
||||||
|
}
|
||||||
@@ -31,3 +31,4 @@
|
|||||||
@import "settings.css";
|
@import "settings.css";
|
||||||
@import "bundles.css";
|
@import "bundles.css";
|
||||||
@import "tags.css";
|
@import "tags.css";
|
||||||
|
@import "auth.css";
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
{% with page_title="Login - Linkding" %}{{ block.super }}{% endwith %}
|
{% with page_title="Login - Linkding" %}{{ block.super }}{% endwith %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
|
<main class="auth-page" aria-labelledby="main-heading">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h1 id="main-heading">Login</h1>
|
<h1 id="main-heading">Login</h1>
|
||||||
</div>
|
</div>
|
||||||
|
{% if not disable_login %}
|
||||||
<form method="post" action="{% url 'login' %}">
|
<form method="post" action="{% url 'login' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
@@ -21,16 +22,14 @@
|
|||||||
{% formlabel form.password 'Password' %}
|
{% formlabel form.password 'Password' %}
|
||||||
{% formfield form.password class='form-input' %}
|
{% formfield form.password class='form-input' %}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<input type="submit" value="Login" class="btn btn-primary width-100 mt-4" />
|
||||||
<div class="d-flex justify-between">
|
|
||||||
<input type="submit" value="Login" class="btn btn-primary btn-wide" />
|
|
||||||
<input type="hidden" name="next" value="{{ next }}" />
|
<input type="hidden" name="next" value="{{ next }}" />
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
{% if enable_oidc %}
|
{% if enable_oidc %}
|
||||||
<a class="btn btn-link"
|
<a class="btn width-100 mt-4"
|
||||||
href="{% url 'oidc_authentication_init' %}"
|
href="{% url 'oidc_authentication_init' %}"
|
||||||
data-turbo="false">Login with OIDC</a>
|
data-turbo="false">Login with OIDC</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% with page_title="Password changed - Linkding" %}{{ block.super }}{% endwith %}
|
{% with page_title="Password changed - Linkding" %}{{ block.super }}{% endwith %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
|
<main class="auth-page" aria-labelledby="main-heading">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h1 id="main-heading">Password Changed</h1>
|
<h1 id="main-heading">Password Changed</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
{% with page_title="Change password - Linkding" %}{{ block.super }}{% endwith %}
|
{% with page_title="Change password - Linkding" %}{{ block.super }}{% endwith %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
|
<main class="auth-page" aria-labelledby="main-heading">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h1 id="main-heading">Change Password</h1>
|
<h1 id="main-heading">Change Password</h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,10 +25,9 @@
|
|||||||
{% formfield form.new_password2 class='form-input' %}
|
{% formfield form.new_password2 class='form-input' %}
|
||||||
{{ form.new_password2.errors }}
|
{{ form.new_password2.errors }}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
|
||||||
<input type="submit"
|
<input type="submit"
|
||||||
value="Change Password"
|
value="Change Password"
|
||||||
class="btn btn-primary btn-wide">
|
class="btn btn-primary width-100 mt-4">
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -41,3 +41,43 @@ class LoginViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||||||
|
|
||||||
# should have turbo disabled
|
# should have turbo disabled
|
||||||
self.assertEqual("false", oidc_login_link.get("data-turbo"))
|
self.assertEqual("false", oidc_login_link.get("data-turbo"))
|
||||||
|
|
||||||
|
def test_should_show_login_form_by_default(self):
|
||||||
|
response = self.client.get("/login/")
|
||||||
|
soup = self.make_soup(response.content.decode())
|
||||||
|
|
||||||
|
form = soup.find("form", {"action": "/login/"})
|
||||||
|
username_input = soup.find("input", {"name": "username"})
|
||||||
|
password_input = soup.find("input", {"name": "password"})
|
||||||
|
submit_button = soup.find("input", {"type": "submit", "value": "Login"})
|
||||||
|
|
||||||
|
self.assertIsNotNone(form)
|
||||||
|
self.assertIsNotNone(username_input)
|
||||||
|
self.assertIsNotNone(password_input)
|
||||||
|
self.assertIsNotNone(submit_button)
|
||||||
|
|
||||||
|
@override_settings(LD_DISABLE_LOGIN_FORM=True)
|
||||||
|
def test_should_hide_login_form_when_disabled(self):
|
||||||
|
response = self.client.get("/login/")
|
||||||
|
soup = self.make_soup(response.content.decode())
|
||||||
|
|
||||||
|
form = soup.find("form", {"action": "/login/"})
|
||||||
|
username_input = soup.find("input", {"name": "username"})
|
||||||
|
password_input = soup.find("input", {"name": "password"})
|
||||||
|
submit_button = soup.find("input", {"type": "submit", "value": "Login"})
|
||||||
|
|
||||||
|
self.assertIsNone(form)
|
||||||
|
self.assertIsNone(username_input)
|
||||||
|
self.assertIsNone(password_input)
|
||||||
|
self.assertIsNone(submit_button)
|
||||||
|
|
||||||
|
@override_settings(LD_DISABLE_LOGIN_FORM=True, LD_ENABLE_OIDC=True)
|
||||||
|
def test_should_only_show_oidc_login_when_login_disabled_and_oidc_enabled(self):
|
||||||
|
response = self.client.get("/login/")
|
||||||
|
soup = self.make_soup(response.content.decode())
|
||||||
|
|
||||||
|
form = soup.find("form", {"action": "/login/"})
|
||||||
|
oidc_login_link = soup.find("a", string="Login with OIDC")
|
||||||
|
|
||||||
|
self.assertIsNone(form)
|
||||||
|
self.assertIsNotNone(oidc_login_link)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class LinkdingLoginView(auth_views.LoginView):
|
|||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
context["enable_oidc"] = settings.LD_ENABLE_OIDC
|
context["enable_oidc"] = settings.LD_ENABLE_OIDC
|
||||||
|
context["disable_login"] = settings.LD_DISABLE_LOGIN_FORM
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def form_invalid(self, form):
|
def form_invalid(self, form):
|
||||||
|
|||||||
@@ -179,6 +179,14 @@ identity_providers:
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### `LD_DISABLE_LOGIN_FORM`
|
||||||
|
|
||||||
|
Values: `True`, `False` | Default = `False`
|
||||||
|
|
||||||
|
Disables the login form on the login page.
|
||||||
|
This is useful when you want to enforce authentication through OIDC only.
|
||||||
|
When enabled, users will not be able to log in using their username and password, and only the "Login with OIDC" button will be shown on the login page.
|
||||||
|
|
||||||
### `LD_CSRF_TRUSTED_ORIGINS`
|
### `LD_CSRF_TRUSTED_ORIGINS`
|
||||||
|
|
||||||
Values: `String` | Default = None
|
Values: `String` | Default = None
|
||||||
|
|||||||
Reference in New Issue
Block a user