From 09d958249d2a99c41337de9e57348c21f927f7fe Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Mon, 25 Sep 2017 21:58:16 -0400 Subject: [PATCH] Add togglable 2FA user requirements (#635) --- app/Http/Controllers/Admin/BaseController.php | 1 + app/Http/Kernel.php | 1 + .../RequireTwoFactorAuthentication.php | 115 ++++++++++++++++++ public/themes/pterodactyl/css/pterodactyl.css | 4 + .../pterodactyl/admin/settings.blade.php | 17 +++ routes/base.php | 4 +- 6 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 app/Http/Middleware/RequireTwoFactorAuthentication.php diff --git a/app/Http/Controllers/Admin/BaseController.php b/app/Http/Controllers/Admin/BaseController.php index 2858cdaf3..69b96b866 100644 --- a/app/Http/Controllers/Admin/BaseController.php +++ b/app/Http/Controllers/Admin/BaseController.php @@ -93,6 +93,7 @@ class BaseController extends Controller public function postSettings(BaseFormRequest $request) { $this->settings->set('company', $request->input('company')); + $this->settings->set('2fa', $request->input('2fa')); $this->alert->success('Settings have been successfully updated.')->flash(); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index ba1dab68f..a451ef333 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -37,6 +37,7 @@ class Kernel extends HttpKernel \Pterodactyl\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, \Pterodactyl\Http\Middleware\LanguageMiddleware::class, + \Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication::class, ], 'api' => [ \Pterodactyl\Http\Middleware\HMACAuthorization::class, diff --git a/app/Http/Middleware/RequireTwoFactorAuthentication.php b/app/Http/Middleware/RequireTwoFactorAuthentication.php new file mode 100644 index 000000000..893fc6198 --- /dev/null +++ b/app/Http/Middleware/RequireTwoFactorAuthentication.php @@ -0,0 +1,115 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Http\Middleware; + +use Closure; +use Krucas\Settings\Settings; +use Prologue\Alerts\AlertsMessageBag; + +class RequireTwoFactorAuthentication +{ + const LEVEL_NONE = 0; + const LEVEL_ADMIN = 1; + const LEVEL_ALL = 2; + + /** + * @var \Prologue\Alerts\AlertsMessageBag + */ + protected $alert; + + /** + * @var \Krucas\Settings\Settings + */ + protected $settings; + + /** + * All TOTP related routes. + * + * @var array + */ + protected $ignoreRoutes = [ + 'account.security', + 'account.security.revoke', + 'account.security.totp', + 'account.security.totp.set', + 'account.security.totp.disable', + 'auth.totp', + 'auth.logout', + ]; + + /** + * RequireTwoFactorAuthentication constructor. + * + * @param \Prologue\Alerts\AlertsMessageBag $alert + * @param \Krucas\Settings\Settings $settings + */ + public function __construct(AlertsMessageBag $alert, Settings $settings) + { + $this->alert = $alert; + $this->settings = $settings; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle($request, Closure $next) + { + // Ignore non-users + if (! $request->user()) { + return $next($request); + } + + // Skip the 2FA pages + if (in_array($request->route()->getName(), $this->ignoreRoutes)) { + return $next($request); + } + + // Get the setting + switch ((int) $this->settings->get('2fa', 0)) { + case self::LEVEL_NONE: + return $next($request); + + case self::LEVEL_ADMIN: + if (! $request->user()->root_admin) { + return $next($request); + } + break; + + case self::LEVEL_ALL: + if ($request->user()->use_totp) { + return $next($request); + } + break; + } + + $this->alert->danger('The administrator has required 2FA to be enabled. You must enable it before you can do any other action.')->flash(); + + return redirect()->route('account.security'); + } +} diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 46c5f2c36..0cc55b214 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -346,6 +346,10 @@ span[aria-labelledby="select2-pUserId-container"] { line-height: 1.5; } +.btn.active, .btn.active.focus { + background-color: #408fec; +} + .strong { font-weight: bold !important; } diff --git a/resources/themes/pterodactyl/admin/settings.blade.php b/resources/themes/pterodactyl/admin/settings.blade.php index 7e13a7c4f..cbadb0c08 100644 --- a/resources/themes/pterodactyl/admin/settings.blade.php +++ b/resources/themes/pterodactyl/admin/settings.blade.php @@ -66,6 +66,23 @@

This is the default language that all clients will use unless they manually change it.

--}} +
+ +
+
+ + + +
+

Require your administrators or users to have 2FA enabled. Users include Admins. Everybody includes Sub Users.

+
+
diff --git a/routes/base.php b/routes/base.php index adb100fe2..10fdd957e 100644 --- a/routes/base.php +++ b/routes/base.php @@ -69,7 +69,7 @@ Route::group(['prefix' => 'account/security'], function () { Route::put('/totp', 'SecurityController@generateTotp')->name('account.security.totp'); - Route::post('/totp', 'SecurityController@setTotp'); + Route::post('/totp', 'SecurityController@setTotp')->name('account.security.totp.set'); - Route::delete('/totp', 'SecurityController@disableTotp'); + Route::delete('/totp', 'SecurityController@disableTotp')->name('account.security.totp.disable'); });