From 40ac403fd248723c422bfb6cde7ac35d094ce709 Mon Sep 17 00:00:00 2001 From: Arie Peterson <arie@greenhost.nl> Date: Thu, 5 Oct 2023 17:07:32 +0200 Subject: [PATCH] Make it possible to enforce 2FA --- backend/config.py | 1 + backend/web/login/login.py | 19 +++++++++++++++++++ backend/web/static/base.js | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/backend/config.py b/backend/config.py index 04039e5a..7f9c276e 100644 --- a/backend/config.py +++ b/backend/config.py @@ -24,3 +24,4 @@ LOAD_INCLUSTER_CONFIG = os.environ.get("LOAD_INCLUSTER_CONFIG").lower() == "true RUN_BY_GUNICORN = "gunicorn" in os.environ.get("SERVER_SOFTWARE", "") DEMO_INSTANCE = os.environ.get("DASHBOARD_DEMO_INSTANCE", "False").lower() in ('true', '1') +ENFORCE_2FA = os.environ.get("DASHBOARD_ENFORCE_2FA", "False").lower() in ('true', '1') diff --git a/backend/web/login/login.py b/backend/web/login/login.py index 6947038e..71117746 100644 --- a/backend/web/login/login.py +++ b/backend/web/login/login.py @@ -17,6 +17,7 @@ from ory_hydra_client.models import AcceptConsentRequest, AcceptLoginRequest, Co import ory_hydra_client.exceptions as hydra_exceptions import ory_kratos_client from ory_kratos_client.api import frontend_api, identity_api +from ory_kratos_client.model.authenticator_assurance_level import AuthenticatorAssuranceLevel from flask import abort, current_app, jsonify, redirect, render_template, request from database import db @@ -335,6 +336,24 @@ def consent(): current_app.logger.error(f"Conflict. Consent request {challenge} already used") abort(503, description="Consent request already used. Please try again") + if ENFORCE_2FA: + # Check for session status, in particular 2FA. + cookie = get_kratos_cookie() + if not cookie: + current_app.logger.info("consent: no kratos cookie set, redirecting to set up 2fa") + response = redirect(KRATOS_PUBLIC_URL + "self-service/settings/browser") + response.set_cookie('stackspin_context', '2fa-required') + return response + session = kratos_public_frontend_api.to_session(cookie=cookie) + # Check session aal. + aal = session['authenticator_assurance_level'] + current_app.logger.info(f"aal: {aal}") + if aal == AuthenticatorAssuranceLevel('aal1'): + current_app.logger.info("aal is only aal1, so not accepting consent request") + response = redirect(KRATOS_PUBLIC_URL + "self-service/settings/browser") + response.set_cookie('stackspin_context', '2fa-required') + return response + # Get information about this consent request: # False positive: pylint: disable=no-member try: diff --git a/backend/web/static/base.js b/backend/web/static/base.js index bf79733c..d362b579 100644 --- a/backend/web/static/base.js +++ b/backend/web/static/base.js @@ -218,6 +218,16 @@ function flow_settings() { $('#pills-password-tab').tab('show'); Cookies.set('stackspin_context', ''); } + + // If the user is required to set up 2FA, switch to + // that tab and show a message. + if (context == "2fa-required") { + $('#pills-totp-tab').tab('show'); + $("#contentMessages").html('Setting up a second factor is required to continue.'); + $("#contentMessages").addClass("alert"); + $("#contentMessages").addClass("alert-warning"); + Cookies.set('stackspin_context', ''); + } }, complete: function (obj) { // If we get a 410, the flow is expired, need to refresh the flow -- GitLab