WebAuthnController.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Core\Controller;
  8. use OC\Authentication\Login\LoginData;
  9. use OC\Authentication\Login\WebAuthnChain;
  10. use OC\Authentication\WebAuthn\Manager;
  11. use OC\URLGenerator;
  12. use OCP\AppFramework\Controller;
  13. use OCP\AppFramework\Http;
  14. use OCP\AppFramework\Http\Attribute\FrontpageRoute;
  15. use OCP\AppFramework\Http\Attribute\PublicPage;
  16. use OCP\AppFramework\Http\Attribute\UseSession;
  17. use OCP\AppFramework\Http\JSONResponse;
  18. use OCP\IRequest;
  19. use OCP\ISession;
  20. use OCP\Util;
  21. use Psr\Log\LoggerInterface;
  22. use Webauthn\PublicKeyCredentialRequestOptions;
  23. class WebAuthnController extends Controller {
  24. private const WEBAUTHN_LOGIN = 'webauthn_login';
  25. private const WEBAUTHN_LOGIN_UID = 'webauthn_login_uid';
  26. public function __construct(
  27. string $appName,
  28. IRequest $request,
  29. private Manager $webAuthnManger,
  30. private ISession $session,
  31. private LoggerInterface $logger,
  32. private WebAuthnChain $webAuthnChain,
  33. private URLGenerator $urlGenerator,
  34. ) {
  35. parent::__construct($appName, $request);
  36. }
  37. #[PublicPage]
  38. #[UseSession]
  39. #[FrontpageRoute(verb: 'POST', url: 'login/webauthn/start')]
  40. public function startAuthentication(string $loginName): JSONResponse {
  41. $this->logger->debug('Starting WebAuthn login');
  42. $this->logger->debug('Converting login name to UID');
  43. $uid = $loginName;
  44. Util::emitHook(
  45. '\OCA\Files_Sharing\API\Server2Server',
  46. 'preLoginNameUsedAsUserName',
  47. ['uid' => &$uid]
  48. );
  49. $this->logger->debug('Got UID: ' . $uid);
  50. $publicKeyCredentialRequestOptions = $this->webAuthnManger->startAuthentication($uid, $this->request->getServerHost());
  51. $this->session->set(self::WEBAUTHN_LOGIN, json_encode($publicKeyCredentialRequestOptions));
  52. $this->session->set(self::WEBAUTHN_LOGIN_UID, $uid);
  53. return new JSONResponse($publicKeyCredentialRequestOptions);
  54. }
  55. #[PublicPage]
  56. #[UseSession]
  57. #[FrontpageRoute(verb: 'POST', url: 'login/webauthn/finish')]
  58. public function finishAuthentication(string $data): JSONResponse {
  59. $this->logger->debug('Validating WebAuthn login');
  60. if (!$this->session->exists(self::WEBAUTHN_LOGIN) || !$this->session->exists(self::WEBAUTHN_LOGIN_UID)) {
  61. $this->logger->debug('Trying to finish WebAuthn login without session data');
  62. return new JSONResponse([], Http::STATUS_BAD_REQUEST);
  63. }
  64. // Obtain the publicKeyCredentialOptions from when we started the registration
  65. $publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::createFromString($this->session->get(self::WEBAUTHN_LOGIN));
  66. $uid = $this->session->get(self::WEBAUTHN_LOGIN_UID);
  67. $this->webAuthnManger->finishAuthentication($publicKeyCredentialRequestOptions, $data, $uid);
  68. //TODO: add other parameters
  69. $loginData = new LoginData(
  70. $this->request,
  71. $uid,
  72. ''
  73. );
  74. $this->webAuthnChain->process($loginData);
  75. return new JSONResponse([
  76. 'defaultRedirectUrl' => $this->urlGenerator->linkToDefaultPageUrl(),
  77. ]);
  78. }
  79. }