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>
This commit is contained in:
rhinoau
2021-07-10 03:36:08 +08:00
committed by GitHub
parent 5acece54eb
commit ccb267bb4d
6 changed files with 97 additions and 25 deletions

View File

@@ -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,
]);
}

View File

@@ -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');
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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',

View File

@@ -22,6 +22,9 @@
@if(\LibreNMS\Authentication\LegacyAuth::getType() == 'mysql')
<th data-column-id="enabled" data-formatter="enabled">@lang('Enabled')</th>
@endif
@config('twofactor')
<th data-column-id="twofactor" data-formatter="twofactor">@lang('2FA')</th>
@endconfig
<th data-column-id="descr">@lang('Description')</th>
<th data-column-id="action" data-formatter="actions" data-sortable="false" data-searchable="false">@lang('Actions')</th>
</tr>
@@ -38,6 +41,11 @@
@if(\LibreNMS\Authentication\LegacyAuth::getType() == 'mysql')
<td>{{ $user->enabled }}</td>
@endif
@config('twofactor')
@if(app('App\Models\UserPref')->getPref($user, 'twofactor'))
<td>1</td>
@endif
@endconfig
<td>{{ $user->descr }}</td>
<td></td>
</tr>
@@ -62,6 +70,11 @@
return '<span class="fa fa-fw fa-close text-danger"></span>';
}
},
twofactor: function (column, row) {
if(row['twofactor'] == 1) {
return '<span class="fa fa-fw fa-check text-success"></span>';
}
},
actions: function (column, row) {
var edit_button = '<form action="{{ route('users.edit', ':user_id') }}'.replace(':user_id', row['user_id']) + '" method="GET">' +
'@csrf' +