Skip to content
Snippets Groups Projects
Unverified Commit 782b7412 authored by f00wl's avatar f00wl
Browse files

(fix #89): Rewrite TOTP setup mechanism

* enable TOTP now require code validation
* once TOTP enabled qrcode and key are not visibles anymore
* once TOTP enabled add TOTP check capability
parent 41da9722
No related branches found
No related tags found
1 merge request!50Resolve "Activation de la 2FA avec TOTP et interface utilisateurice"
Pipeline #24166 passed
......@@ -33,43 +33,61 @@ def password():
@security.authentication_required()
def totp():
user = flask_login.current_user
if models.Auth.TOTP in user.auths:
key = user.auths[models.Auth.TOTP].value
issuer = flask.current_app.config['WEBSITE_NAME']
totp_uri = pyotp.totp.TOTP(key).provisioning_uri(
name=user.username,
issuer_name=issuer)
img = qrcode.make(totp_uri).get_image()
buffered = BytesIO()
img.save(buffered, format="PNG")
qr = base64.b64encode(buffered.getvalue()).decode('ascii')
return flask.render_template(
"account_auth_totp.html",
key=key, name=user.username, issuer=issuer, qr=qr
)
return flask.render_template("account_auth_totp.html")
form = forms.TotpForm()
if form.validate_on_submit():
if user.auths[models.Auth.TOTP].check_totp(form.totp.data):
flask.flash(_("TOTP is valid"), "success")
return flask.redirect(flask.url_for(".totp"))
else:
flask.flash(_("Invalid or expired TOTP, try again or disable and re-enable TOTP to reset your private key"), "danger")
return flask.redirect(flask.url_for(".totp"))
enabled = models.Auth.TOTP in user.auths and user.auths[models.Auth.TOTP].enabled
return flask.render_template("account_auth_totp.html", form=form, enabled=enabled)
@blueprint.route("/auth/totp/setup", methods=["GET", "POST"])
@blueprint.route("/auth/totp/enable", methods=["GET", "POST"])
@security.authentication_required()
@security.confirmation_required("setup TOTP")
def totp_setup():
def totp_enable():
user = flask_login.current_user
auth = models.Auth(models.Auth.TOTP)
auth.set_otp_key()
user.auths[models.Auth.TOTP] = auth
models.log(models.History.MFA, comment=str(_("TOTP has been enabled")),
user=flask_login.current_user)
models.db.session.add(auth)
models.db.session.commit()
flask.flash(_("Successfully setup TOTP"), "success")
return flask.redirect(flask.url_for(".totp"))
if models.Auth.TOTP not in user.auths:
auth = models.Auth(models.Auth.TOTP)
auth.set_otp_key()
user.auths[models.Auth.TOTP] = auth
models.db.session.add(auth)
models.db.session.commit()
key = user.auths[models.Auth.TOTP].value
issuer = flask.current_app.config['WEBSITE_NAME']
totp_uri = pyotp.totp.TOTP(key).provisioning_uri(
name=user.username,
issuer_name=issuer)
img = qrcode.make(totp_uri).get_image()
buffered = BytesIO()
img.save(buffered, format="PNG")
qr = base64.b64encode(buffered.getvalue()).decode('ascii')
form = forms.TotpForm()
if form.validate_on_submit():
if user.auths[models.Auth.TOTP].check_totp(form.totp.data):
models.log(models.History.MFA, comment=str(_("TOTP has been enabled")),
user=user)
user.auths[models.Auth.TOTP].enabled = True
models.db.session.add(user)
models.db.session.commit()
flask.flash(_("Successfully enabled TOTP"), "success")
return flask.redirect(flask.url_for(".totp"))
else:
flask.flash(_("Failed to enable TOTP, wrong TOTP"), "danger")
return flask.redirect(flask.url_for(".totp_enable"))
flask.flash(_("Fill-in the form to confirm your TOTP client is working"), "warning")
return flask.render_template(
"account_auth_totp_enable.html",
key=key, name=user.username, issuer=issuer, qr=qr, form=form
)
@blueprint.route("/auth/totp/delete", methods=["GET", "POST"])
@blueprint.route("/auth/totp/disable", methods=["GET", "POST"])
@security.authentication_required()
@security.confirmation_required("disable TOTP")
def totp_delete():
def totp_disable():
user = flask_login.current_user
auth = user.auths[models.Auth.TOTP]
models.log(models.History.MFA, comment=str(_("TOTP has been disabled")),
......
......@@ -4,52 +4,39 @@
{% block subtitle %}{% trans %}with Time-based One-Time Password (TOTP){% endtrans %}{% endblock %}
{% block content %}
{% if not key %}
{% if enabled %}
<div class="col">
<blockquote class="quote-warning">
<h5>{% trans %}Not configured{% endtrans %}</h5>
<p>{% trans %}Two-factor authentication with Time-based One-Time Passowrd is not setup.{% endtrans %}
<blockquote class="quote-info">
<h5>{% trans %}Enabled{% endtrans %}</h5>
<p>{% trans %}Two-factor authentication with Time-based One-Time Passowrd is enabled. Use the form below to test your TOTP client configuration{% endtrans %}
<br>
{% trans %}Click on "Setup TOTP" to get started.{% endtrans %}
{% trans %}Click on "Disable TOTP" to disable TOTP.{% endtrans %}
</p>
</blockquote>
<div class="row">
{{ macros.form(form) }}
</div>
</div>
{% else %}
<blockquote class="quote-info">
<h5>{% trans %}Howto{% endtrans %}</h5>
<p>{% trans %}Scan this QR code or use text informations{% endtrans %}</p>
<h5>{% trans %}Disabled{% endtrans %}</h5>
<p>{% trans %}Two-factor authentication with Time-based One-Time Passowrd is disabled.{% endtrans %}
<br>
<p>{% trans %}Click on "Enable TOTP" to enable TOTP{% endtrans %}</p>
</blockquote>
<div class="row">
<div class="col-md-6 col text-center">
<img src="data:image/png;base64,{{ qr }}" class="rounded mb-4" width=250 height=250>
</div>
<div class="col-md-6 col">
<ul class="list-group", style="max-width: 500px">
<li class="list-group-item d-flex justify-content-between">
{% trans %}Secret key{% endtrans %}<code>{{ key }}</code>
</li>
<li class="list-group-item d-flex justify-content-between">
{% trans %}Name{% endtrans %}<code>{{ name }}</code>
</li>
<li class="list-group-item d-flex justify-content-between">
{% trans %}Issuer{% endtrans %}<code>{{ issuer }}</code>
</li>
</ul>
</div>
</div>
{% endif %}
{% endblock %}
{% block actions %}
{% if not key %}
{% if enabled %}
<a href="{{ url_for(".totp_setup") }}" class="btn btn-info">{% trans %}Setup TOTP{% endtrans %}</a>
<a href="{{ url_for(".totp_disable") }}" class="btn btn-warning">{% trans %}Disable TOTP{% endtrans %}</a>
{% else %}
<a href="{{ url_for(".totp_delete") }}" class="btn btn-warning">{% trans %}Delete TOTP{% endtrans %}</a>
<a href="{{ url_for(".totp_enable") }}" class="btn btn-info">{% trans %}Enable TOTP{% endtrans %}</a>
{% endif %}
{% endblock %}
{% extends "base.html" %}
{% block title %} {% trans %}Two-factor authentication{% endtrans %} {% endblock %}
{% block subtitle %}{% trans %}with Time-based One-Time Password (TOTP){% endtrans %}{% endblock %}
{% block content %}
<blockquote class="quote-info">
<h5>{% trans %}Howto{% endtrans %}</h5>
<p>{% trans %}Scan this QR code or use text informations to configure a TOTP client{% endtrans %}</p>
</blockquote>
<div class="row">
<div class="col-md-6 col text-center">
<img src="data:image/png;base64,{{ qr }}" class="rounded mb-4" width=250 height=250>
</div>
<div class="col-md-6 col">
<ul class="list-group", style="max-width: 500px">
<li class="list-group-item d-flex justify-content-between">
{% trans %}Secret key{% endtrans %}<code>{{ key }}</code>
</li>
<li class="list-group-item d-flex justify-content-between">
{% trans %}Name{% endtrans %}<code>{{ name }}</code>
</li>
<li class="list-group-item d-flex justify-content-between">
{% trans %}Issuer{% endtrans %}<code>{{ issuer }}</code>
</li>
</ul>
</div>
{{ macros.form(form) }}
</div>
{% endblock %}
{% block actions %}
<a href="{{ url_for(".totp_disable") }}" class="btn btn-warning">{% trans %}Cancel{% endtrans %}</a>
{% endblock %}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment