WebAuthnController.php 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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\UseSession;
  16. use OCP\AppFramework\Http\JSONResponse;
  17. use OCP\IRequest;
  18. use OCP\ISession;
  19. use OCP\Util;
  20. use Psr\Log\LoggerInterface;
  21. use Webauthn\PublicKeyCredentialRequestOptions;
  22. class WebAuthnController extends Controller {
  23. private const WEBAUTHN_LOGIN = 'webauthn_login';
  24. private const WEBAUTHN_LOGIN_UID = 'webauthn_login_uid';
  25. public function __construct(
  26. string $appName,
  27. IRequest $request,
  28. private Manager $webAuthnManger,
  29. private ISession $session,
  30. private LoggerInterface $logger,
  31. private WebAuthnChain $webAuthnChain,
  32. private URLGenerator $urlGenerator,
  33. ) {
  34. parent::__construct($appName, $request);
  35. }
  36. /**
  37. * @NoAdminRequired
  38. * @PublicPage
  39. */
  40. #[UseSession]
  41. #[FrontpageRoute(verb: 'POST', url: 'login/webauthn/start')]
  42. public function startAuthentication(string $loginName): JSONResponse {
  43. $this->logger->debug('Starting WebAuthn login');
  44. $this->logger->debug('Converting login name to UID');
  45. $uid = $loginName;
  46. Util::emitHook(
  47. '\OCA\Files_Sharing\API\Server2Server',
  48. 'preLoginNameUsedAsUserName',
  49. ['uid' => &$uid]
  50. );
  51. $this->logger->debug('Got UID: ' . $uid);
  52. $publicKeyCredentialRequestOptions = $this->webAuthnManger->startAuthentication($uid, $this->request->getServerHost());
  53. $this->session->set(self::WEBAUTHN_LOGIN, json_encode($publicKeyCredentialRequestOptions));
  54. $this->session->set(self::WEBAUTHN_LOGIN_UID, $uid);
  55. return new JSONResponse($publicKeyCredentialRequestOptions);
  56. }
  57. /**
  58. * @NoAdminRequired
  59. * @PublicPage
  60. */
  61. #[UseSession]
  62. #[FrontpageRoute(verb: 'POST', url: 'login/webauthn/finish')]
  63. public function finishAuthentication(string $data): JSONResponse {
  64. $this->logger->debug('Validating WebAuthn login');
  65. if (!$this->session->exists(self::WEBAUTHN_LOGIN) || !$this->session->exists(self::WEBAUTHN_LOGIN_UID)) {
  66. $this->logger->debug('Trying to finish WebAuthn login without session data');
  67. return new JSONResponse([], Http::STATUS_BAD_REQUEST);
  68. }
  69. // Obtain the publicKeyCredentialOptions from when we started the registration
  70. $publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::createFromString($this->session->get(self::WEBAUTHN_LOGIN));
  71. $uid = $this->session->get(self::WEBAUTHN_LOGIN_UID);
  72. $this->webAuthnManger->finishAuthentication($publicKeyCredentialRequestOptions, $data, $uid);
  73. //TODO: add other parameters
  74. $loginData = new LoginData(
  75. $this->request,
  76. $uid,
  77. ''
  78. );
  79. $this->webAuthnChain->process($loginData);
  80. return new JSONResponse([
  81. 'defaultRedirectUrl' => $this->urlGenerator->linkToDefaultPageUrl(),
  82. ]);
  83. }
  84. }