diff options
author | John Molakvoæ <skjnldsv@users.noreply.github.com> | 2021-12-30 08:14:23 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-30 08:14:23 +0100 |
commit | bfaeb6ae64b01d591c8122ccb8ba4f7af98652c7 (patch) | |
tree | e424b97303d34c95befc9bc2a8d43bb590cf3b02 /core | |
parent | bf6388ef2d1b13829ef85dc83d6ccbd5e43759bb (diff) | |
parent | cdda25acb49e50e5989743c0251b394dbbebcaa5 (diff) | |
download | nextcloud-server-bfaeb6ae64b01d591c8122ccb8ba4f7af98652c7.tar.gz nextcloud-server-bfaeb6ae64b01d591c8122ccb8ba4f7af98652c7.zip |
Merge pull request #29531 from nextcloud/bugfix/noid/flow-auth-v2-apptoken
Diffstat (limited to 'core')
-rw-r--r-- | core/Controller/ClientFlowLoginV2Controller.php | 46 | ||||
-rw-r--r-- | core/Service/LoginFlowV2Service.php | 17 | ||||
-rw-r--r-- | core/css/login/authpicker.css | 5 | ||||
-rw-r--r-- | core/routes.php | 1 | ||||
-rw-r--r-- | core/templates/loginflow/authpicker.php | 8 | ||||
-rw-r--r-- | core/templates/loginflowv2/authpicker.php | 18 |
6 files changed, 91 insertions, 4 deletions
diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php index 46031356ba5..ab46cb4b729 100644 --- a/core/Controller/ClientFlowLoginV2Controller.php +++ b/core/Controller/ClientFlowLoginV2Controller.php @@ -27,6 +27,7 @@ declare(strict_types=1); */ namespace OC\Core\Controller; +use OC\Authentication\Exceptions\InvalidTokenException; use OC\Core\Db\LoginFlowV2; use OC\Core\Exception\LoginFlowV2NotFoundException; use OC\Core\Service\LoginFlowV2Service; @@ -175,6 +176,48 @@ class ClientFlowLoginV2Controller extends Controller { } /** + * @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 */ @@ -197,7 +240,10 @@ class ClientFlowLoginV2Controller extends Controller { $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 6f8c7966e27..8710cab5cae 100644 --- a/core/Service/LoginFlowV2Service.php +++ b/core/Service/LoginFlowV2Service.php @@ -186,6 +186,23 @@ class LoginFlowV2Service { 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/css/login/authpicker.css b/core/css/login/authpicker.css index 3603a7906e4..d245c48680f 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/routes.php b/core/routes.php index 5750dac2ad1..c3bbb7337ba 100644 --- a/core/routes.php +++ b/core/routes.php @@ -68,6 +68,7 @@ $application->registerRoutes($this, [ ['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/loginflow/authpicker.php b/core/templates/loginflow/authpicker.php index 128429cb0b3..d8ef2998d13 100644 --- a/core/templates/loginflow/authpicker.php +++ b/core/templates/loginflow/authpicker.php @@ -64,8 +64,8 @@ $urlGenerator = $_['urlGenerator']; <input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>"> <input id="submit-app-token-login" type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Grant access')) ?>"> </form> -</div> -<?php if (empty($_['oauthState'])): ?> -<a id="app-token-login" class="warning" href="#"><?php p($l->t('Alternative log in using app token')) ?></a> -<?php endif; ?> + <?php if (empty($_['oauthState'])): ?> + <a id="app-token-login" class="apptoken-link" href="#"><?php p($l->t('Alternative log in using app token')) ?></a> + <?php endif; ?> +</div> diff --git a/core/templates/loginflowv2/authpicker.php b/core/templates/loginflowv2/authpicker.php index 42eb72aee33..8caa42f2ce8 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 @@ $urlGenerator = $_['urlGenerator']; </a> </p> + <form action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLoginV2.apptokenRedirect')); ?>" method="post" id="app-token-login-field" class="hidden"> + <p class="grouptop"> + <input type="text" name="user" id="user" placeholder="<?php p($l->t('Username')) ?>"> + <label for="user" class="infield"><?php p($l->t('Username')) ?></label> + </p> + <p class="groupbottom"> + <input type="password" name="password" id="password" placeholder="<?php p($l->t('App token')) ?>"> + <label for="password" class="infield"><?php p($l->t('Password')) ?></label> + </p> + <input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" /> + <input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>"> + <input id="submit-app-token-login" type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Grant access')) ?>"> + </form> + + <?php if (empty($_['oauthState'])): ?> + <a id="app-token-login" class="apptoken-link" href="#"><?php p($l->t('Alternative log in using app token')) ?></a> + <?php endif; ?> </div> |