From 969d40d6c13be965035c92580487916ecc9fcc0b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 13 Feb 2022 14:15:18 -0500 Subject: [PATCH] Logic cleanup after a bit of dust collection --- .../Api/Client/SecurityKeyController.php | 1 + app/Http/Controllers/Auth/LoginController.php | 56 ++++++++----------- app/Models/SecurityKey.php | 15 +++-- .../PublicKeyCredentialSourceRepository.php | 4 +- .../CreatePublicKeyCredentialsService.php | 2 +- ...ratePublicKeyCredentialsRequestService.php | 39 +++++++++++++ 6 files changed, 74 insertions(+), 43 deletions(-) create mode 100644 app/Services/Users/SecurityKeys/GeneratePublicKeyCredentialsRequestService.php diff --git a/app/Http/Controllers/Api/Client/SecurityKeyController.php b/app/Http/Controllers/Api/Client/SecurityKeyController.php index 96c493bd0..3354f12d6 100644 --- a/app/Http/Controllers/Api/Client/SecurityKeyController.php +++ b/app/Http/Controllers/Api/Client/SecurityKeyController.php @@ -61,6 +61,7 @@ class SecurityKeyController extends ClientApiController $tokenId = Str::random(64); $credentials = $this->createPublicKeyCredentials->handle($request->user()); + // TODO: session $this->cache->put( "register-security-key:$tokenId", serialize($credentials), diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 4ed326623..8b47f16d7 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -7,27 +7,27 @@ use Illuminate\Support\Str; use Illuminate\Http\Request; use Pterodactyl\Models\User; use Illuminate\Http\JsonResponse; -use Illuminate\Contracts\View\View; -use LaravelWebauthn\Facades\Webauthn; -use Illuminate\Contracts\View\Factory as ViewFactory; +use Pterodactyl\Models\SecurityKey; +use Illuminate\Support\Facades\View; +use Illuminate\Contracts\View\View as ViewContract; +use Pterodactyl\Services\Users\SecurityKeys\GeneratePublicKeyCredentialsRequestService; class LoginController extends AbstractLoginController { - private const SESSION_PUBLICKEY_REQUEST = 'webauthn.publicKeyRequest'; - private const METHOD_TOTP = 'totp'; private const METHOD_WEBAUTHN = 'webauthn'; + private const SESSION_PUBLICKEY_REQUEST = 'webauthn.publicKeyRequest'; - private ViewFactory $view; + protected GeneratePublicKeyCredentialsRequestService $service; /** - * LoginController constructor. + * @param \Pterodactyl\Services\Users\SecurityKeys\GeneratePublicKeyCredentialsRequestService $service */ - public function __construct(ViewFactory $view) + public function __construct(GeneratePublicKeyCredentialsRequestService $service) { parent::__construct(); - $this->view = $view; + $this->service = $service; } /** @@ -35,9 +35,9 @@ class LoginController extends AbstractLoginController * base authentication view component. React will take over at this point and * turn the login area into an SPA. */ - public function index(): View + public function index(): ViewContract { - return $this->view->make('templates/auth.core'); + return View::make('templates/auth.core'); } /** @@ -75,23 +75,11 @@ class LoginController extends AbstractLoginController return; } - $useTotp = $user->use_totp; - $webauthnKeys = $user->webauthnKeys()->get(); - - if (!$useTotp && count($webauthnKeys) < 1) { + if (!$user->use_totp && empty($user->security_keys_count)) { return $this->sendLoginResponse($user, $request); } - $methods = []; - if ($useTotp) { - $methods[] = self::METHOD_TOTP; - } - if (count($webauthnKeys) > 0) { - $methods[] = self::METHOD_WEBAUTHN; - } - $token = Str::random(64); - $request->session()->put('auth_confirmation_token', [ 'user_id' => $user->id, 'token_value' => $token, @@ -100,17 +88,21 @@ class LoginController extends AbstractLoginController $response = [ 'complete' => false, - 'methods' => $methods, + 'methods' => array_filter([ + $user->use_totp ? self::METHOD_TOTP : null, + $user->security_keys_count > 0 ? self::METHOD_WEBAUTHN : null, + ]), 'confirmation_token' => $token, ]; - if (count($webauthnKeys) > 0) { - $publicKey = Webauthn::getAuthenticateData($user); - $request->session()->put(self::SESSION_PUBLICKEY_REQUEST, $publicKey); - - $response['webauthn'] = [ - 'public_key' => $publicKey, - ]; + if ($user->security_keys_count > 0) { +// $key = $this->service->handle($user); +// +// $request->session()->put(self::SESSION_PUBLICKEY_REQUEST, $publicKey); +// +// $response['webauthn'] = [ +// 'public_key' => $publicKey, +// ]; } return new JsonResponse($response); diff --git a/app/Models/SecurityKey.php b/app/Models/SecurityKey.php index eee9d62d0..552967e73 100644 --- a/app/Models/SecurityKey.php +++ b/app/Models/SecurityKey.php @@ -2,7 +2,6 @@ namespace Pterodactyl\Models; -use Stringable; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; use Webauthn\TrustPath\TrustPath; @@ -82,12 +81,7 @@ class SecurityKey extends Model return null; } - public function user(): BelongsTo - { - return $this->belongsTo(User::class); - } - - public function getPublicKeyCredentialsDescriptorAttribute(): PublicKeyCredentialDescriptor + public function getPublicKeyCredentialDescriptor(): PublicKeyCredentialDescriptor { return new PublicKeyCredentialDescriptor( $this->type, @@ -96,7 +90,7 @@ class SecurityKey extends Model ); } - public function getPublicKeyCredentialSourceAttribute(): PublicKeyCredentialSource + public function getPublicKeyCredentialSource(): PublicKeyCredentialSource { return new PublicKeyCredentialSource( $this->public_key_id, @@ -110,4 +104,9 @@ class SecurityKey extends Model $this->counter ); } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } } diff --git a/app/Repositories/SecurityKeys/PublicKeyCredentialSourceRepository.php b/app/Repositories/SecurityKeys/PublicKeyCredentialSourceRepository.php index 8c5269ea4..e24d956b8 100644 --- a/app/Repositories/SecurityKeys/PublicKeyCredentialSourceRepository.php +++ b/app/Repositories/SecurityKeys/PublicKeyCredentialSourceRepository.php @@ -29,7 +29,7 @@ class PublicKeyCredentialSourceRepository implements PublicKeyRepositoryInterfac ->where('public_key_id', $id) ->first(); - return $key ? $key->public_key_credential_source : null; + return optional($key)->getPublicKeyCredentialSource(); } /** @@ -43,7 +43,7 @@ class PublicKeyCredentialSourceRepository implements PublicKeyRepositoryInterfac ->get(); return $results->map(function (SecurityKey $key) { - return $key->public_key_credential_source; + return $key->getPublicKeyCredentialSource(); })->values()->toArray(); } diff --git a/app/Services/Users/SecurityKeys/CreatePublicKeyCredentialsService.php b/app/Services/Users/SecurityKeys/CreatePublicKeyCredentialsService.php index dadde95f7..d2bedccea 100644 --- a/app/Services/Users/SecurityKeys/CreatePublicKeyCredentialsService.php +++ b/app/Services/Users/SecurityKeys/CreatePublicKeyCredentialsService.php @@ -22,7 +22,7 @@ class CreatePublicKeyCredentialsService $entity = new PublicKeyCredentialUserEntity($user->username, $user->uuid, $user->email, null); $excluded = $user->securityKeys->map(function (SecurityKey $key) { - return $key->public_key_credentials_descriptor; + return $key->getPublicKeyCredentialDescriptor(); })->values()->toArray(); $server = $this->webauthnServerRepository->getServer($user); diff --git a/app/Services/Users/SecurityKeys/GeneratePublicKeyCredentialsRequestService.php b/app/Services/Users/SecurityKeys/GeneratePublicKeyCredentialsRequestService.php new file mode 100644 index 000000000..4a8be3c6d --- /dev/null +++ b/app/Services/Users/SecurityKeys/GeneratePublicKeyCredentialsRequestService.php @@ -0,0 +1,39 @@ +serverRepository = $serverRepository; + } + + /** + * @param \Pterodactyl\Models\User $user + * @return \Webauthn\PublicKeyCredentialRequestOptions + */ + public function handle(User $user): PublicKeyCredentialRequestOptions + { + $credentials = $user->securityKeys->map(function (SecurityKey $key) { + return $key->getPublicKeyCredentialDescriptor(); + }); + + $response = $this->serverRepository->getServer($user) + ->generatePublicKeyCredentialRequestOptions( + PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_PREFERRED, $credentials + ); + + return $response->setTimeout(300); + } +}