From ccb267bb4dcea597653cf34c35fa041fe8302a9f Mon Sep 17 00:00:00 2001 From: rhinoau <78184917+rhinoau@users.noreply.github.com> Date: Sat, 10 Jul 2021 03:36:08 +0800 Subject: [PATCH] Two-factor UI config and status display (#13012) * two-factor UI config and status display additions * force test re-run * removal of blade foreach via keyBy * remove where clause against all() * attempt where filtering with keyBy * use @config and getPref in blade * another forgotten @config changed Co-authored-by: PipoCanaja <38363551+PipoCanaja@users.noreply.github.com> --- app/Http/Controllers/UserController.php | 2 +- app/Models/UserPref.php | 4 ++ doc/Extensions/Two-Factor-Auth.md | 79 ++++++++++++++++++------- misc/config_definitions.json | 16 +++-- resources/lang/en/settings.php | 8 +++ resources/views/user/index.blade.php | 13 ++++ 6 files changed, 97 insertions(+), 25 deletions(-) diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 385d8f672d..96cce5afe5 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -54,7 +54,7 @@ class UserController extends Controller $this->authorize('manage', User::class); return view('user.index', [ - 'users' => User::orderBy('username')->get(), + 'users' => User::with('preferences')->orderBy('username')->get(), 'multiauth' => User::query()->distinct('auth_type')->count('auth_type') > 1, ]); } diff --git a/app/Models/UserPref.php b/app/Models/UserPref.php index cf250602e3..80d454c69a 100644 --- a/app/Models/UserPref.php +++ b/app/Models/UserPref.php @@ -36,6 +36,10 @@ class UserPref extends BaseModel // ---- Helper Functions ---- public static function getPref(User $user, $pref) { + if ($user->relationLoaded('preferences')) { + return optional($user->preferences->firstWhere('pref', $pref))->value; + } + return $user->preferences()->where('pref', $pref)->value('value'); } diff --git a/doc/Extensions/Two-Factor-Auth.md b/doc/Extensions/Two-Factor-Auth.md index 05d58a889e..8560e3777a 100644 --- a/doc/Extensions/Two-Factor-Auth.md +++ b/doc/Extensions/Two-Factor-Auth.md @@ -1,28 +1,29 @@ source: Extensions/Two-Factor-Auth.md path: blob/master/doc/ -# About +# Two-Factor Authentication Over the last couple of years, the primary attack vector for internet accounts has been static passwords. Therefore static passwords are no longer sufficient to protect unauthorized access to accounts. Two Factor Authentication adds a variable part in authentication procedures. A user is now required to supply a changing 6-digit -passcode in addition to it's password to obtain access to the account. +passcode in addition to their password to obtain access to the account. -LibreNMS has a RFC4226 conform implementation of both Time and Counter +LibreNMS has a RFC4226 conformant implementation of both Time and Counter based One-Time-Passwords. It also allows the administrator to configure a throttle time to enforce after 3 failures exceeded. Unlike -RFC4226 suggestions, this throttle time will not stack on the amount of failures. +RFC4226 suggestions, this throttle time will not stack on the amount of +failures. -# Types +## Types In general, these two types do not differ in algorithmic terms. The types only differ in the variable being used to derive the passcodes from. The underlying HMAC-SHA1 remains the same for both types, security advantages or disadvantages of each are discussed further down. -## Timebased One-Time-Password (TOTP) +### Timebased One-Time-Password (TOTP) Like the name suggests, this type uses the current Time or a subset of it to generate the passcodes. These passcodes solely rely on the @@ -32,7 +33,7 @@ given time, presumably the time upon login. RFC4226 suggests a resynchronization attempt in case the passcode mismatches, providing the attacker a range of up to +/- 3 Minutes to create passcodes. -## Counterbased One-Time-Password (TOTP) +### Counterbased One-Time-Password (HOTP) This type uses an internal counter that needs to be in sync with the server's counter to successfully authenticate the passcodes. The main @@ -42,25 +43,51 @@ passcodes. RFC4226 suggests a resynchronization attempt in case the passcode mismatches, providing the attacker a range of up to +4 increments from the actual counter to create passcodes. -# Configuration +## Configuration + +### WebUI + +Enable 'Two-Factor' Via Global Settings in the Web UI under +Authentication -> General Authentication Settings. + +Optionally enter a throttle timer in seconds. This will unlock an account +after this time once it has failed 3 attempt to authenticate. Set to 0 (default) +to disable this feature, meaning accounts will remain locked after 3 attempts +and will need an administrator to clear. + +### CLI Enable Two-Factor: -```php -$config['twofactor'] = true; -``` +`./lnms config:set twofactor true` + Set throttle-time (in seconds): -```php -$config['twofactor_lock'] = 300; -``` +`./lnms config:set twofactor_lock 300` -# Usage +## User Administation -These steps imply that TwoFactor has been enabled in your `config.php` +If Two-Factor is enabled, the Settings -> Manage Users grid will show a '2FA' column +containing a green tick for users with active 2FA. -Create a Two-Factor key: +There is no functionality to mandate 2FA for users. + +If a user has failed 3 attempts, their account can be unlocked or 2FA disabled by +editing the user from the Manage Users table. + +If a throttle timer is set, it will unlock accounts after this time. If set to the +default of 0, accounts will need to be manually unlocked by an administrator after 3 +failed attempts. + +Locked accounts will report to the user stating to wait for the throttle time period, +or to contact the administrator if no timer set. + +## End-User Enrolment + +These steps imply that Two-Factor has been enabled system wide as above under Configuration. + +2FA is enabled by each user once they are logged in normally: - Go to 'My Settings' (/preferences/) - Choose TwoFactor type @@ -68,12 +95,24 @@ Create a Two-Factor key: - If your browser didn't reload, reload manually - Scan provided QR or click on 'Manual' to see the Key -## Google Authenticator +### Google Authenticator Installation guides for Google Authenticator can be found [here](https://support.google.com/accounts/answer/1066447?hl=en). Usage: -- Create a key like described above -- Scan provided QR or click on 'Manual' and type down the Secret +- Create a key as described above +- Scan provided QR or click on 'Manual' and enter the Secret +- On next login, enter the passcode that the App provides + +### LastPass Authenticator + +LastPass Authenticator is confirmed to work with Timebased One-Time Passwords (TOTP). + +Installation guide for LastPass Authenticator can be found [here](https://support.logmeininc.com/lastpass/help/lastpass-authenticator-lp030014). + +Usage: + +- Create a Timerbased key as described above +- Click Add (+) and scan provided QR or click on 'NO QR CODE?' and enter naming details and the Secret - On next login, enter the passcode that the App provides diff --git a/misc/config_definitions.json b/misc/config_definitions.json index 20a240b2d0..113efcc5e5 100644 --- a/misc/config_definitions.json +++ b/misc/config_definitions.json @@ -620,7 +620,7 @@ "units": "days", "group": "auth", "section": "general", - "order": 3, + "order": 4, "type": "integer" }, "authlog_purge": { @@ -3737,7 +3737,7 @@ "default": "Unauthorised access or use shall render the user liable to criminal and/or civil prosecution.", "group": "auth", "section": "general", - "order": 4, + "order": 5, "type": "text" }, "mac_oui.enabled": { @@ -4220,7 +4220,7 @@ "type": "integer", "group": "auth", "section": "general", - "order": 5 + "order": 6 }, "peering_descr": { "default": [ @@ -4670,7 +4670,7 @@ "default": false, "group": "auth", "section": "general", - "order": 6, + "order": 7, "type": "boolean" }, "rancid_ignorecomments": { @@ -5203,11 +5203,19 @@ "order": 1 }, "twofactor": { + "default": "false", "type": "boolean", "group": "auth", "section": "general", "order": 1 }, + "twofactor_lock": { + "default": "0", + "type": "integer", + "group": "auth", + "section": "general", + "order": 2 + }, "unix-agent-connection-time-out": { "default": 10, "type": "integer" diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 55c277c1ae..e0345503b9 100644 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -1331,6 +1331,14 @@ return [ 'traceroute6' => [ 'description' => 'Path to traceroute6', ], + 'twofactor' => [ + 'description' => 'Two-Factor', + 'help' => 'Allow users to activate and use Timebased (TOTP) or Counterbased (HOTP) One-Time Passwords (OTP)', + ], + 'twofactor_lock' => [ + 'description' => 'Two-Factor Throttle Time (seconds)', + 'help' => 'Lock-out time to wait in seconds before allowing further attempts if Two-Factor authentication is failed 3 times consecutively - will prompt user to wait this long. Set to 0 to disable resulting in a permanent account lock-out and a message to user to contact administrator', + ], 'unix-agent' => [ 'connection-timeout' => [ 'description' => 'Unix-agent connection timeout', diff --git a/resources/views/user/index.blade.php b/resources/views/user/index.blade.php index 958d22674b..07c019c656 100644 --- a/resources/views/user/index.blade.php +++ b/resources/views/user/index.blade.php @@ -22,6 +22,9 @@ @if(\LibreNMS\Authentication\LegacyAuth::getType() == 'mysql') @lang('Enabled') @endif + @config('twofactor') + @lang('2FA') + @endconfig @lang('Description') @lang('Actions') @@ -38,6 +41,11 @@ @if(\LibreNMS\Authentication\LegacyAuth::getType() == 'mysql') {{ $user->enabled }} @endif + @config('twofactor') + @if(app('App\Models\UserPref')->getPref($user, 'twofactor')) + 1 + @endif + @endconfig {{ $user->descr }} @@ -62,6 +70,11 @@ return ''; } }, + twofactor: function (column, row) { + if(row['twofactor'] == 1) { + return ''; + } + }, actions: function (column, row) { var edit_button = '
' + '@csrf' +