Skip to content
Snippets Groups Projects
Commit 790fe873 authored by Julian's avatar Julian
Browse files

added login_required to auth_webauthn_* and implemented pre-mfa-session timeout

parent f32460b6
Branches
Tags
No related merge requests found
......@@ -50,8 +50,16 @@ function begin_webauthn() {
fetch({{ url_for('mfa.auth_webauthn_begin')|tojson }}, {
method: 'POST',
}).then(function(response) {
if(response.ok) return response.arrayBuffer();
if (response.ok) {
return response.arrayBuffer();
} else if (response.status == 403) {
window.location = {{ request.url|tojson }}; /* reload */
throw new Error('Session timed out');
} else if (response.status == 404) {
throw new Error('You have not registered any U2F/FIDO2 devices for your account');
} else {
throw new Error('Server error');
}
}).then(CBOR.decode).then(function(options) {
$('#webauthn-btn-text').text('Waiting for response from your device');
return navigator.credentials.get(options);
......@@ -72,10 +80,13 @@ function begin_webauthn() {
$('#webauthn-spinner').addClass('d-none');
$('#webauthn-btn-text').text('Success, redirecting');
window.location = {{ (ref or url_for('index'))|tojson }};
} else if (response.status == 403) {
window.location = {{ request.url|tojson }}; /* reload */
throw new Error('Session timed out');
} else {
throw new Error('Response from authenticator rejected');
}
}, function(err) {
}).catch(function(err) {
console.log(err);
/* various webauthn errors */
if (err.name == 'NotAllowedError')
......
......@@ -5,7 +5,7 @@ from flask import Blueprint, render_template, session, request, redirect, url_fo
from uffd.database import db
from uffd.mfa.models import MFAMethod, TOTPMethod, WebauthnMethod, RecoveryCodeMethod
from uffd.session.views import get_current_user, login_required
from uffd.session.views import get_current_user, login_required, pre_mfa_login_required
from uffd.ldap import uid_to_dn
from uffd.user.models import User
from uffd.csrf import csrf_protect
......@@ -156,6 +156,7 @@ if WEBAUTHN_SUPPORTED:
return cbor.dumps({"status": "OK"})
@bp.route("/auth/webauthn/begin", methods=["POST"])
@pre_mfa_login_required(no_redirect=True)
def auth_webauthn_begin():
user = get_current_user()
server = get_webauthn_server()
......@@ -168,6 +169,7 @@ if WEBAUTHN_SUPPORTED:
return cbor.dumps(auth_data)
@bp.route("/auth/webauthn/complete", methods=["POST"])
@pre_mfa_login_required(no_redirect=True)
def auth_webauthn_complete():
user = get_current_user()
server = get_webauthn_server()
......@@ -204,7 +206,7 @@ def delete_webauthn(id): #pylint: disable=redefined-builtin
return redirect(url_for('mfa.setup'))
@bp.route('/auth', methods=['GET'])
@login_required(skip_mfa=True)
@pre_mfa_login_required()
def auth():
user = get_current_user()
recovery_methods = RecoveryCodeMethod.query.filter_by(dn=user.dn).all()
......@@ -218,7 +220,7 @@ def auth():
webauthn_methods=webauthn_methods, recovery_methods=recovery_methods)
@bp.route('/auth', methods=['POST'])
@login_required(skip_mfa=True)
@pre_mfa_login_required()
def auth_finish():
user = get_current_user()
recovery_methods = RecoveryCodeMethod.query.filter_by(dn=user.dn).all()
......
......@@ -2,7 +2,7 @@ import datetime
import secrets
import functools
from flask import Blueprint, render_template, request, url_for, redirect, flash, current_app, session
from flask import Blueprint, render_template, request, url_for, redirect, flash, current_app, session, abort
from uffd.user.models import User
from uffd.ldap import user_conn, uid_to_dn
......@@ -59,15 +59,28 @@ def is_valid_session():
return True
bp.add_app_template_global(is_valid_session)
def login_required(group=None, skip_mfa=False):
def pre_mfa_login_required(no_redirect=False):
def wrapper(func):
@functools.wraps(func)
def decorator(*args, **kwargs):
if not login_valid() or datetime.datetime.now().timestamp() > session['logintime'] + 10*60:
session.clear()
if no_redirect:
abort(403)
flash('You need to login first')
return redirect(url_for('session.login', ref=request.url))
return func(*args, **kwargs)
return decorator
return wrapper
def login_required(group=None):
def wrapper(func):
@functools.wraps(func)
def decorator(*args, **kwargs):
if not login_valid():
flash('You need to login first')
return redirect(url_for('session.login', ref=request.url))
if not skip_mfa and not session.get('user_mfa'):
print('redirecting login_required', skip_mfa, session.get('user_mfa'))
if not session.get('user_mfa'):
return redirect(url_for('mfa.auth', ref=request.url))
if not get_current_user().is_in_group(group):
flash('Access denied')
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment