From b64ed7ad639f0ab27c752e2d6240718c10b597c6 Mon Sep 17 00:00:00 2001 From: devStorm <59678453+developStorm@users.noreply.github.com> Date: Mon, 18 May 2020 05:07:06 -0700 Subject: [PATCH] key management page --- app/dashboard/__init__.py | 2 +- .../templates/dashboard/fido_cancel.html | 28 --------- .../templates/dashboard/fido_manage.html | 53 +++++++++++++++++ .../templates/dashboard/setting.html | 2 +- app/dashboard/views/fido_cancel.py | 45 -------------- app/dashboard/views/fido_manage.py | 59 +++++++++++++++++++ app/dashboard/views/fido_setup.py | 7 ++- 7 files changed, 119 insertions(+), 77 deletions(-) delete mode 100644 app/dashboard/templates/dashboard/fido_cancel.html create mode 100644 app/dashboard/templates/dashboard/fido_manage.html delete mode 100644 app/dashboard/views/fido_cancel.py create mode 100644 app/dashboard/views/fido_manage.py diff --git a/app/dashboard/__init__.py b/app/dashboard/__init__.py index 16ca9962..fc216406 100644 --- a/app/dashboard/__init__.py +++ b/app/dashboard/__init__.py @@ -13,7 +13,7 @@ from .views import ( mfa_setup, mfa_cancel, fido_setup, - fido_cancel, + fido_manage, domain_detail, lifetime_licence, directory, diff --git a/app/dashboard/templates/dashboard/fido_cancel.html b/app/dashboard/templates/dashboard/fido_cancel.html deleted file mode 100644 index 0df4c53d..00000000 --- a/app/dashboard/templates/dashboard/fido_cancel.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends 'default.html' %} -{% set active_page = "setting" %} -{% block title %} - Unlink Security Key -{% endblock %} - - -{% block default_content %} -
-
-

Unlink Your Security Key

-

- Please enter the password of your account so that we can ensure it's you. -

- -
- {{ password_check_form.csrf_token }} - -
Password
- - {{ password_check_form.password(class="form-control", autofocus="true") }} - {{ render_field_errors(password_check_form.password) }} - -
- -
-
-{% endblock %} \ No newline at end of file diff --git a/app/dashboard/templates/dashboard/fido_manage.html b/app/dashboard/templates/dashboard/fido_manage.html new file mode 100644 index 00000000..3f76c159 --- /dev/null +++ b/app/dashboard/templates/dashboard/fido_manage.html @@ -0,0 +1,53 @@ +{% extends 'default.html' %} +{% set active_page = "setting" %} +{% block title %} + Security Key Manage +{% endblock %} + +{% block head %} + +{% endblock %} + +{% block default_content %} +
+
+

Manage Your Security Key

+

Delete all keys will also disable WebAuthn 2FA.

+ +
+ {{ fido_manage_form.csrf_token }} + {{ fido_manage_form.credential_id(class="form-control", placeholder="") }} +
+ + + + + + + + + + + + {%for key in keys%} + + + + + + + {%endfor%} + + + + + + + +
IDNameLinked AtOperation
{{ key.id }}{{ key.name }}
#Link a New Key
+ + + +
+
+{% endblock %} diff --git a/app/dashboard/templates/dashboard/setting.html b/app/dashboard/templates/dashboard/setting.html index b4e1eb8e..d0c66a2d 100644 --- a/app/dashboard/templates/dashboard/setting.html +++ b/app/dashboard/templates/dashboard/setting.html @@ -97,7 +97,7 @@ {% if current_user.fido_uuid is none %} Setup WebAuthn {% else %} - Disable WebAuthn + Manage WebAuthn Recovery Codes {% endif %} diff --git a/app/dashboard/views/fido_cancel.py b/app/dashboard/views/fido_cancel.py deleted file mode 100644 index 621aa6f5..00000000 --- a/app/dashboard/views/fido_cancel.py +++ /dev/null @@ -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 - ) diff --git a/app/dashboard/views/fido_manage.py b/app/dashboard/views/fido_manage.py new file mode 100644 index 00000000..f4b46573 --- /dev/null +++ b/app/dashboard/views/fido_manage.py @@ -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), + ) diff --git a/app/dashboard/views/fido_setup.py b/app/dashboard/views/fido_setup.py index 2dd4506c..3b86c0c9 100644 --- a/app/dashboard/views/fido_setup.py +++ b/app/dashboard/views/fido_setup.py @@ -13,7 +13,7 @@ from app.config import RP_ID, URL from app.dashboard.base import dashboard_bp from app.extensions import db 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 @@ -84,7 +84,10 @@ def fido_setup(): ) 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 fido_uuid = (