mirror of https://github.com/nextcloud/server
Allow using an app token to login with v2 flow auth
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
parent
8c3ab46545
commit
aa3f4bdf63
|
@ -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;
|
||||
|
@ -173,6 +174,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
|
||||
|
@ -196,7 +239,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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -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>
|
||||
|
||||
</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; ?>
|
||||
|
|
Loading…
Reference in New Issue