Redirect to ClientLoginFlow and ClientLoginFlowV2 when it was used
Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
parent
4d5fb2628a
commit
0b4fac2edf
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* ownCloud - registration
|
||||
*
|
||||
|
|
@ -7,53 +10,63 @@
|
|||
*
|
||||
* @author Pellaeon Lin <pellaeon@hs.ntnu.edu.tw>
|
||||
* @author Julius Härtl <jus@bitgrid.net>
|
||||
* @author 2020 Joas Schilling <coding@schilljs.com>
|
||||
* @copyright Pellaeon Lin 2014
|
||||
*/
|
||||
|
||||
namespace OCA\Registration\Controller;
|
||||
|
||||
use Exception;
|
||||
use OCA\Registration\Db\Registration;
|
||||
use OCA\Registration\Service\LoginFlowService;
|
||||
use OCA\Registration\Service\MailService;
|
||||
use OCA\Registration\Service\RegistrationException;
|
||||
use OCA\Registration\Service\RegistrationService;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCP\AppFramework\Http\RedirectToDefaultAppResponse;
|
||||
use OCP\AppFramework\Http\Response;
|
||||
use \OCP\IRequest;
|
||||
use \OCP\AppFramework\Http\TemplateResponse;
|
||||
use \OCP\AppFramework\Http\RedirectResponse;
|
||||
use \OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\StandaloneTemplateResponse;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use \OCP\IConfig;
|
||||
use \OCP\IL10N;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
|
||||
class RegisterController extends Controller {
|
||||
|
||||
/** @var IL10N */
|
||||
private $l10n;
|
||||
/** @var IURLGenerator */
|
||||
private $urlgenerator;
|
||||
private $urlGenerator;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var RegistrationService */
|
||||
private $registrationService;
|
||||
/** @var MailService */
|
||||
private $mailService;
|
||||
|
||||
/** @var LoginFlowService */
|
||||
private $loginFlowService;
|
||||
|
||||
public function __construct(
|
||||
$appName,
|
||||
string $appName,
|
||||
IRequest $request,
|
||||
IL10N $l10n,
|
||||
IURLGenerator $urlgenerator,
|
||||
IURLGenerator $urlGenerator,
|
||||
IConfig $config,
|
||||
RegistrationService $registrationService,
|
||||
LoginFlowService $loginFlowService,
|
||||
MailService $mailService
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->l10n = $l10n;
|
||||
$this->urlgenerator = $urlgenerator;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->config = $config;
|
||||
$this->registrationService = $registrationService;
|
||||
$this->loginFlowService = $loginFlowService;
|
||||
$this->mailService = $mailService;
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +115,7 @@ class RegisterController extends Controller {
|
|||
}
|
||||
|
||||
return new RedirectResponse(
|
||||
$this->urlgenerator->linkToRoute(
|
||||
$this->urlGenerator->linkToRoute(
|
||||
'registration.register.showVerificationForm',
|
||||
['secret' => $registration->getClientSecret()]
|
||||
)
|
||||
|
|
@ -120,12 +133,8 @@ class RegisterController extends Controller {
|
|||
public function showVerificationForm(string $secret, string $message = ''): TemplateResponse {
|
||||
try {
|
||||
$this->registrationService->getRegistrationForSecret($secret);
|
||||
} catch (RegistrationException $e) {
|
||||
return new TemplateResponse('core', 'error', [
|
||||
'errors' => [
|
||||
$this->l10n->t('The verification secret does not exist anymore'),
|
||||
],
|
||||
], 'error');
|
||||
} catch (DoesNotExistException $e) {
|
||||
return $this->validateSecretAndTokenErrorPage();
|
||||
}
|
||||
|
||||
return new TemplateResponse('registration', 'form/verification', [
|
||||
|
|
@ -151,16 +160,12 @@ class RegisterController extends Controller {
|
|||
$this->l10n->t('The entered verification code is wrong')
|
||||
);
|
||||
}
|
||||
} catch (RegistrationException $e) {
|
||||
return new TemplateResponse('core', 'error', [
|
||||
'errors' => [
|
||||
$this->l10n->t('The verification secret does not exist anymore'),
|
||||
],
|
||||
], 'error');
|
||||
} catch (DoesNotExistException $e) {
|
||||
return $this->validateSecretAndTokenErrorPage();
|
||||
}
|
||||
|
||||
return new RedirectResponse(
|
||||
$this->urlgenerator->linkToRoute(
|
||||
$this->urlGenerator->linkToRoute(
|
||||
'registration.register.showUserForm',
|
||||
[
|
||||
'secret' => $secret,
|
||||
|
|
@ -176,95 +181,101 @@ class RegisterController extends Controller {
|
|||
*
|
||||
* @param string $secret
|
||||
* @param string $token
|
||||
* @param string $username
|
||||
* @param string $message
|
||||
* @return TemplateResponse
|
||||
*/
|
||||
public function showUserForm(string $secret, string $token): TemplateResponse {
|
||||
public function showUserForm(string $secret, string $token, string $username = '', string $message = ''): TemplateResponse {
|
||||
try {
|
||||
$registration = $this->registrationService->getRegistrationForSecret($secret);
|
||||
|
||||
if ($registration->getToken() !== $token) {
|
||||
throw new RegistrationException('Invalid verification token');
|
||||
}
|
||||
$registration = $this->validateSecretAndToken($secret, $token);
|
||||
} catch (RegistrationException $e) {
|
||||
return new TemplateResponse('core', 'error', [
|
||||
'errors' => [
|
||||
$this->l10n->t('The verification secret does not exist anymore or the verification token is invalid'),
|
||||
],
|
||||
], 'error');
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var Registration $registration */
|
||||
$registration = $this->registrationService->verifyToken($token);
|
||||
$this->registrationService->confirmEmail($registration);
|
||||
|
||||
// create account without form if username/password are already stored
|
||||
if ($registration->getUsername() !== "" && $registration->getPassword() !== "") {
|
||||
$this->registrationService->createAccount($registration);
|
||||
return new TemplateResponse('registration', 'message',
|
||||
['msg' => $this->l10n->t('Your account has been successfully created, you can <a href="%s">log in now</a>.', [$this->urlgenerator->getAbsoluteURL('/')])],
|
||||
'guest'
|
||||
);
|
||||
return $this->validateSecretAndTokenErrorPage();
|
||||
}
|
||||
|
||||
return new TemplateResponse('registration', 'form/user', [
|
||||
'email' => $registration->getEmail(),
|
||||
'email_is_login' => $this->config->getAppValue('registration', 'email_is_login', '0') === '1',
|
||||
'token' => $registration->getToken(),
|
||||
'username' => $username,
|
||||
'message' => $message,
|
||||
], 'guest');
|
||||
} catch (RegistrationException $exception) {
|
||||
return $this->renderError($exception->getMessage(), $exception->getHint());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @PublicPage
|
||||
* @UseSession
|
||||
*
|
||||
* @param $token
|
||||
* @param string $secret
|
||||
* @param string $token
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return RedirectResponse|TemplateResponse
|
||||
*/
|
||||
public function submitUserForm($token) {
|
||||
$registration = $this->registrationService->getRegistrationForToken($token);
|
||||
public function submitUserForm(string $secret, string $token, string $username, string $password): Response {
|
||||
try {
|
||||
$registration = $this->validateSecretAndToken($secret, $token);
|
||||
} catch (RegistrationException $e) {
|
||||
return $this->validateSecretAndTokenErrorPage();
|
||||
}
|
||||
|
||||
if ($this->config->getAppValue('registration', 'email_is_login', '0') === '1') {
|
||||
$username = $registration->getEmail();
|
||||
} else {
|
||||
$username = $this->request->getParam('username');
|
||||
}
|
||||
$password = $this->request->getParam('password');
|
||||
|
||||
try {
|
||||
$user = $this->registrationService->createAccount($registration, $username, $password);
|
||||
} catch (\Exception $exception) {
|
||||
// Render form with previously sent values
|
||||
return new TemplateResponse('registration', 'form',
|
||||
[
|
||||
'email' => $registration->getEmail(),
|
||||
'entered_data' => ['user' => $username],
|
||||
'errormsgs' => [$exception->getMessage()],
|
||||
'token' => $token
|
||||
], 'guest');
|
||||
} catch (Exception $exception) {
|
||||
return $this->showUserForm($secret, $token, $username, $exception->getMessage());
|
||||
}
|
||||
|
||||
if ($user->isEnabled()) {
|
||||
// log the user
|
||||
return $this->registrationService->loginUser($user->getUID(), $username, $password, false);
|
||||
} else {
|
||||
// warn the user their account needs admin validation
|
||||
return new TemplateResponse(
|
||||
'registration',
|
||||
'message',
|
||||
['msg' => $this->l10n->t("Your account has been successfully created, but it still needs approval from an administrator.")],
|
||||
'guest');
|
||||
$this->registrationService->loginUser($user->getUID(), $user->getUID(), $password);
|
||||
|
||||
if ($this->loginFlowService->isUsingLoginFlow(2)) {
|
||||
$response = $this->loginFlowService->tryLoginFlowV2($user);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
private function renderError($error, $hint="") {
|
||||
return new TemplateResponse('', 'error', [
|
||||
'errors' => [[
|
||||
'error' => $error,
|
||||
'hint' => $hint
|
||||
]]
|
||||
if ($this->loginFlowService->isUsingLoginFlow(1)) {
|
||||
$response = $this->loginFlowService->tryLoginFlowV1();
|
||||
if ($response instanceof Response && $response->getStatus() === Http::STATUS_SEE_OTHER) {
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
return new RedirectToDefaultAppResponse();
|
||||
}
|
||||
|
||||
// warn the user their account needs admin validation
|
||||
return new StandaloneTemplateResponse('registration', 'approval-required', [], 'guest');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $secret
|
||||
* @param string $token
|
||||
* @return Registration
|
||||
* @throws RegistrationException
|
||||
*/
|
||||
protected function validateSecretAndToken(string $secret, string $token): Registration {
|
||||
try {
|
||||
$registration = $this->registrationService->getRegistrationForSecret($secret);
|
||||
} catch (DoesNotExistException $e) {
|
||||
throw new RegistrationException('Invalid secret');
|
||||
}
|
||||
|
||||
if ($registration->getToken() !== $token) {
|
||||
throw new RegistrationException('Invalid token');
|
||||
}
|
||||
|
||||
return $registration;
|
||||
}
|
||||
|
||||
protected function validateSecretAndTokenErrorPage(): TemplateResponse {
|
||||
return new TemplateResponse('core', 'error', [
|
||||
'errors' => [
|
||||
$this->l10n->t('The verification failed.'),
|
||||
],
|
||||
], 'error');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Registration\Service;
|
||||
|
||||
use OC\Core\Controller\ClientFlowLoginController;
|
||||
use OC\Core\Controller\ClientFlowLoginV2Controller;
|
||||
use OC\Core\Service\LoginFlowV2Service;
|
||||
use OCP\AppFramework\Http\Response;
|
||||
use OCP\AppFramework\Http\StandaloneTemplateResponse;
|
||||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IUser;
|
||||
|
||||
class LoginFlowService {
|
||||
|
||||
/** @var IRequest */
|
||||
protected $request;
|
||||
/** @var ISession */
|
||||
protected $session;
|
||||
/** @var LoginFlowV2Service */
|
||||
protected $loginFlowV2Service;
|
||||
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
ISession $session,
|
||||
LoginFlowV2Service $loginFlowV2Service
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->session = $session;
|
||||
$this->loginFlowV2Service = $loginFlowV2Service;
|
||||
}
|
||||
|
||||
public function isUsingLoginFlow(?int $version = null): bool {
|
||||
if (($version === 1 || $version === null) && $this->session->get(ClientFlowLoginController::STATE_NAME) !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (($version === 2 || $version === null) && $this->session->get(ClientFlowLoginV2Controller::TOKEN_NAME) !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function tryLoginFlowV1(): ?Response {
|
||||
/** @var ClientFlowLoginController $controller */
|
||||
$container = \OC::$server->getRegisteredAppContainer('core');
|
||||
$controller = $container->query(ClientFlowLoginController::class);
|
||||
return $controller->generateAppPassword(
|
||||
$this->session->get(ClientFlowLoginController::STATE_NAME)
|
||||
);
|
||||
}
|
||||
|
||||
public function tryLoginFlowV2(IUser $user): ?StandaloneTemplateResponse {
|
||||
$result = $this->loginFlowV2Service->flowDone(
|
||||
$this->session->get(ClientFlowLoginV2Controller::TOKEN_NAME),
|
||||
$this->session->getId(),
|
||||
$this->getServerPath(),
|
||||
$user->getUID()
|
||||
);
|
||||
|
||||
if (!$result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new StandaloneTemplateResponse(
|
||||
'core',
|
||||
'loginflowv2/done',
|
||||
[],
|
||||
'guest'
|
||||
);
|
||||
}
|
||||
|
||||
private function getServerPath(): string {
|
||||
$serverPostfix = '';
|
||||
|
||||
if (strpos($this->request->getRequestUri(), '/index.php') !== false) {
|
||||
$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/index.php'));
|
||||
} elseif (strpos($this->request->getRequestUri(), '/login/v2') !== false) {
|
||||
$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/login/v2'));
|
||||
}
|
||||
|
||||
$protocol = $this->request->getServerProtocol();
|
||||
return $protocol . '://' . $this->request->getServerHost() . $serverPostfix;
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ use OCP\ILogger;
|
|||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\Security\ICrypto;
|
||||
use OCP\Session\Exceptions\SessionNotAvailableException;
|
||||
use \OCP\IUserManager;
|
||||
|
|
@ -247,12 +248,12 @@ class RegistrationService {
|
|||
|
||||
/**
|
||||
* @param $registration
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string|null $username
|
||||
* @param string|null $password
|
||||
* @return \OCP\IUser
|
||||
* @throws RegistrationException|InvalidTokenException
|
||||
*/
|
||||
public function createAccount(Registration $registration, $username = null, $password = null) {
|
||||
public function createAccount(Registration $registration, ?string $username = null, ?string $password = null) {
|
||||
if ($password === null && $registration->getPassword() === null) {
|
||||
$generatedPassword = $this->generateRandomDeviceToken();
|
||||
$registration->setPassword($this->crypto->encrypt($generatedPassword));
|
||||
|
|
@ -414,33 +415,18 @@ class RegistrationService {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $userId
|
||||
* @param $username
|
||||
* @param $password
|
||||
* @param $decrypt
|
||||
* @return RedirectResponse|TemplateResponse
|
||||
* @param string $userId
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param bool $decrypt
|
||||
*/
|
||||
public function loginUser($userId, $username, $password, $decrypt = false) {
|
||||
public function loginUser(string $userId, string $username, string $password, bool $decrypt = false): void {
|
||||
if ($decrypt) {
|
||||
$password = $this->crypto->decrypt($password);
|
||||
}
|
||||
if (method_exists($this->usersession, 'createSessionToken')) {
|
||||
|
||||
$this->usersession->login($username, $password);
|
||||
$this->usersession->createSessionToken($this->request, $userId, $username, $password);
|
||||
return new RedirectResponse($this->urlGenerator->linkTo('', 'index.php'));
|
||||
} elseif (\OC_User::login($username, $password)) {
|
||||
$this->cleanupLoginTokens($userId);
|
||||
// FIXME unsetMagicInCookie will fail from session already closed, so now we always remember
|
||||
$logintoken = $this->random->generate(32);
|
||||
$this->config->setUserValue($userId, 'login_token', $logintoken, time());
|
||||
\OC_User::setMagicInCookie($userId, $logintoken);
|
||||
\OC_Util::redirectToDefaultPage();
|
||||
}
|
||||
// Render message in case redirect failed
|
||||
return new TemplateResponse('registration', 'message',
|
||||
['msg' => $this->l10n->t('Your account has been successfully created, you can <a href="%s">log in now</a>.', [$this->urlGenerator->getAbsoluteURL('/')])]
|
||||
, 'guest'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/** @var array $_ */
|
||||
/** @var \OCP\IL10N $l */
|
||||
style('registration', 'style');
|
||||
?>
|
||||
<div class="error">
|
||||
<h2><?php p($l->t('Approval required')) ?></h2>
|
||||
<ul>
|
||||
<li>
|
||||
<p><?php p($l->t('Your account has been successfully created, but it still needs approval from an administrator.')) ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
/** @var array $_ */
|
||||
/** @var \OCP\IL10N $l */
|
||||
style('registration', 'style');
|
||||
?>
|
||||
<ul class="error-wide">
|
||||
<li class='error'><?php p($l->t('Registration is only allowed for the following domains:')); ?>
|
||||
<?php
|
||||
foreach ($_['domains'] as $domain) {
|
||||
echo "<p class='hint'>";
|
||||
p($domain);
|
||||
echo "</p>";
|
||||
}
|
||||
?>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
/** @var array $_ */
|
||||
/** @var \OCP\IL10N $l */
|
||||
style('registration', 'style');
|
||||
?>
|
||||
<ul class="msg error-wide nc-theming-main-text">
|
||||
<li><?php print_unescaped($_['msg'])?></li>
|
||||
</ul>
|
||||
Loading…
Reference in New Issue