mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-03-26 17:19:54 +08:00
Added role based MFA control
- Added new DB column for control and role updated create/update actions. - Created new middleware as a start to actual enforcement logic. - Added indicator to role list of whether MFA is enforced.
This commit is contained in:
parent
529971c534
commit
09c2814dc7
app
database/migrations
resources
routes
tests/Permissions
@ -57,6 +57,7 @@ class PermissionsRepo
|
||||
public function saveNewRole(array $roleData): Role
|
||||
{
|
||||
$role = $this->role->newInstance($roleData);
|
||||
$role->mfa_enforced = ($roleData['mfa_enforced'] ?? 'false') === 'true';
|
||||
$role->save();
|
||||
|
||||
$permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
|
||||
@ -90,6 +91,7 @@ class PermissionsRepo
|
||||
$this->assignRolePermissions($role, $permissions);
|
||||
|
||||
$role->fill($roleData);
|
||||
$role->mfa_enforced = ($roleData['mfa_enforced'] ?? 'false') === 'true';
|
||||
$role->save();
|
||||
$this->permissionService->buildJointPermissionForRole($role);
|
||||
Activity::add(ActivityType::ROLE_UPDATE, $role);
|
||||
|
@ -18,6 +18,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
* @property string $description
|
||||
* @property string $external_auth_id
|
||||
* @property string $system_name
|
||||
* @property bool $mfa_enforced
|
||||
*/
|
||||
class Role extends Model implements Loggable
|
||||
{
|
||||
|
24
app/Http/Middleware/EnforceMfaRequirements.php
Normal file
24
app/Http/Middleware/EnforceMfaRequirements.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class EnforceMfaRequirements
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$mfaRequired = user()->roles()->where('mfa_enforced', '=', true)->exists();
|
||||
// TODO - Run this after auth (If authenticated)
|
||||
// TODO - Redirect user to setup MFA or verify via MFA.
|
||||
// TODO - Store mfa_pass into session for future requests?
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddMfaEnforcedToRolesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('roles', function (Blueprint $table) {
|
||||
$table->boolean('mfa_enforced');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('roles', function (Blueprint $table) {
|
||||
$table->dropColumn('mfa_enforced');
|
||||
});
|
||||
}
|
||||
}
|
@ -138,6 +138,7 @@ return [
|
||||
'role_details' => 'Role Details',
|
||||
'role_name' => 'Role Name',
|
||||
'role_desc' => 'Short Description of Role',
|
||||
'role_mfa_enforced' => 'Requires Multi-Factor Authentication',
|
||||
'role_external_auth_id' => 'External Authentication IDs',
|
||||
'role_system' => 'System Permissions',
|
||||
'role_manage_users' => 'Manage users',
|
||||
|
@ -11,13 +11,16 @@
|
||||
</div>
|
||||
<div>
|
||||
<div class="form-group">
|
||||
<label for="name">{{ trans('settings.role_name') }}</label>
|
||||
<label for="display_name">{{ trans('settings.role_name') }}</label>
|
||||
@include('form.text', ['name' => 'display_name'])
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="name">{{ trans('settings.role_desc') }}</label>
|
||||
<label for="description">{{ trans('settings.role_desc') }}</label>
|
||||
@include('form.text', ['name' => 'description'])
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@include('form.checkbox', ['name' => 'mfa_enforced', 'label' => trans('settings.role_mfa_enforced') ])
|
||||
</div>
|
||||
|
||||
@if(config('auth.method') === 'ldap' || config('auth.method') === 'saml2')
|
||||
<div class="form-group">
|
||||
|
@ -27,7 +27,12 @@
|
||||
@foreach($roles as $role)
|
||||
<tr>
|
||||
<td><a href="{{ url("/settings/roles/{$role->id}") }}">{{ $role->display_name }}</a></td>
|
||||
<td>{{ $role->description }}</td>
|
||||
<td>
|
||||
@if($role->mfa_enforced)
|
||||
<span title="{{ trans('settings.role_mfa_enforced') }}">@icon('lock') </span>
|
||||
@endif
|
||||
{{ $role->description }}
|
||||
</td>
|
||||
<td class="text-center">{{ $role->users->count() }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
@ -224,6 +224,7 @@ Route::group(['middleware' => 'auth'], function () {
|
||||
Route::put('/roles/{id}', 'RoleController@update');
|
||||
});
|
||||
|
||||
// MFA Setup Routes
|
||||
Route::get('/mfa/setup', 'Auth\MfaController@setup');
|
||||
Route::get('/mfa/totp-generate', 'Auth\MfaTotpController@generate');
|
||||
Route::post('/mfa/totp-confirm', 'Auth\MfaTotpController@confirm');
|
||||
|
@ -64,15 +64,16 @@ class RolesTest extends BrowserKitTest
|
||||
->type('Test Role', 'display_name')
|
||||
->type('A little test description', 'description')
|
||||
->press('Save Role')
|
||||
->seeInDatabase('roles', ['display_name' => $testRoleName, 'description' => $testRoleDesc])
|
||||
->seeInDatabase('roles', ['display_name' => $testRoleName, 'description' => $testRoleDesc, 'mfa_enforced' => false])
|
||||
->seePageIs('/settings/roles');
|
||||
// Updating
|
||||
$this->asAdmin()->visit('/settings/roles')
|
||||
->see($testRoleDesc)
|
||||
->click($testRoleName)
|
||||
->type($testRoleUpdateName, '#display_name')
|
||||
->check('#mfa_enforced')
|
||||
->press('Save Role')
|
||||
->seeInDatabase('roles', ['display_name' => $testRoleUpdateName, 'description' => $testRoleDesc])
|
||||
->seeInDatabase('roles', ['display_name' => $testRoleUpdateName, 'description' => $testRoleDesc, 'mfa_enforced' => true])
|
||||
->seePageIs('/settings/roles');
|
||||
// Deleting
|
||||
$this->asAdmin()->visit('/settings/roles')
|
||||
|
Loading…
x
Reference in New Issue
Block a user