Doc updates & minor code cleanup
This commit is contained in:
parent
f02434bc23
commit
b5a3c030ab
|
@ -5,7 +5,8 @@ This document attempts to track **major** changes and additions in ENiGMA½. For
|
||||||
+ `oputil.js user rename USERNAME NEWNAME`
|
+ `oputil.js user rename USERNAME NEWNAME`
|
||||||
+ `my_messages.js` module (defaulted to "m" at the message menu) to list public messages addressed to the currently logged in user. Takes into account their username and `real_name` property.
|
+ `my_messages.js` module (defaulted to "m" at the message menu) to list public messages addressed to the currently logged in user. Takes into account their username and `real_name` property.
|
||||||
+ SSH Public Key Authentication has been added. The system uses a OpenSSH style public key set on the `ssh_public_key` user property.
|
+ SSH Public Key Authentication has been added. The system uses a OpenSSH style public key set on the `ssh_public_key` user property.
|
||||||
+ 2-Factor (2FA) authentication is now available using [RFC-4266 - HOTP: HMAC-Based One-Time Password Algorithm)](https://tools.ietf.org/html/rfc4226), [RFC-6238 - TOTP: Time-Based One-Time Password Algorithm](https://tools.ietf.org/html/rfc6238), or [Google Authenticator](http://google-authenticator.com/). QR codes for activation are available as well. One-time backup aka recovery codes can also be used.
|
+ 2-Factor (2FA) authentication is now available using [RFC-4266 - HOTP: HMAC-Based One-Time Password Algorithm)](https://tools.ietf.org/html/rfc4226), [RFC-6238 - TOTP: Time-Based One-Time Password Algorithm](https://tools.ietf.org/html/rfc6238), or [Google Authenticator](http://google-authenticator.com/). QR codes for activation are available as well. One-time backup aka recovery codes can also be used. See [Security](/docs/configuration/security.md) for more info!
|
||||||
|
* New ACS codes for new 2FA/OTP: `AR` and `AF`. See [ACS](/docs/configuration/acs.md) for details.
|
||||||
+ `oputil.js user 2fa USERNAME TYPE` enables 2-factor authentication for a user.
|
+ `oputil.js user 2fa USERNAME TYPE` enables 2-factor authentication for a user.
|
||||||
* `oputil.js user info USERNAME --security` can now display additional security information such as 2FA/OTP.
|
* `oputil.js user info USERNAME --security` can now display additional security information such as 2FA/OTP.
|
||||||
* `oputil.js fb scan --quick` is now the default. Override with `--full-scan`.
|
* `oputil.js fb scan --quick` is now the default. Override with `--full-scan`.
|
||||||
|
|
|
@ -40,6 +40,14 @@ const MciViewIds = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const DefaultMsg = {
|
const DefaultMsg = {
|
||||||
|
infoText: {
|
||||||
|
disabled : 'Enabling 2-Factor Authentication via One-Time-Password can greatly increase the security of your account.',
|
||||||
|
enabled : 'A valid email address set in user config is required to enable 2-Factor Authentication.',
|
||||||
|
rfc6238_TOTP : 'Time-Based One-Time-Password (TOTP, RFC-6238).',
|
||||||
|
rfc4266_HOTP : 'HMAC-Based One-Time-Passowrd (HOTP, RFC-4266).',
|
||||||
|
googleAuth : 'Google Authenticator.',
|
||||||
|
},
|
||||||
|
statusText : {
|
||||||
otpNotEnabled : '2FA/OTP is not currently enabled for this account.',
|
otpNotEnabled : '2FA/OTP is not currently enabled for this account.',
|
||||||
noBackupCodes : 'No backup codes remaining or set.',
|
noBackupCodes : 'No backup codes remaining or set.',
|
||||||
saveDisabled : '2FA/OTP is now disabled for this account.',
|
saveDisabled : '2FA/OTP is now disabled for this account.',
|
||||||
|
@ -47,6 +55,7 @@ const DefaultMsg = {
|
||||||
saveError : 'Failed to send email. Please contact the system operator.',
|
saveError : 'Failed to send email. Please contact the system operator.',
|
||||||
qrNotAvail : 'QR code not available for this OTP type.',
|
qrNotAvail : 'QR code not available for this OTP type.',
|
||||||
emailRequired : 'Your account must have a valid email address set to use this feature.',
|
emailRequired : 'Your account must have a valid email address set to use this feature.',
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
|
@ -155,7 +164,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
|
|
||||||
let qrCode;
|
let qrCode;
|
||||||
if(!otp) {
|
if(!otp) {
|
||||||
qrCode = this.config.otpNotEnabled || DefaultMsg.otpNotEnabled;
|
qrCode = this.getStatusText('otpNotEnabled');
|
||||||
} else {
|
} else {
|
||||||
const qrOptions = {
|
const qrOptions = {
|
||||||
username : this.client.user.username,
|
username : this.client.user.username,
|
||||||
|
@ -171,7 +180,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
if(qrCode) {
|
if(qrCode) {
|
||||||
qrCode = qrCode.replace(/\n/g, '\r\n');
|
qrCode = qrCode.replace(/\n/g, '\r\n');
|
||||||
} else {
|
} else {
|
||||||
qrCode = this.config.qrNotAvail || DefaultMsg.qrNotAvail;
|
qrCode = this.getStatusText('qrNotAvail');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,15 +190,15 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
showSecret(cb) {
|
showSecret(cb) {
|
||||||
const info =
|
const info =
|
||||||
this.client.user.getProperty(UserProps.AuthFactor2OTPSecret) ||
|
this.client.user.getProperty(UserProps.AuthFactor2OTPSecret) ||
|
||||||
this.config.otpNotEnabled || DefaultMsg.otpNotEnabled;
|
this.getStatusText('otpNotEnabled');
|
||||||
return this.displayDetails(info, cb);
|
return this.displayDetails(info, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
showBackupCodes(cb) {
|
showBackupCodes(cb) {
|
||||||
let info;
|
let info;
|
||||||
const noBackupCodes = this.config.noBackupCodes || DefaultMsg.noBackupCodes;
|
const noBackupCodes = this.getStatusText('noBackupCodes');
|
||||||
if(!this.isOTPEnabledForUser()) {
|
if(!this.isOTPEnabledForUser()) {
|
||||||
info = this.config.otpNotEnabled || DefaultMsg.otpNotEnabled;
|
info = this.getStatusText('otpNotEnabled');
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
info = JSON.parse(this.client.user.getProperty(UserProps.AuthFactor2OTPBackupCodes) || '[]').join(', ');
|
info = JSON.parse(this.client.user.getProperty(UserProps.AuthFactor2OTPBackupCodes) || '[]').join(', ');
|
||||||
|
@ -203,7 +212,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
|
|
||||||
generateNewBackupCodes(cb) {
|
generateNewBackupCodes(cb) {
|
||||||
if(!this.isOTPEnabledForUser()) {
|
if(!this.isOTPEnabledForUser()) {
|
||||||
const info = this.config.otpNotEnabled || DefaultMsg.otpNotEnabled;
|
const info = this.getStatusText('otpNotEnabled');
|
||||||
return this.displayDetails(info, cb);
|
return this.displayDetails(info, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,14 +240,14 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
const emailRegExp = /[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/;
|
const emailRegExp = /[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/;
|
||||||
const emailAddr = this.client.user.getProperty(UserProps.EmailAddress);
|
const emailAddr = this.client.user.getProperty(UserProps.EmailAddress);
|
||||||
if(!emailAddr || !emailRegExp.test(emailAddr)) {
|
if(!emailAddr || !emailRegExp.test(emailAddr)) {
|
||||||
const info = this.config.emailRequired || DefaultMsg.emailRequired;
|
const info = this.getStatusText('emailRequired');
|
||||||
return this.displayDetails(info, cb);
|
return this.displayDetails(info, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
const otpTypeProp = this.otpTypeFromOTPTypeIndex(_.get(formData, 'value.otpType'));
|
const otpTypeProp = this.otpTypeFromOTPTypeIndex(_.get(formData, 'value.otpType'));
|
||||||
|
|
||||||
const saveFailedError = (err) => {
|
const saveFailedError = (err) => {
|
||||||
const info = this.config.saveError || DefaultMsg.saveError;
|
const info = this.getStatusText('saveError');
|
||||||
this.displayDetails(info, () => {
|
this.displayDetails(info, () => {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
});
|
});
|
||||||
|
@ -258,7 +267,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
return saveFailedError(err);
|
return saveFailedError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const info = this.config.saveEmailSent || DefaultMsg.saveEmailSent;
|
const info = this.getStatusText('saveEmailSent');
|
||||||
return this.displayDetails(info, cb);
|
return this.displayDetails(info, cb);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -279,7 +288,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const info = this.config.saveDisabled || DefaultMsg.saveDisabled;
|
const info = this.getStatusText('saveDisabled');
|
||||||
return this.displayDetails(info, cb);
|
return this.displayDetails(info, cb);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -289,7 +298,11 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
getInfoText(key) {
|
getInfoText(key) {
|
||||||
return _.get(this.config, [ 'infoText', key ], '');
|
return _.get(this.config, [ 'infoText', key ], DefaultMsg.infoText[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatusText(key) {
|
||||||
|
return _.get(this.config, [ 'statusText', key ], DefaultMsg.statusText[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
enableToggleUpdate(idx) {
|
enableToggleUpdate(idx) {
|
||||||
|
|
|
@ -18,21 +18,23 @@ Enabling Two-Factor Authentication via One-Time-Password (2FA/OTP) on an account
|
||||||
:information_source: For WebSockets and the web server, ENiGMA½ _may_ listen on insecure channels if behind a secure web proxy.
|
:information_source: For WebSockets and the web server, ENiGMA½ _may_ listen on insecure channels if behind a secure web proxy.
|
||||||
|
|
||||||
### User Registration Flow
|
### User Registration Flow
|
||||||
Due to the nature of 2FA/OTP, even if enabled on your system, users must opt-in and enable this feature on their account. Users must also have a valid email address such that a registration link can be sent to them. To opt-in, a process similar to the following is taken:
|
Due to the nature of 2FA/OTP, even if enabled on your system, users must opt-in and enable this feature on their account. Users must also have a valid email address such that a registration link can be sent to them. To opt-in, users must enable the option, which will cause the system to email them a registration link. Following the link provides the following:
|
||||||
|
|
||||||
1. Navigate to the 2FA/OTP configuration menu and switches the feature to enabled.
|
|
||||||
2. Selects the "flavor" of 2FA/OTP: Google Authenticator, TOTP, or HOTP.
|
|
||||||
3. Confirms settings by saving.
|
|
||||||
|
|
||||||
After saving, a registration link will be mailed to the user. Clicking the link provides the following:
|
|
||||||
1. A secret for manual entry into a OTP device.
|
1. A secret for manual entry into a OTP device.
|
||||||
2. If applicable, a scannable QR code for easy device entry (e.g. Google Authenticator)
|
2. If applicable, a scannable QR code for easy device entry (e.g. Google Authenticator)
|
||||||
3. A confirmation prompt in which the user must enter a OTP code. If entered correctly, this validates everything is set up properly and 2FA/OTP will be enabled for the account. Future logins will now prompt the user for their OTP after they enter their standard password.
|
3. A confirmation prompt in which the user must enter a OTP code. If entered correctly, this validates everything is set up properly and 2FA/OTP will be enabled for the account. Backup codes will also be provided at this time. Future logins will now prompt the user for their OTP after they enter their standard password.
|
||||||
|
|
||||||
:warning: Serving 2FA/OTP registration links over insecure (HTTP) can expose secrets intended for the user and is **highly** discouraged!
|
:warning: Serving 2FA/OTP registration links over insecure (HTTP) can expose secrets intended for the user and is **highly** discouraged!
|
||||||
|
|
||||||
:information_source: +ops can also manually enable or disable 2FA/OTP for a user using [oputil](/docs/admin/oputil.md), but this is generally discouraged.
|
:information_source: +ops can also manually enable or disable 2FA/OTP for a user using [oputil](/docs/admin/oputil.md), but this is generally discouraged.
|
||||||
|
|
||||||
|
#### Recovery
|
||||||
|
In the situation that a user loses their 2FA/OTP device (such as a lost phone with Google Auth), there are some options:
|
||||||
|
* Utilize one of their backup codes.
|
||||||
|
* Contact the SysOp.
|
||||||
|
|
||||||
|
:warning: There is no way for a user to disable 2FA/OTP without first fully logging in! This is by design as a security measure.
|
||||||
|
|
||||||
### ACS Checks
|
### ACS Checks
|
||||||
Various places throughout the system that implement [ACS](/docs/configuration/acs.md) can make 2FA specific checks:
|
Various places throughout the system that implement [ACS](/docs/configuration/acs.md) can make 2FA specific checks:
|
||||||
* `AR#`: Current users **required** authentication factor. `AR2` for example means 2FA/OTP is required for this user.
|
* `AR#`: Current users **required** authentication factor. `AR2` for example means 2FA/OTP is required for this user.
|
||||||
|
|
Loading…
Reference in New Issue