Added autofido2fa option in PasswordRequirements, #2952
Ylian Saint-Hilaire committed
Jul 28, 2021 at 10:35 UTC
15ddd3cd00e1cb3fbcd5fa53716743017f1906f0
5 files changed
+30
-5
meshcentral-config-schema.json
+2
-1
@@ -385,7 +385,8 @@
385
"oldPasswordBan": { "type": "integer", "description": "Number of old passwords the server should remember and not allow the user to switch back to." },
386
"banCommonPasswords": { "type": "boolean", "default": false, "description": "Uses WildLeek to block use of the 10000 most commonly used passwords." },
387
"loginTokens": { "type": "boolean", "default": true, "description": "Allows users to create alternative username/passwords for their account." },
388
- "twoFactorTimeout": { "type": "integer", "default": 300, "description": "Maximum about of time the to wait for a 2FA token on the login page in seconds." }
388
+ "twoFactorTimeout": { "type": "integer", "default": 300, "description": "Maximum about of time the to wait for a 2FA token on the login page in seconds." },
389
+ "autofido2fa": { "type": "boolean", "default": false, "description": "If true and user account has FIDO key setup, 2FA login screen will automatically request FIDO 2FA." }
390
}
391
},
392
"twoFactorCookieDurationDays": { "type": "integer", "default": 30, "description": "Number of days that a user is allowed to remember this device for when completing 2FA. Set this to 0 to remove this option." },
views/login-mobile.handlebars
+8
-2
@@ -324,6 +324,7 @@
324
var currentpanel = 0;
325
var otpemail = ('{{{otpemail}}}' === 'true');
326
var otpsms = ('{{{otpsms}}}' === 'true');
327
+ var autofido = (decodeURIComponent('{{{autofido}}}') === 'true');
328
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
329
var authStrategies = '{{{authStrategies}}}'.split(',');
330
var tokenTimeout = parseInt('{{{tokenTimeout}}}');
@@ -405,15 +406,20 @@
406
if (loginMode == '4') {
407
if (tokenTimeout > 0) { setTimeout(function () { Q('hwtokenInput').value = '**timeout**'; QE('tokenOkButton', true); Q('tokenOkButton').click(); }, tokenTimeout); }
408
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
408
- QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
409
+ var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
410
+ QV('securityKeyButton', twofakey);
411
QV('emailKeyButton', otpemail && (messageid != 2) && (messageid != 4));
412
QV('smsKeyButton', otpsms && (messageid != 2) && (messageid != 4));
413
+
414
+ // If hardware key is an option, trigger it now
415
+ if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); }
416
}
417
418
if (loginMode == '5') {
419
if (tokenTimeout > 0) { setTimeout(function () { Q('hwtokenInput').value = '**timeout**'; QE('tokenOkButton', true); Q('tokenOkButton').click(); }, tokenTimeout); }
420
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
416
- if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
421
+ var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
422
+ if (twofakey) {
423
if (typeof hardwareKeyChallenge.challenge == 'string') { hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer; }
424
425
publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
views/login.handlebars
+11
-2
@@ -323,6 +323,7 @@
323
var publicKeyCredentialRequestOptions = null;
324
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
325
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
326
+ var autofido = (decodeURIComponent('{{{autofido}}}') === 'true');
327
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
328
var authStrategies = '{{{authStrategies}}}'.split(',');
329
var tokenTimeout = parseInt('{{{tokenTimeout}}}');
@@ -435,17 +436,25 @@
436
if (loginMode == '4') {
437
if (tokenTimeout > 0) { setTimeout(function () { Q('hwtokenInput').value = '**timeout**'; QE('tokenOkButton', true); Q('tokenOkButton').click(); }, tokenTimeout); }
438
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
438
- QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
439
+ var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
440
+ QV('securityKeyButton', twofakey);
441
QV('emailKeyButton', otpemail && (messageid != 2) && (messageid != 4));
442
QV('smsKeyButton', otpsms && (messageid != 2) && (messageid != 4));
443
+
444
+ // If hardware key is an option, trigger it now
445
+ if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); }
446
}
447
448
if (loginMode == '5') {
449
if (tokenTimeout > 0) { setTimeout(function () { Q('hwtokenInput').value = '**timeout**'; QE('tokenOkButton', true); Q('tokenOkButton').click(); }, tokenTimeout); }
450
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
446
- QV('securityKeyButton2', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
451
+ var twofakey = (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn');
452
+ QV('securityKeyButton2', twofakey);
453
QV('emailKeyButton2', otpemail && (messageid != 2) && (messageid != 4));
454
QV('smsKeyButton2', otpsms && (messageid != 2) && (messageid != 4));
455
+
456
+ // If hardware key is an option, trigger it now
457
+ if (autofido && twofakey) { setTimeout(function () { useSecurityKey(2); }, 300); }
458
}
459
460
/*
views/login2.handlebars
+7
@@ -356,6 +356,7 @@
356
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
357
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
358
var otppush = (decodeURIComponent('{{{otppush}}}') === 'true');
359
+ var autofido = (decodeURIComponent('{{{autofido}}}') === 'true');
360
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
361
var authStrategies = '{{{authStrategies}}}'.split(',');
362
var tokenTimeout = parseInt('{{{tokenTimeout}}}');
@@ -475,6 +476,9 @@
476
QV('smsKeyButton', smskey);
477
QV('pushKeyButton', pushkey);
478
QV('2farow', twofakey || emailkey || smskey || pushkey);
479
+
480
+ // If hardware key is an option, trigger it now
481
+ if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); }
482
}
483
484
if (loginMode == '5') {
@@ -489,6 +493,9 @@
493
QV('smsKeyButton2', smskey);
494
QV('pushKeyButton', pushkey);
495
QV('2farow2', twofakey || emailkey || smskey || pushkey);
496
+
497
+ // If hardware key is an option, trigger it now
498
+ if (autofido && twofakey) { setTimeout(function () { useSecurityKey(2); }, 300); }
499
}
500
501
if (loginMode == '8') {
webserver.js
+2
@@ -2863,6 +2863,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2863
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; }
2864
var otppush = (parent.firebase != null) && (req.session != null) && (req.session.tpush === 1);
2865
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.push2factor == false)) { otppush = false; }
2866
+ const autofido = ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.autofido2fa == true)); // See if FIDO should be automatically prompted if user account has it.
2867
2868
// See if we support two-factor trusted cookies
2869
var twoFactorCookieDays = 30;
@@ -2917,6 +2918,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2918
otpemail: otpemail,
2919
otpsms: otpsms,
2920
otppush: otppush,
2921
+ autofido: autofido,
2922
twoFactorCookieDays: twoFactorCookieDays,
2923
authStrategies: authStrategies.join(','),
2924
loginpicture: (typeof domain.loginpicture == 'string'),