mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-05-04 08:10:26 +00:00
Added TOTP generation view and started verification stage
Also updated MFA setup view to have settings-like listed interface to make it possible to extend with extra options in the future.
This commit is contained in:
parent
efb6a6b457
commit
d25cd83d8e
5 changed files with 141 additions and 7 deletions
app/Http/Controllers/Auth
resources
routes
|
@ -2,11 +2,24 @@
|
||||||
|
|
||||||
namespace BookStack\Http\Controllers\Auth;
|
namespace BookStack\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Color\Rgb;
|
||||||
|
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
|
||||||
|
use BaconQrCode\Renderer\ImageRenderer;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\Fill;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||||
|
use BaconQrCode\Writer;
|
||||||
use BookStack\Http\Controllers\Controller;
|
use BookStack\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException;
|
||||||
|
use PragmaRX\Google2FA\Exceptions\InvalidCharactersException;
|
||||||
|
use PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException;
|
||||||
|
use PragmaRX\Google2FA\Google2FA;
|
||||||
|
|
||||||
class MfaController extends Controller
|
class MfaController extends Controller
|
||||||
{
|
{
|
||||||
|
protected const TOTP_SETUP_SECRET_SESSION_KEY = 'mfa-setup-totp-secret';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the view to setup MFA for the current user.
|
* Show the view to setup MFA for the current user.
|
||||||
*/
|
*/
|
||||||
|
@ -17,13 +30,57 @@ class MfaController extends Controller
|
||||||
return view('mfa.setup');
|
return view('mfa.setup');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateQr()
|
/**
|
||||||
|
* Show a view that generates and displays a TOTP QR code.
|
||||||
|
* @throws IncompatibleWithGoogleAuthenticatorException
|
||||||
|
* @throws InvalidCharactersException
|
||||||
|
* @throws SecretKeyTooShortException
|
||||||
|
*/
|
||||||
|
public function totpGenerate()
|
||||||
{
|
{
|
||||||
// https://github.com/antonioribeiro/google2fa#how-to-generate-and-use-two-factor-authentication
|
// TODO - Ensure a QR code doesn't already exist? Or overwrite?
|
||||||
|
$google2fa = new Google2FA();
|
||||||
|
if (session()->has(static::TOTP_SETUP_SECRET_SESSION_KEY)) {
|
||||||
|
$totpSecret = decrypt(session()->get(static::TOTP_SETUP_SECRET_SESSION_KEY));
|
||||||
|
} else {
|
||||||
|
$totpSecret = $google2fa->generateSecretKey();
|
||||||
|
session()->put(static::TOTP_SETUP_SECRET_SESSION_KEY, encrypt($totpSecret));
|
||||||
|
}
|
||||||
|
|
||||||
|
$qrCodeUrl = $google2fa->getQRCodeUrl(
|
||||||
|
setting('app-name'),
|
||||||
|
user()->email,
|
||||||
|
$totpSecret
|
||||||
|
);
|
||||||
|
|
||||||
|
$color = Fill::uniformColor(new Rgb(255, 255, 255), new Rgb(32, 110, 167));
|
||||||
|
$svg = (new Writer(
|
||||||
|
new ImageRenderer(
|
||||||
|
new RendererStyle(192, 0, null, null, $color),
|
||||||
|
new SvgImageBackEnd
|
||||||
|
)
|
||||||
|
))->writeString($qrCodeUrl);
|
||||||
|
|
||||||
// Generate secret key
|
|
||||||
// Store key in session?
|
|
||||||
// Get user to verify setup via responding once.
|
// Get user to verify setup via responding once.
|
||||||
// If correct response, Save key against user
|
// If correct response, Save key against user
|
||||||
|
return view('mfa.totp-generate', [
|
||||||
|
'secret' => $totpSecret,
|
||||||
|
'svg' => $svg,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm the setup of TOTP and save the auth method secret
|
||||||
|
* against the current user.
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
public function totpConfirm(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'code' => 'required|max:12|min:4'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// TODO - Confirm code
|
||||||
|
dd($request->input('code'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-fill-width {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
.fake-input {
|
.fake-input {
|
||||||
@extend .input-base;
|
@extend .input-base;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
|
@ -5,12 +5,39 @@
|
||||||
|
|
||||||
<div class="card content-wrap auto-height">
|
<div class="card content-wrap auto-height">
|
||||||
<h1 class="list-heading">Setup Multi-Factor Authentication</h1>
|
<h1 class="list-heading">Setup Multi-Factor Authentication</h1>
|
||||||
<p>
|
<p class="mb-none">
|
||||||
Setup multi-factor authentication as an extra layer of security
|
Setup multi-factor authentication as an extra layer of security
|
||||||
for your user account.
|
for your user account.
|
||||||
To use multi-factor authentication you'll need a mobile application
|
|
||||||
that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="setting-list">
|
||||||
|
<div class="grid half gap-xl">
|
||||||
|
<div>
|
||||||
|
<div class="setting-list-label">Mobile App</div>
|
||||||
|
<p class="small">
|
||||||
|
To use multi-factor authentication you'll need a mobile application
|
||||||
|
that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="pt-m">
|
||||||
|
<a href="{{ url('/mfa/totp-generate') }}" class="button outline">Setup</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid half gap-xl">
|
||||||
|
<div>
|
||||||
|
<div class="setting-list-label">Backup Codes</div>
|
||||||
|
<p class="small">
|
||||||
|
Print out or securely store a set of one-time backup codes
|
||||||
|
which you can enter to verify your identity.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="pt-m">
|
||||||
|
<a href="{{ url('/mfa/codes/generate') }}" class="button outline">Setup</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
44
resources/views/mfa/totp-generate.blade.php
Normal file
44
resources/views/mfa/totp-generate.blade.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
@extends('simple-layout')
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
|
||||||
|
<div class="container very-small py-xl">
|
||||||
|
<div class="card content-wrap auto-height">
|
||||||
|
<h1 class="list-heading">Mobile App Setup</h1>
|
||||||
|
<p>
|
||||||
|
To use multi-factor authentication you'll need a mobile application
|
||||||
|
that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Scan the QR code below using your preferred authentication app to get started.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="block inline">
|
||||||
|
{!! $svg !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="list-heading">Verify Setup</h2>
|
||||||
|
<p id="totp-verify-input-details" class="mb-s">
|
||||||
|
Verify that all is working by entering a code, generated within your
|
||||||
|
authentication app, in the input box below:
|
||||||
|
</p>
|
||||||
|
<form action="{{ url('/mfa/totp-confirm') }}" method="POST">
|
||||||
|
{{ csrf_field() }}
|
||||||
|
<input type="text"
|
||||||
|
name="code"
|
||||||
|
aria-labelledby="totp-verify-input-details"
|
||||||
|
placeholder="Provide your app generated code here"
|
||||||
|
class="input-fill-width {{ $errors->has('code') ? 'neg' : '' }}">
|
||||||
|
@if($errors->has('code'))
|
||||||
|
<div class="text-neg text-small px-xs">{{ $errors->first('code') }}</div>
|
||||||
|
@endif
|
||||||
|
<div class="mt-s text-right">
|
||||||
|
<button class="button">Confirm and Enable</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@stop
|
|
@ -225,6 +225,8 @@ Route::group(['middleware' => 'auth'], function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/mfa/setup', 'Auth\MfaController@setup');
|
Route::get('/mfa/setup', 'Auth\MfaController@setup');
|
||||||
|
Route::get('/mfa/totp-generate', 'Auth\MfaController@totpGenerate');
|
||||||
|
Route::post('/mfa/totp-confirm', 'Auth\MfaController@totpConfirm');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Social auth routes
|
// Social auth routes
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue