key management page
This commit is contained in:
parent
6ea17b4feb
commit
b64ed7ad63
|
@ -13,7 +13,7 @@ from .views import (
|
||||||
mfa_setup,
|
mfa_setup,
|
||||||
mfa_cancel,
|
mfa_cancel,
|
||||||
fido_setup,
|
fido_setup,
|
||||||
fido_cancel,
|
fido_manage,
|
||||||
domain_detail,
|
domain_detail,
|
||||||
lifetime_licence,
|
lifetime_licence,
|
||||||
directory,
|
directory,
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
{% extends 'default.html' %}
|
|
||||||
{% set active_page = "setting" %}
|
|
||||||
{% block title %}
|
|
||||||
Unlink Security Key
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block default_content %}
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
<h1 class="h2">Unlink Your Security Key</h1>
|
|
||||||
<p>
|
|
||||||
Please enter the password of your account so that we can ensure it's you.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<form method="post">
|
|
||||||
{{ password_check_form.csrf_token }}
|
|
||||||
|
|
||||||
<div class="font-weight-bold mt-5">Password</div>
|
|
||||||
|
|
||||||
{{ password_check_form.password(class="form-control", autofocus="true") }}
|
|
||||||
{{ render_field_errors(password_check_form.password) }}
|
|
||||||
<button class="btn btn-lg btn-danger mt-2">Unlink Key</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
{% extends 'default.html' %}
|
||||||
|
{% set active_page = "setting" %}
|
||||||
|
{% block title %}
|
||||||
|
Security Key Manage
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<script src="{{ url_for('static', filename='node_modules/qrious/dist/qrious.min.js') }}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block default_content %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h1 class="h2">Manage Your Security Key</h1>
|
||||||
|
<p>Delete all keys will also disable WebAuthn 2FA.</p>
|
||||||
|
|
||||||
|
<form id="formManageKey" method="post">
|
||||||
|
{{ fido_manage_form.csrf_token }}
|
||||||
|
{{ fido_manage_form.credential_id(class="form-control", placeholder="") }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">ID</th>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Linked At</th>
|
||||||
|
<th scope="col" class="text-center">Operation</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{%for key in keys%}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{ key.id }}</th>
|
||||||
|
<td>{{ key.name }}</td>
|
||||||
|
<td><script>document.write(new Date('{{ key.created_at }}').toLocaleString());</script></td>
|
||||||
|
<td class="text-center"><button class="btn btn-outline-danger" onclick="$('#credential_id').val('{{ key.credential_id }}'); $('#formManageKey').submit();">Delete</button></td>
|
||||||
|
</tr>
|
||||||
|
{%endfor%}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">#</th>
|
||||||
|
<td>Link a New Key</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="text-center"><a href="{{ url_for('dashboard.fido_setup') }}"><button class="btn btn-outline-success">Link</button></a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -97,7 +97,7 @@
|
||||||
{% if current_user.fido_uuid is none %}
|
{% if current_user.fido_uuid is none %}
|
||||||
<a href="{{ url_for('dashboard.fido_setup') }}" class="btn btn-outline-primary">Setup WebAuthn</a>
|
<a href="{{ url_for('dashboard.fido_setup') }}" class="btn btn-outline-primary">Setup WebAuthn</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('dashboard.fido_cancel') }}" class="btn btn-outline-danger">Disable WebAuthn</a>
|
<a href="{{ url_for('dashboard.fido_manage') }}" class="btn btn-outline-info">Manage WebAuthn</a>
|
||||||
<a href="{{ url_for('dashboard.recovery_code_route') }}" class="btn btn-outline-secondary">Recovery Codes</a>
|
<a href="{{ url_for('dashboard.recovery_code_route') }}" class="btn btn-outline-secondary">Recovery Codes</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
from flask import render_template, flash, redirect, url_for
|
|
||||||
from flask_login import login_required, current_user
|
|
||||||
from flask_wtf import FlaskForm
|
|
||||||
from wtforms import PasswordField, validators
|
|
||||||
|
|
||||||
from app.dashboard.base import dashboard_bp
|
|
||||||
from app.extensions import db
|
|
||||||
from app.models import RecoveryCode
|
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(FlaskForm):
|
|
||||||
password = PasswordField("Password", validators=[validators.DataRequired()])
|
|
||||||
|
|
||||||
|
|
||||||
@dashboard_bp.route("/fido_cancel", methods=["GET", "POST"])
|
|
||||||
@login_required
|
|
||||||
def fido_cancel():
|
|
||||||
if not current_user.fido_enabled():
|
|
||||||
flash("You haven't registed a security key", "warning")
|
|
||||||
return redirect(url_for("dashboard.index"))
|
|
||||||
|
|
||||||
password_check_form = LoginForm()
|
|
||||||
|
|
||||||
if password_check_form.validate_on_submit():
|
|
||||||
password = password_check_form.password.data
|
|
||||||
|
|
||||||
if current_user.check_password(password):
|
|
||||||
current_user.fido_pk = None
|
|
||||||
current_user.fido_uuid = None
|
|
||||||
current_user.fido_sign_count = None
|
|
||||||
current_user.fido_credential_id = None
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
# user does not have any 2FA enabled left, delete all recovery codes
|
|
||||||
if not current_user.two_factor_authentication_enabled():
|
|
||||||
RecoveryCode.empty(current_user)
|
|
||||||
|
|
||||||
flash("We've unlinked your security key.", "success")
|
|
||||||
return redirect(url_for("dashboard.index"))
|
|
||||||
else:
|
|
||||||
flash("Incorrect password", "warning")
|
|
||||||
|
|
||||||
return render_template(
|
|
||||||
"dashboard/fido_cancel.html", password_check_form=password_check_form
|
|
||||||
)
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
from flask import render_template, flash, redirect, url_for
|
||||||
|
from flask_login import login_required, current_user
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import HiddenField, validators
|
||||||
|
|
||||||
|
from app.dashboard.base import dashboard_bp
|
||||||
|
from app.extensions import db
|
||||||
|
from app.log import LOG
|
||||||
|
from app.models import RecoveryCode, FIDO
|
||||||
|
from app.dashboard.views.enter_sudo import sudo_required
|
||||||
|
|
||||||
|
|
||||||
|
class FidoManageForm(FlaskForm):
|
||||||
|
credential_id = HiddenField("credential_id", validators=[validators.DataRequired()])
|
||||||
|
|
||||||
|
|
||||||
|
@dashboard_bp.route("/fido_manage", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
@sudo_required
|
||||||
|
def fido_manage():
|
||||||
|
if not current_user.fido_enabled():
|
||||||
|
flash("You haven't registed a security key", "warning")
|
||||||
|
return redirect(url_for("dashboard.index"))
|
||||||
|
|
||||||
|
fido_manage_form = FidoManageForm()
|
||||||
|
|
||||||
|
if fido_manage_form.validate_on_submit():
|
||||||
|
credential_id = fido_manage_form.credential_id.data
|
||||||
|
|
||||||
|
fido_key = FIDO.get_by(uuid=current_user.fido_uuid, credential_id=credential_id)
|
||||||
|
|
||||||
|
if not fido_key:
|
||||||
|
flash("Unknown error, redirect back to manage page", "warning")
|
||||||
|
return redirect(url_for("dashboard.fido_manage"))
|
||||||
|
|
||||||
|
FIDO.delete(fido_key.id)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
LOG.d(f"FIDO Key ID={fido_key.id} Removed")
|
||||||
|
flash(f"Key {fido_key.name} successfully unlinked", "success")
|
||||||
|
|
||||||
|
# Disable FIDO for the user if all keys have been deleted
|
||||||
|
if not FIDO.filter_by(uuid=current_user.fido_uuid).all():
|
||||||
|
current_user.fido_uuid = None
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
# user does not have any 2FA enabled left, delete all recovery codes
|
||||||
|
if not current_user.two_factor_authentication_enabled():
|
||||||
|
RecoveryCode.empty(current_user)
|
||||||
|
|
||||||
|
return redirect(url_for("dashboard.index"))
|
||||||
|
|
||||||
|
return redirect(url_for("dashboard.fido_manage"))
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"dashboard/fido_manage.html",
|
||||||
|
fido_manage_form=fido_manage_form,
|
||||||
|
keys=FIDO.filter_by(uuid=current_user.fido_uuid),
|
||||||
|
)
|
|
@ -13,7 +13,7 @@ from app.config import RP_ID, URL
|
||||||
from app.dashboard.base import dashboard_bp
|
from app.dashboard.base import dashboard_bp
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.log import LOG
|
from app.log import LOG
|
||||||
from app.models import FIDO
|
from app.models import FIDO, RecoveryCode
|
||||||
from app.dashboard.views.enter_sudo import sudo_required
|
from app.dashboard.views.enter_sudo import sudo_required
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,7 +84,10 @@ def fido_setup():
|
||||||
)
|
)
|
||||||
|
|
||||||
flash("Security key has been activated", "success")
|
flash("Security key has been activated", "success")
|
||||||
return redirect(url_for("dashboard.recovery_code_route"))
|
if not RecoveryCode.query.filter_by(user_id=current_user.id).all():
|
||||||
|
return redirect(url_for("dashboard.recovery_code_route"))
|
||||||
|
else:
|
||||||
|
return redirect(url_for("dashboard.fido_manage"))
|
||||||
|
|
||||||
# Prepare information for key registration process
|
# Prepare information for key registration process
|
||||||
fido_uuid = (
|
fido_uuid = (
|
||||||
|
|
Loading…
Reference in New Issue