first commit
This commit is contained in:
@@ -0,0 +1,503 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file pages/login/LoginHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class LoginHandler
|
||||
*
|
||||
* @ingroup pages_login
|
||||
*
|
||||
* @brief Handle login/logout requests.
|
||||
*/
|
||||
|
||||
namespace PKP\pages\login;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\facades\Repo;
|
||||
use APP\handler\Handler;
|
||||
use APP\template\TemplateManager;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use PKP\config\Config;
|
||||
use PKP\context\Context;
|
||||
use PKP\core\PKPApplication;
|
||||
use PKP\core\PKPRequest;
|
||||
use PKP\core\PKPString;
|
||||
use PKP\form\validation\FormValidatorReCaptcha;
|
||||
use PKP\mail\mailables\PasswordResetRequested;
|
||||
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
|
||||
use PKP\security\Role;
|
||||
use PKP\security\Validation;
|
||||
use PKP\session\SessionManager;
|
||||
use PKP\site\Site;
|
||||
use PKP\user\form\LoginChangePasswordForm;
|
||||
use PKP\user\form\ResetPasswordForm;
|
||||
use PKP\user\User;
|
||||
|
||||
class LoginHandler extends Handler
|
||||
{
|
||||
/**
|
||||
* @copydoc PKPHandler::authorize()
|
||||
*/
|
||||
public function authorize($request, &$args, $roleAssignments)
|
||||
{
|
||||
switch ($op = $request->getRequestedOp()) {
|
||||
case 'signInAsUser':
|
||||
$this->addPolicy(new RoleBasedHandlerOperationPolicy($request, [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN], ['signInAsUser']));
|
||||
break;
|
||||
}
|
||||
return parent::authorize($request, $args, $roleAssignments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display user login form.
|
||||
* Redirect to user index page if user is already validated.
|
||||
*/
|
||||
public function index($args, $request)
|
||||
{
|
||||
$this->setupTemplate($request);
|
||||
if (Validation::isLoggedIn()) {
|
||||
$this->sendHome($request);
|
||||
}
|
||||
|
||||
if (Config::getVar('security', 'force_login_ssl') && $request->getProtocol() != 'https') {
|
||||
// Force SSL connections for login
|
||||
$request->redirectSSL();
|
||||
}
|
||||
|
||||
$sessionManager = SessionManager::getManager();
|
||||
$session = $sessionManager->getUserSession();
|
||||
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->assign([
|
||||
'loginMessage' => $request->getUserVar('loginMessage'),
|
||||
'username' => $session->getSessionVar('email') ?? $session->getSessionVar('username'),
|
||||
'remember' => $request->getUserVar('remember'),
|
||||
'source' => $request->getUserVar('source'),
|
||||
'showRemember' => Config::getVar('general', 'session_lifetime') > 0,
|
||||
]);
|
||||
|
||||
// For force_login_ssl with base_url[...]: make sure SSL used for login form
|
||||
$loginUrl = $request->url(null, 'login', 'signIn');
|
||||
if (Config::getVar('security', 'force_login_ssl')) {
|
||||
$loginUrl = PKPString::regexp_replace('/^http:/', 'https:', $loginUrl);
|
||||
}
|
||||
$templateMgr->assign('loginUrl', $loginUrl);
|
||||
|
||||
$isCaptchaEnabled = Config::getVar('captcha', 'recaptcha') && Config::getVar('captcha', 'captcha_on_login');
|
||||
if ($isCaptchaEnabled) {
|
||||
$templateMgr->assign('recaptchaPublicKey', Config::getVar('captcha', 'recaptcha_public_key'));
|
||||
}
|
||||
|
||||
$templateMgr->display('frontend/pages/userLogin.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* After a login has completed, direct the user somewhere.
|
||||
*
|
||||
* @param PKPRequest $request
|
||||
*/
|
||||
public function _redirectAfterLogin($request)
|
||||
{
|
||||
$context = $this->getTargetContext($request);
|
||||
// If there's a context, send them to the dashboard after login.
|
||||
if ($context && $request->getUserVar('source') == '' && array_intersect(
|
||||
[Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_AUTHOR, Role::ROLE_ID_REVIEWER, Role::ROLE_ID_ASSISTANT],
|
||||
(array) $this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES)
|
||||
)) {
|
||||
return $request->redirect($context->getPath(), 'dashboard');
|
||||
}
|
||||
|
||||
$request->getRouter()->redirectHome($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a user's credentials and log the user in.
|
||||
*/
|
||||
public function signIn($args, $request)
|
||||
{
|
||||
$this->setupTemplate($request);
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
|
||||
if (Validation::isLoggedIn()) {
|
||||
$this->sendHome($request);
|
||||
}
|
||||
if (Config::getVar('security', 'force_login_ssl') && $request->getProtocol() != 'https') {
|
||||
// Force SSL connections for login
|
||||
$request->redirectSSL();
|
||||
}
|
||||
|
||||
$error = null;
|
||||
$isCaptchaEnabled = Config::getVar('captcha', 'captcha_on_login') && Config::getVar('captcha', 'recaptcha');
|
||||
if ($isCaptchaEnabled) {
|
||||
$templateMgr->assign('recaptchaPublicKey', Config::getVar('captcha', 'recaptcha_public_key'));
|
||||
try {
|
||||
FormValidatorReCaptcha::validateResponse($request->getUserVar('g-recaptcha-response'), $request->getRemoteAddr(), $request->getServerHost());
|
||||
} catch (Exception $exception) {
|
||||
$error = 'common.captcha.error.missing-input-response';
|
||||
}
|
||||
}
|
||||
|
||||
$username = $request->getUserVar('username');
|
||||
$reason = null;
|
||||
$user = $error || !strlen($username ?? '')
|
||||
? null
|
||||
: Validation::login($username, $request->getUserVar('password'), $reason, !!$request->getUserVar('remember'));
|
||||
if ($user) {
|
||||
if ($user->getMustChangePassword()) {
|
||||
// User must change their password in order to log in
|
||||
Validation::logout();
|
||||
$request->redirect(null, null, 'changePassword', $user->getUsername());
|
||||
}
|
||||
$source = $request->getUserVar('source');
|
||||
if (preg_match('#^/\w#', (string) $source) === 1) {
|
||||
$request->redirectUrl($source);
|
||||
}
|
||||
$redirectNonSsl = Config::getVar('security', 'force_login_ssl') && !Config::getVar('security', 'force_ssl');
|
||||
if ($redirectNonSsl) {
|
||||
$request->redirectNonSSL();
|
||||
}
|
||||
$this->_redirectAfterLogin($request);
|
||||
}
|
||||
|
||||
if ($reason) {
|
||||
$error = 'user.login.accountDisabledWithReason';
|
||||
} elseif ($reason !== null) {
|
||||
$error = 'user.login.accountDisabled';
|
||||
}
|
||||
$error ??= 'user.login.loginError';
|
||||
|
||||
|
||||
$templateMgr->assign([
|
||||
'username' => $username,
|
||||
'remember' => $request->getUserVar('remember'),
|
||||
'source' => $request->getUserVar('source'),
|
||||
'showRemember' => Config::getVar('general', 'session_lifetime') > 0,
|
||||
'error' => $error,
|
||||
'reason' => $reason,
|
||||
]);
|
||||
$templateMgr->display('frontend/pages/userLogin.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a user out.
|
||||
*/
|
||||
public function signOut($args, $request)
|
||||
{
|
||||
$this->setupTemplate($request);
|
||||
if (Validation::isLoggedIn()) {
|
||||
Validation::logout();
|
||||
}
|
||||
|
||||
$source = $request->getUserVar('source');
|
||||
if (isset($source) && !empty($source)) {
|
||||
$request->redirectUrl($request->getProtocol() . '://' . $request->getServerHost() . $source, false);
|
||||
} else {
|
||||
$request->redirect(null, $request->getRequestedPage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display form to reset a user's password.
|
||||
*/
|
||||
public function lostPassword($args, $request)
|
||||
{
|
||||
if (Validation::isLoggedIn()) {
|
||||
$this->sendHome($request);
|
||||
}
|
||||
|
||||
$this->setupTemplate($request);
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->display('frontend/pages/userLostPassword.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to reset a user's password
|
||||
*/
|
||||
public function requestResetPassword($args, $request)
|
||||
{
|
||||
$this->setupTemplate($request);
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
|
||||
$email = $request->getUserVar('email');
|
||||
$user = Repo::user()->getByEmail($email, true); /** @var User $user */
|
||||
|
||||
if ($user !== null) {
|
||||
|
||||
if ($user->getDisabled()) {
|
||||
$templateMgr
|
||||
->assign([
|
||||
'error' => 'user.login.lostPassword.confirmationSentFailedWithReason',
|
||||
'reason' => empty($reason = $user->getDisabledReason() ?? '')
|
||||
? __('user.login.accountDisabled')
|
||||
: __('user.login.accountDisabledWithReason', ['reason' => htmlspecialchars($reason)])
|
||||
])
|
||||
->display('frontend/pages/userLostPassword.tpl');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Send email confirming password reset
|
||||
$site = $request->getSite(); /** @var Site $site */
|
||||
$context = $request->getContext(); /** @var Context $context */
|
||||
$template = Repo::emailTemplate()->getByKey(
|
||||
$context ? $context->getId() : PKPApplication::CONTEXT_SITE,
|
||||
PasswordResetRequested::getEmailTemplateKey()
|
||||
);
|
||||
$mailable = (new PasswordResetRequested($site))
|
||||
->recipients($user)
|
||||
->from($site->getLocalizedContactEmail(), $site->getLocalizedContactName())
|
||||
->body($template->getLocalizedData('body'))
|
||||
->subject($template->getLocalizedData('subject'));
|
||||
Mail::send($mailable);
|
||||
|
||||
}
|
||||
|
||||
$templateMgr->assign([
|
||||
'pageTitle' => 'user.login.resetPassword',
|
||||
'message' => 'user.login.lostPassword.confirmationSent',
|
||||
'backLink' => $request->url(null, $request->getRequestedPage(), null, null),
|
||||
'backLinkLabel' => 'user.login',
|
||||
])->display('frontend/pages/message.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the password reset form to reset user's password
|
||||
*
|
||||
* @param array $args first param contains the username of the user whose password is to be reset
|
||||
*/
|
||||
public function resetPassword($args, $request)
|
||||
{
|
||||
if (Validation::isLoggedIn()) {
|
||||
$this->sendHome($request);
|
||||
}
|
||||
|
||||
$this->_isBackendPage = true;
|
||||
$this->setupTemplate($request);
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->setupBackendPage();
|
||||
$templateMgr->assign([
|
||||
'pageTitle' => 'user.login.resetPassword',
|
||||
]);
|
||||
|
||||
$username = $args[0] ?? null;
|
||||
$confirmHash = $request->getUserVar('confirm');
|
||||
|
||||
if ($username == null || ($user = Repo::user()->getByUsername($username, true)) == null) {
|
||||
return $request->redirect(null, null, 'lostPassword');
|
||||
}
|
||||
|
||||
if ($user->getDisabled()) {
|
||||
$templateMgr
|
||||
->assign([
|
||||
'backLink' => $request->url(null, $request->getRequestedPage()),
|
||||
'backLinkLabel' => 'user.login',
|
||||
'messageTranslated' => __('user.login.lostPassword.confirmationSentFailedWithReason', [
|
||||
'reason' => empty($reason = $user->getDisabledReason() ?? '')
|
||||
? __('user.login.accountDisabled')
|
||||
: __('user.login.accountDisabledWithReason', ['reason' => htmlspecialchars($reason)])
|
||||
]),
|
||||
])
|
||||
->display('frontend/pages/message.tpl');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$passwordResetForm = new ResetPasswordForm($user, $request->getSite(), $confirmHash);
|
||||
$passwordResetForm->initData();
|
||||
|
||||
$passwordResetForm->validatePasswordResetHash()
|
||||
? $passwordResetForm->display($request)
|
||||
: $passwordResetForm->displayInvalidHashErrorMessage($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset a user's password
|
||||
*
|
||||
* @param array $args first param contains the username of the user whose password is to be reset
|
||||
*/
|
||||
public function updateResetPassword($args, $request)
|
||||
{
|
||||
$this->_isBackendPage = true;
|
||||
$this->setupTemplate($request);
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
|
||||
$username = $request->getUserVar('username');
|
||||
$confirmHash = $request->getUserVar('hash');
|
||||
|
||||
if ($username == null || ($user = Repo::user()->getByUsername($username, true)) == null) {
|
||||
return $request->redirect(null, null, 'lostPassword');
|
||||
}
|
||||
|
||||
$passwordResetForm = new ResetPasswordForm($user, $request->getSite(), $confirmHash);
|
||||
$passwordResetForm->readInputData();
|
||||
|
||||
if (!$passwordResetForm->validatePasswordResetHash()) {
|
||||
return $passwordResetForm->displayInvalidHashErrorMessage($request);
|
||||
}
|
||||
|
||||
if ($passwordResetForm->validate()) {
|
||||
if ($passwordResetForm->execute()) {
|
||||
$templateMgr->assign([
|
||||
'pageTitle' => 'user.login.resetPassword',
|
||||
'message' => 'user.login.resetPassword.passwordUpdated',
|
||||
'backLink' => $request->url(null, $request->getRequestedPage(), null, null, ['username' => $user->getUsername()]),
|
||||
'backLinkLabel' => 'user.login',
|
||||
]);
|
||||
|
||||
$templateMgr->display('frontend/pages/message.tpl');
|
||||
}
|
||||
} else {
|
||||
$passwordResetForm->display($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display form to change user's password.
|
||||
*
|
||||
* @param array $args first argument may contain user's username
|
||||
*/
|
||||
public function changePassword($args, $request)
|
||||
{
|
||||
$this->_isBackendPage = true;
|
||||
$this->setupTemplate($request);
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->setupBackendPage();
|
||||
$templateMgr->assign([
|
||||
'pageTitle' => __('user.changePassword'),
|
||||
]);
|
||||
|
||||
$passwordForm = new LoginChangePasswordForm($request->getSite());
|
||||
$passwordForm->initData();
|
||||
if (isset($args[0])) {
|
||||
$passwordForm->setData('username', $args[0]);
|
||||
}
|
||||
$passwordForm->display($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save user's new password.
|
||||
*/
|
||||
public function savePassword($args, $request)
|
||||
{
|
||||
$this->_isBackendPage = true;
|
||||
$this->setupTemplate($request);
|
||||
|
||||
$passwordForm = new LoginChangePasswordForm($request->getSite());
|
||||
$passwordForm->readInputData();
|
||||
|
||||
if ($passwordForm->validate()) {
|
||||
if ($passwordForm->execute()) {
|
||||
$user = Validation::login($passwordForm->getData('username'), $passwordForm->getData('password'), $reason);
|
||||
|
||||
$sessionManager = SessionManager::getManager();
|
||||
$sessionManager->invalidateSessions($user->getId(), $sessionManager->getUserSession()->getId());
|
||||
}
|
||||
$this->sendHome($request);
|
||||
} else {
|
||||
$passwordForm->display($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign in as another user.
|
||||
*
|
||||
* @param array $args ($userId)
|
||||
* @param PKPRequest $request
|
||||
*/
|
||||
public function signInAsUser($args, $request)
|
||||
{
|
||||
if (isset($args[0]) && !empty($args[0])) {
|
||||
$userId = (int)$args[0];
|
||||
$session = $request->getSession();
|
||||
if (Validation::getAdministrationLevel($userId, $session->getUserId()) !== Validation::ADMINISTRATION_FULL) {
|
||||
$this->setupTemplate($request);
|
||||
// We don't have administrative rights
|
||||
// over this user. Display an error.
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->assign([
|
||||
'pageTitle' => 'manager.people',
|
||||
'errorMsg' => 'manager.people.noAdministrativeRights',
|
||||
'backLink' => $request->url(null, null, 'people', 'all'),
|
||||
'backLinkLabel' => 'manager.people.allUsers',
|
||||
]);
|
||||
return $templateMgr->display('frontend/pages/error.tpl');
|
||||
}
|
||||
|
||||
$newUser = Repo::user()->get($userId, true);
|
||||
|
||||
if (isset($newUser) && $session->getUserId() != $newUser->getId()) {
|
||||
$session->setSessionVar('signedInAs', $session->getUserId());
|
||||
$session->setSessionVar('userId', $userId);
|
||||
$session->setUserId($userId);
|
||||
$session->setSessionVar('username', $newUser->getUsername());
|
||||
$this->_redirectByURL($request);
|
||||
}
|
||||
}
|
||||
|
||||
$request->redirect(null, $request->getRequestedPage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restore original user account after signing in as a user.
|
||||
*
|
||||
* @param array $args
|
||||
* @param PKPRequest $request
|
||||
*/
|
||||
public function signOutAsUser($args, $request)
|
||||
{
|
||||
$session = $request->getSession();
|
||||
$signedInAs = $session->getSessionVar('signedInAs');
|
||||
|
||||
if (isset($signedInAs) && !empty($signedInAs)) {
|
||||
$signedInAs = (int)$signedInAs;
|
||||
|
||||
$oldUser = Repo::user()->get($signedInAs, true);
|
||||
|
||||
$session->unsetSessionVar('signedInAs');
|
||||
|
||||
if (isset($oldUser)) {
|
||||
$session->setSessionVar('userId', $signedInAs);
|
||||
$session->setUserId($signedInAs);
|
||||
$session->setSessionVar('username', $oldUser->getUsername());
|
||||
}
|
||||
}
|
||||
$this->_redirectByURL($request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Redirect to redirectURL if exists else send to Home
|
||||
*
|
||||
* @param PKPRequest $request
|
||||
*/
|
||||
public function _redirectByURL($request)
|
||||
{
|
||||
$requestVars = $request->getUserVars();
|
||||
if (isset($requestVars['redirectUrl']) && !empty($requestVars['redirectUrl'])) {
|
||||
$request->redirectUrl($requestVars['redirectUrl']);
|
||||
} else {
|
||||
$this->sendHome($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the user "home" (typically to the dashboard, but that may not
|
||||
* always be available).
|
||||
*
|
||||
* @param PKPRequest $request
|
||||
*/
|
||||
protected function sendHome($request)
|
||||
{
|
||||
if ($request->getContext()) {
|
||||
$request->redirect(null, 'submissions');
|
||||
} else {
|
||||
$request->redirect(null, 'user');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user