Merge branch 'issue-99-disable-password-recovery' into 'master'

Added an option to disable password recovery

Closes #99

See merge request yaal/canaille!46
This commit is contained in:
Éloi Rivard 2022-04-05 07:59:25 +00:00
commit 6ef0766acf
10 changed files with 48 additions and 4 deletions

View file

@ -3,7 +3,16 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_,
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
[0.0.7] - 2022-03-15
[0.0.9] - 2022-xx-xx
====================
Added
*****
- ``DISABLE_PASSWORD_RESET`` configuration option to disable password recovery. :pr:`46`
[0.0.8] - 2022-03-15
====================
Fixed

View file

@ -179,6 +179,9 @@ def create_app(config=None, validate=True):
return {
"has_smtp": "SMTP" in app.config,
"has_password_recovery": app.config.get(
"ENABLE_PASSWORD_RECOVERY", True
),
"logo_url": app.config.get("LOGO"),
"favicon_url": app.config.get("FAVICON", app.config.get("LOGO")),
"website_name": app.config.get("NAME", "Canaille"),

View file

@ -526,6 +526,9 @@ def impersonate(user, username):
@bp.route("/reset", methods=["GET", "POST"])
@smtp_needed()
def forgotten():
if not current_app.config.get("ENABLE_PASSWORD_RECOVERY", True):
abort(404)
form = ForgottenPasswordForm(request.form)
if not request.form:
return render_template("forgotten-password.html", form=form)
@ -562,6 +565,9 @@ def forgotten():
@bp.route("/reset/<uid>/<hash>", methods=["GET", "POST"])
def reset(uid, hash):
if not current_app.config.get("ENABLE_PASSWORD_RECOVERY", True):
abort(404)
form = PasswordResetForm(request.form)
user = User.get(uid)

View file

@ -40,6 +40,10 @@ OIDC_METADATA_FILE = "canaille/conf/openid-configuration.json"
# wether the login exists or not.
# HIDE_INVALID_LOGINS = false
# If ENABLE_PASSWORD_RECOVERY is false, then users cannot ask for a password
# recovery link by email. This option is true by default.
# ENABLE_PASSWORD_RECOVERY = true
# The validity duration of registration invitations, in seconds.
# Defaults to 2 days
# INVITATION_EXPIRATION = 172800

View file

@ -34,7 +34,7 @@
<div class="ui right aligned container">
<div class="ui stackable buttons">
{% if has_smtp %}
{% if has_smtp and has_password_recovery %}
<a type="button" class="ui right floated button" href="{{ url_for('account.forgotten') }}">{{ _("Forgotten password") }}</a>
{% endif %}
<button type="submit" class="ui right floated primary button">{{ _("Continue") }}</button>

View file

@ -31,7 +31,7 @@
<div class="ui right aligned container">
<div class="ui stackable buttons">
<a type="button" class="ui right floated button" href="{{ url_for('account.login') }}">{{ _("I am not %(username)s", username=username) }}</a>
{% if has_smtp %}
{% if has_smtp and has_password_recovery %}
<a type="button" class="ui right floated button" href="{{ url_for('account.forgotten') }}">{{ _("Forgotten password") }}</a>
{% endif %}
<button type="submit" class="ui right floated primary button">{{ _("Sign in") }}</button>

View file

@ -40,6 +40,10 @@ OIDC_METADATA_FILE = "conf/openid-configuration.json"
# wether the login exists or not.
# HIDE_INVALID_LOGINS = false
# If ENABLE_PASSWORD_RECOVERY is false, then users cannot ask for a password
# recovery link by email. This option is true by default.
# ENABLE_PASSWORD_RECOVERY = true
# The validity duration of registration invitations, in seconds.
# Defaults to 2 days
# INVITATION_EXPIRATION = 172800

View file

@ -40,6 +40,10 @@ OIDC_METADATA_FILE = "conf/openid-configuration.json"
# wether the login exists or not.
# HIDE_INVALID_LOGINS = false
# If ENABLE_PASSWORD_RECOVERY is false, then users cannot ask for a password
# recovery link by email. This option is true by default.
# ENABLE_PASSWORD_RECOVERY = true
# The validity duration of registration invitations, in seconds.
# Defaults to 2 days
# INVITATION_EXPIRATION = 172800

View file

@ -49,7 +49,11 @@ Canaille is based on Flask, so any `flask configuration <https://flask.palletspr
:HIDE_INVALID_LOGINS:
*Optional.* Wether to tell the users if a username exists during failing login attempts.
Defaults to ``True``. This may be a security issue to disable this, as this give a way to malicious people to guess who has an account on this canaille instance.
Defaults to ``True``. This may be a security issue to disable this, as this give a way to malicious people to if an account exists on this canaille instance.
:ENABLE_PASSWORD_RECOVERY:
*Optional* Wether the password recovery feature is enabled or not.
Defaults to ``True``.
:INVITATION_EXPIRATION:
*Optional* The validity duration of registration invitations, in seconds.

View file

@ -1,3 +1,13 @@
def test_password_forgotten_disabled(smtpd, testclient, slapd_connection, user):
testclient.app.config["ENABLE_PASSWORD_RECOVERY"] = False
testclient.get("/reset", status=404)
testclient.get("/reset/uid/hash", status=404)
res = testclient.get("/login")
assert "Forgotten password" not in res.text
def test_password_forgotten(smtpd, testclient, slapd_connection, user):
res = testclient.get("/reset", status=200)