From aa3f4bdf6351a600f1b422c6ab1daf75727c265e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 3 Nov 2021 10:54:02 +0100 Subject: [PATCH 1/2] Allow using an app token to login with v2 flow auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- .../ClientFlowLoginV2Controller.php | 46 +++++++++++++++++++ core/Service/LoginFlowV2Service.php | 17 +++++++ core/routes.php | 1 + core/templates/loginflowv2/authpicker.php | 18 ++++++++ 4 files changed, 82 insertions(+) diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php index 205c1ff8a1c74..84321d33e13fb 100644 --- a/core/Controller/ClientFlowLoginV2Controller.php +++ b/core/Controller/ClientFlowLoginV2Controller.php @@ -27,6 +27,7 @@ */ namespace OC\Core\Controller; +use OC\Authentication\Exceptions\InvalidTokenException; use OC\Core\Db\LoginFlowV2; use OC\Core\Exception\LoginFlowV2NotFoundException; use OC\Core\Service\LoginFlowV2Service; @@ -173,6 +174,48 @@ public function grantPage(string $stateToken): StandaloneTemplateResponse { ); } + /** + * @PublicPage + */ + public function apptokenRedirect(string $stateToken, string $user, string $password) { + if (!$this->isValidStateToken($stateToken)) { + return $this->stateTokenForbiddenResponse(); + } + + try { + $this->getFlowByLoginToken(); + } catch (LoginFlowV2NotFoundException $e) { + return $this->loginTokenForbiddenResponse(); + } + + $loginToken = $this->session->get(self::TOKEN_NAME); + + // Clear session variables + $this->session->remove(self::TOKEN_NAME); + $this->session->remove(self::STATE_NAME); + + try { + $token = \OC::$server->get(\OC\Authentication\Token\IProvider::class)->getToken($password); + if ($token->getLoginName() !== $user) { + throw new InvalidTokenException('login name does not match'); + } + } catch (InvalidTokenException $e) { + $response = new StandaloneTemplateResponse( + $this->appName, + '403', + [ + 'message' => $this->l10n->t('Invalid app password'), + ], + 'guest' + ); + $response->setStatus(Http::STATUS_FORBIDDEN); + return $response; + } + + $result = $this->loginFlowV2Service->flowDoneWithAppPassword($loginToken, $this->getServerPath(), $this->userId, $password); + return $this->handleFlowDone($result); + } + /** * @NoAdminRequired * @UseSession @@ -196,7 +239,10 @@ public function generateAppPassword(string $stateToken): Response { $sessionId = $this->session->getId(); $result = $this->loginFlowV2Service->flowDone($loginToken, $sessionId, $this->getServerPath(), $this->userId); + return $this->handleFlowDone($result); + } + private function handleFlowDone(bool $result): StandaloneTemplateResponse { if ($result) { return new StandaloneTemplateResponse( $this->appName, diff --git a/core/Service/LoginFlowV2Service.php b/core/Service/LoginFlowV2Service.php index 6f8c7966e2733..8710cab5cae64 100644 --- a/core/Service/LoginFlowV2Service.php +++ b/core/Service/LoginFlowV2Service.php @@ -186,6 +186,23 @@ public function flowDone(string $loginToken, string $sessionId, string $server, return true; } + public function flowDoneWithAppPassword(string $loginToken, string $server, string $loginName, string $appPassword): bool { + try { + $data = $this->mapper->getByLoginToken($loginToken); + } catch (DoesNotExistException $e) { + return false; + } + + $data->setLoginName($loginName); + $data->setServer($server); + + // Properly encrypt + $data->setAppPassword($this->encryptPassword($appPassword, $data->getPublicKey())); + + $this->mapper->update($data); + return true; + } + public function createTokens(string $userAgent): LoginFlowV2Tokens { $flow = new LoginFlowV2(); $pollToken = $this->random->generate(128, ISecureRandom::CHAR_DIGITS.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER); diff --git a/core/routes.php b/core/routes.php index 5750dac2ad1b7..c3bbb7337ba85 100644 --- a/core/routes.php +++ b/core/routes.php @@ -68,6 +68,7 @@ ['name' => 'ClientFlowLoginV2#grantPage', 'url' => '/login/v2/grant', 'verb' => 'GET'], ['name' => 'ClientFlowLoginV2#generateAppPassword', 'url' => '/login/v2/grant', 'verb' => 'POST'], ['name' => 'ClientFlowLoginV2#init', 'url' => '/login/v2', 'verb' => 'POST'], + ['name' => 'ClientFlowLoginV2#apptokenRedirect', 'url' => '/login/v2/apptoken', 'verb' => 'POST'], ['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'], ['name' => 'TwoFactorChallenge#showChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'GET'], ['name' => 'TwoFactorChallenge#solveChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'POST'], diff --git a/core/templates/loginflowv2/authpicker.php b/core/templates/loginflowv2/authpicker.php index ce993ea20920d..468eed99e35c3 100644 --- a/core/templates/loginflowv2/authpicker.php +++ b/core/templates/loginflowv2/authpicker.php @@ -20,6 +20,7 @@ */ style('core', 'login/authpicker'); +script('core', 'login/authpicker'); /** @var array $_ */ /** @var \OCP\IURLGenerator $urlGenerator */ @@ -50,4 +51,21 @@

+ + + + t('Alternative log in using app token')) ?> + From cdda25acb49e50e5989743c0251b394dbbebcaa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Fri, 3 Dec 2021 08:44:09 +0100 Subject: [PATCH 2/2] Adjust auth token link design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/css/login/authpicker.css | 5 +++++ core/templates/loginflow/authpicker.php | 8 ++++---- core/templates/loginflowv2/authpicker.php | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/css/login/authpicker.css b/core/css/login/authpicker.css index 3603a7906e45f..d245c48680ff4 100644 --- a/core/css/login/authpicker.css +++ b/core/css/login/authpicker.css @@ -7,3 +7,8 @@ border-radius: 3px; cursor: default; } + +.apptoken-link { + margin: 20px; + display: block; +} diff --git a/core/templates/loginflow/authpicker.php b/core/templates/loginflow/authpicker.php index 02b4b9cc003b4..e0980a8d2b32e 100644 --- a/core/templates/loginflow/authpicker.php +++ b/core/templates/loginflow/authpicker.php @@ -64,8 +64,8 @@ - - -t('Alternative log in using app token')) ?> - + + t('Alternative log in using app token')) ?> + + diff --git a/core/templates/loginflowv2/authpicker.php b/core/templates/loginflowv2/authpicker.php index 468eed99e35c3..af49ed6d760fa 100644 --- a/core/templates/loginflowv2/authpicker.php +++ b/core/templates/loginflowv2/authpicker.php @@ -65,7 +65,7 @@ + + t('Alternative log in using app token')) ?> + - - t('Alternative log in using app token')) ?> -