From d25cd83d8e2a8741a6476ce2d7ff6efc728ecc6e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 29 Jun 2021 22:06:49 +0100 Subject: [PATCH] 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. --- app/Http/Controllers/Auth/MfaController.php | 65 +++++++++++++++++++-- resources/sass/_forms.scss | 4 ++ resources/views/mfa/setup.blade.php | 33 ++++++++++- resources/views/mfa/totp-generate.blade.php | 44 ++++++++++++++ routes/web.php | 2 + 5 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 resources/views/mfa/totp-generate.blade.php diff --git a/app/Http/Controllers/Auth/MfaController.php b/app/Http/Controllers/Auth/MfaController.php index 1d0dbd1a4..be381e3b0 100644 --- a/app/Http/Controllers/Auth/MfaController.php +++ b/app/Http/Controllers/Auth/MfaController.php @@ -2,11 +2,24 @@ 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 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 { + protected const TOTP_SETUP_SECRET_SESSION_KEY = 'mfa-setup-totp-secret'; + /** * Show the view to setup MFA for the current user. */ @@ -17,13 +30,57 @@ class MfaController extends Controller 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. // 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')); } } diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index 953d1d060..bb6d17f82 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -29,6 +29,10 @@ } } +.input-fill-width { + width: 100% !important; +} + .fake-input { @extend .input-base; overflow: auto; diff --git a/resources/views/mfa/setup.blade.php b/resources/views/mfa/setup.blade.php index 25eb5d925..577841af5 100644 --- a/resources/views/mfa/setup.blade.php +++ b/resources/views/mfa/setup.blade.php @@ -5,12 +5,39 @@

Setup Multi-Factor Authentication

-

+

Setup multi-factor authentication as an extra layer of security 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.

+ +
+
+
+
Mobile App
+

+ To use multi-factor authentication you'll need a mobile application + that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator. +

+
+
+ Setup +
+
+ +
+
+
Backup Codes
+

+ Print out or securely store a set of one-time backup codes + which you can enter to verify your identity. +

+
+
+ Setup +
+
+
+
@stop diff --git a/resources/views/mfa/totp-generate.blade.php b/resources/views/mfa/totp-generate.blade.php new file mode 100644 index 000000000..17d38adaa --- /dev/null +++ b/resources/views/mfa/totp-generate.blade.php @@ -0,0 +1,44 @@ +@extends('simple-layout') + +@section('body') + +
+
+

Mobile App Setup

+

+ To use multi-factor authentication you'll need a mobile application + that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator. +

+

+ Scan the QR code below using your preferred authentication app to get started. +

+ +
+
+ {!! $svg !!} +
+
+ +

Verify Setup

+

+ Verify that all is working by entering a code, generated within your + authentication app, in the input box below: +

+
+ {{ csrf_field() }} + + @if($errors->has('code')) +
{{ $errors->first('code') }}
+ @endif +
+ +
+
+
+
+ +@stop diff --git a/routes/web.php b/routes/web.php index 7807d5477..f9967465b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -225,6 +225,8 @@ Route::group(['middleware' => 'auth'], function () { }); 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