| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- <?php
- /**
- * Login
- *
- * Copyright 2010 by Shaun McCormick <shaun+login@modx.com>
- *
- * Login is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * Login 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * Login; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * @package login
- */
- /**
- * Handles logging in and out of users
- *
- * @package login
- * @subpackage controllers
- */
- class LoginLoginController extends LoginController {
- public $isAuthenticated = false;
- /** @var LoginDictionary $dictionary */
- public $dictionary;
- public function initialize() {
- $this->setDefaultProperties(array(
- 'loginViaEmail' => false,
- 'loginTpl' => 'lgnLoginTpl',
- 'logoutTpl' => 'lgnLogoutTpl',
- 'loggedinResourceId' => '',
- 'loggedoutResourceId' => '',
- 'loginMsg' => '',
- 'logoutMsg' => '',
- 'preHooks' => '',
- 'tplType' => 'modChunk',
- 'actionKey' => 'service',
- 'loginKey' => 'login',
- 'logoutKey' => 'logout',
- 'errorPrefix' => 'error',
- 'errTpl' => 'lgnErrTpl',
- 'errTplType' => 'modChunk',
- 'rememberMeKey' => 'rememberme',
- 'loginContext' => $this->modx->context->get('key'),
- 'contexts' => '',
- 'jsonResponse' => false,
- ));
- if (!empty($_REQUEST['login_context'])) {
- $this->setProperty('loginContext',$_REQUEST['login_context']);
- }
- if (!empty($_REQUEST['add_contexts'])) {
- $this->setProperty('contexts',$_REQUEST['add_contexts']);
- }
- $this->isAuthenticated = $this->modx->user->isAuthenticated($this->getProperty('loginContext'));
- }
- /**
- * Process the controller
- * @return string
- */
- public function process() {
- if (!empty($_REQUEST[$this->getProperty('actionKey','service')])) {
- $this->handleRequest();
- }
- $content = $this->renderForm();
- return $this->output($content);
- }
- /**
- * Render the logout or login form
- * @return string
- */
- public function renderForm() {
- $redirectToPrior = $this->getProperty('redirectToPrior',false,'isset');
- $tpl = $this->isAuthenticated ? $this->getProperty('logoutTpl') : $this->getProperty('loginTpl');
- $actionMsg = $this->isAuthenticated
- ? $this->getProperty('logoutMsg',$this->modx->lexicon('login.logout'))
- : $this->getProperty('loginMsg',$this->modx->lexicon('login'));
- $this->modx->setPlaceholder('actionMsg', $actionMsg);
- $phs = $this->isAuthenticated ? $this->getProperties() : array_merge($this->getProperties(), $_POST);
-
- /* make sure to strip out logout GET parameter to prevent ghost logout */
- $logoutKey = $this->getProperty('logoutKey','logout');
- if (!$redirectToPrior) {
- $phs['request_uri'] = str_replace(array('?service='.$logoutKey,'&service='.$logoutKey,'&service='.$logoutKey),'',$_SERVER['REQUEST_URI']);
- } else {
- $phs['request_uri'] = str_replace(array('?service='.$logoutKey,'&service='.$logoutKey,'&service='.$logoutKey),'',$_SERVER['HTTP_REFERER']);
- }
- $phs = $this->escapePlaceholders($phs);
- /* properly build logout url */
- if ($this->isAuthenticated) {
- $phs['logoutUrl'] = $phs['request_uri'];
- $phs['logoutUrl'] .= strpos($phs['logoutUrl'],'?') ? ($this->modx->getOption('xhtml_urls',null,false) ? '&' : '&') : '?';
- $phs['logoutUrl'] .= $phs['actionKey'].'='.$phs['logoutKey'];
- $phs['logoutUrl'] = str_replace(array('?=', '&=', '&='), '', $phs['logoutUrl']);
- }
- $this->loadReCaptcha();
- if ($this->isAuthenticated && $this->getProperty('loggedinResourceId') && $this->modx->resource->get('id') != $this->getProperty('loggedinResourceId')) {
- $url = $this->modx->makeUrl($this->getProperty('loggedinResourceId'), '', '', 'full');
- $this->modx->sendRedirect($url);
- }
- if (!$this->isAuthenticated && $this->getProperty('loggedoutResourceId') && $this->modx->resource->get('id') != $this->getProperty('loggedoutResourceId')) {
- $url = $this->modx->makeUrl($this->getProperty('loggedoutResourceId'), '', '', 'full');
- $this->modx->sendRedirect($url);
- }
- return $this->login->getChunk($tpl,$phs,$this->getProperty('tplType','modChunk'));
- }
- /**
- * Either output the content or set it as a placeholder
- * @param string $content
- * @return string
- */
- public function output($content = '') {
- $toPlaceholder = $this->getProperty('toPlaceholder','');
- if (!empty($toPlaceholder)) {
- $this->modx->setPlaceholder($toPlaceholder,$content);
- return '';
- }
- return $content;
- }
- /**
- * Check for and load reCaptcha
- * @return boolean
- */
- public function loadReCaptcha() {
- $loaded = false;
- $preHooks = $this->getProperty('preHooks','');
- /* if using recaptcha, load recaptcha html */
- if (strpos($preHooks,'recaptcha') !== false && !$this->isAuthenticated) {
- /** @var reCaptcha $reCaptcha */
- $reCaptcha = $this->modx->getService('recaptcha','reCaptcha',$this->login->config['modelPath'].'recaptcha/');
- if ($reCaptcha instanceof reCaptcha) {
- $this->modx->lexicon->load('login:recaptcha');
- $recaptchaTheme = $this->getProperty('recaptchaTheme','clean');
- $recaptchaWidth = $this->getProperty('recaptchaWidth',500);
- $recaptchaHeight = $this->getProperty('recaptchaHeight',300);
- $html = $reCaptcha->getHtml($recaptchaTheme,$recaptchaWidth,$recaptchaHeight);
- $this->modx->setPlaceholder('login.recaptcha_html',$html);
- $loaded = true;
- } else {
- $this->modx->log(modX::LOG_LEVEL_ERROR,'[Login] '.$this->modx->lexicon('login.recaptcha_err_load'));
- }
- }
- return $loaded;
- }
- /**
- * Handle any POST request
- *
- * @return void
- */
- public function handleRequest() {
- $this->loadDictionary();
- $actionKey = $this->getProperty('actionKey','service');
-
- if (!empty($_POST) && isset($_POST[$actionKey]) && !$this->isAuthenticated) {
- if ($_POST[$actionKey] == $this->getProperty('loginKey','login')) {
- $this->login();
- } else {
- $this->modx->log(modX::LOG_LEVEL_ERROR,$this->modx->lexicon('login.invalid_post',array(
- 'action' => $_POST[$actionKey],
- )));
- }
- } elseif ($_REQUEST[$actionKey] == $this->getProperty('logoutKey','logout') && $this->isAuthenticated) {
- $this->logout();
- }
- }
- /**
- * Handle a Login submission
- *
- * @return void
- */
- public function login() {
- /* set default POST vars if not in form */
- if (empty($_POST['login_context'])) $_POST['login_context'] = $this->getProperty('loginContext');
- if ($this->runPreLoginHooks()) {
- $response = $this->runLoginProcessor();
- /* if we've got a good response, proceed */
- if (!empty($response) && !$response->isError()) {
- $this->runPostLoginHooks($response);
- /* process posthooks for login */
- if ($this->postHooks->hasErrors()) {
- $errors = $this->postHooks->getErrors();
- $errorMsg = $this->postHooks->getErrorMessage();
- // Return JSON posthook errors if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonErrorOutput = array(
- 'success' => false,
- 'message' => $errorMsg,
- 'errors' => $errors
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonErrorOutput));
- }
- $errorPrefix = $this->getProperty('errorPrefix','error');
- $this->modx->toPlaceholders($errors,$errorPrefix);
- $this->modx->toPlaceholder('message',$errorMsg,$errorPrefix);
- } else {
- // Return JSON success response if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonSuccessOutput = array(
- 'success' => true,
- 'message' => $this->getProperty('loginMsg')
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonSuccessOutput));
- }
- $this->redirectAfterLogin($response);
- }
- /* login failed, output error */
- } else {
- $this->checkForRedirectOnFailedAuth($response);
- $errorOutput = $this->prepareFailureMessage($response,$this->modx->lexicon('login.login_err'));
- $this->modx->setPlaceholder('errors', $errorOutput);
- }
- }
- }
- /**
- * Run any preHooks before logging in
- *
- * @return boolean
- */
- public function runPreLoginHooks() {
- $success = true;
-
- /* do pre-login hooks */
- $this->loadHooks('preHooks');
- $this->preHooks->loadMultiple($this->getProperty('preHooks',''),$this->dictionary->toArray(),array(
- 'mode' => Login::MODE_LOGIN,
- ));
- /* process prehooks */
- if ($this->preHooks->hasErrors()) {
- $errors = $this->preHooks->getErrors();
- // Return JSON prehook errors if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonErrorOutput = array(
- 'success' => false,
- 'errors' => $errors
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonErrorOutput));
- }
- $this->modx->toPlaceholders($errors,$this->getProperty('errorPrefix','error'));
- $errorMsg = $this->preHooks->getErrorMessage();
- $errorOutput = $this->modx->getChunk($this->getProperty('errTpl'), array('msg' => $errorMsg));
- $this->modx->setPlaceholder('errors',$errorOutput);
- $success = false;
- }
- return $success;
- }
- /**
- * @return modProcessorResponse
- */
- public function runLoginProcessor() {
- $loginViaEmail = $this->getProperty('loginViaEmail', false);
-
- $fields = $this->dictionary->toArray();
- /* send to login processor and handle response */
- $properties = array(
- 'login_context' => $this->getProperty('loginContext'),
- 'add_contexts' => $this->getProperty('contexts',''),
- 'username' => $fields['username'],
- 'password' => $fields['password'],
- 'returnUrl' => $fields['returnUrl'],
- 'rememberme' => !empty($fields[$this->getProperty('rememberMeKey','rememberme')]) ? true : false,
- );
- if ($loginViaEmail) {
- $processorsPath = $this->config['processorsPath'];
- return $this->modx->runProcessor('customlogin', $properties, array('processors_path' => $processorsPath));
- } else {
- return $this->modx->runProcessor('security/login', $properties);
- }
- }
- /**
- * @param modProcessorResponse $response
- * @param string $defaultErrorMessage
- * @return string
- */
- public function prepareFailureMessage(modProcessorResponse $response,$defaultErrorMessage = '') {
- $errorOutput = '';
- $errTpl = $this->getProperty('errTpl');
- $errors = $response->getFieldErrors();
- $message = $response->getMessage();
- if (!empty($errors)) {
- // Return JSON login errors if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonErrorOutput = array(
- 'success' => false,
- 'message' => $message,
- 'errors' => $errors
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonErrorOutput));
- }
- foreach ($errors as $error) {
- $errorOutput .= $this->modx->getChunk($errTpl, $error);
- }
- } elseif (!empty($message)) {
- // Return JSON error message in response if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonErrorOutput = array(
- 'success' => false,
- 'message' => $message
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonErrorOutput));
- }
- $errorOutput = $this->modx->getChunk($errTpl, array('msg' => $message));
- } else {
- // Return JSON default error if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonErrorOutput = array(
- 'success' => false,
- 'message' => $defaultErrorMessage
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonErrorOutput));
- }
- $errorOutput = $this->modx->getChunk($errTpl, array('msg' => $defaultErrorMessage));
- }
- return $errorOutput;
- }
- /**
- * Check to see if the user wants to redirect to a separ
- * @param modProcessorResponse $response
- * @return void
- */
- public function checkForRedirectOnFailedAuth(modProcessorResponse $response) {
- $redirectToOnFailedAuth = $this->getProperty('redirectToOnFailedAuth',false,'isset');
- if ($redirectToOnFailedAuth && $redirectToOnFailedAuth != $this->modx->resource->get('id')) {
- $p = array(
- 'u' => $this->dictionary->get('username'),
- );
- $message = $response->getMessage();
- if (!empty($message)) $params['m'] = $message;
- $url = $this->modx->makeUrl($redirectToOnFailedAuth,'',$p,'full');
- $this->modx->sendRedirect($url);
- }
- }
- /**
- * Run any postHooks specified after the user has logged in
- *
- * @param modProcessorResponse $response
- * @return void
- */
- public function runPostLoginHooks(modProcessorResponse $response) {
- $responseArray = $response->getObject();
- /* do post hooks */
- $postHooks = $this->getProperty('postHooks','');
- $this->loadHooks('postHooks');
- $fields = $_POST;
- $fields['response'] =& $responseArray;
- $fields['contexts'] =& $contexts;
- $fields['loginContext'] =& $loginContext;
- $fields['loginResourceId'] =& $loginResourceId;
- $this->postHooks->loadMultiple($postHooks,$fields,array(
- 'mode' => Login::MODE_LOGIN,
- ));
- }
- /**
- * Redirect the user after logging them in
- *
- * @param modProcessorResponse $response
- * @return void
- */
- public function redirectAfterLogin(modProcessorResponse $response) {
- $responseArray = $response->getObject();
- /* allow dynamic redirection handling */
- $redirectBack = $this->modx->getOption('redirectBack',$_REQUEST,$this->getProperty('redirectBack',''));
- $redirectBackParams = $this->modx->getOption('redirectBackParams',$_REQUEST,$this->getProperty('redirectBackParams',''));
- if (!empty($redirectBackParams)) {
- $redirectBackParams = $this->login->decodeParams($redirectBackParams);
- }
- /* otherwise specify a specific resource to redirect to */
- $loginResourceId = $this->getProperty('loginResourceId',$redirectBack);
- /* login posthooks succeeded, now redirect */
- if (!empty($loginResourceId)) {
- $loginResourceParams = $this->getProperty('loginResourceParams',$redirectBackParams);
- if (!empty($loginResourceParams) && !is_array($loginResourceParams)) {
- $loginResourceParams = $this->modx->fromJSON($loginResourceParams);
- }
- $url = $this->modx->makeUrl($loginResourceId,'',$loginResourceParams,'full');
- $this->modx->sendRedirect($url);
- } elseif (!empty($responseArray) && !empty($responseArray['url'])) {
- $this->modx->sendRedirect($responseArray['url']);
- } else {
- $this->modx->sendRedirect($this->modx->getOption('site_url'));
- }
- }
- public function logout() {
- /* set default REQUEST vars if not provided */
- if (empty($_REQUEST['login_context'])) $_REQUEST['login_context'] = $this->getProperty('loginContext');
- if ($this->runPreLogoutHooks()) {
- /* send to logout processor and handle response for each context */
- /** @var modProcessorResponse $response */
- $response = $this->modx->runProcessor('security/logout',array(
- 'login_context' => $this->getProperty('loginContext',$this->modx->context->get('key')),
- 'add_contexts' => $this->getProperty('contexts',''),
- ));
- /* if successful logout */
- if (!empty($response) && !$response->isError()) {
- $this->runPostLogoutHooks($response);
- // Return JSON logout success
- if ($this->getProperty('jsonResponse')) {
- $jsonSuccessOutput = array(
- 'success' => true,
- 'message' => $this->getProperty('logoutMsg')
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonSuccessOutput));
- }
- $this->redirectAfterLogout($response);
- /* logout failed, output error */
- } else {
- $errorOutput = $this->prepareFailureMessage($response,$this->modx->lexicon('login.logout_err'));
- $this->modx->setPlaceholder('errors', $errorOutput);
- }
- }
- }
- /**
- * @return boolean
- */
- public function runPreLogoutHooks() {
- $success = true;
- $this->loadHooks('preHooks');
- $this->preHooks->loadMultiple($this->getProperty('preHooks',''),$this->dictionary->toArray(),array(
- 'mode' => Login::MODE_LOGOUT,
- ));
- if ($this->preHooks->hasErrors()) {
- $errors = $this->preHooks->getErrors();
- $errorMsg = $this->preHooks->getErrorMessage();
- // Return JSON login errors if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonErrorOutput = array(
- 'success' => false,
- 'message' => $errorMsg,
- 'errors' => $errors
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonErrorOutput));
- }
- $this->modx->toPlaceholders($errors,$this->getProperty('errorPrefix','error'));
- $errorOutput = $this->modx->getChunk($this->getProperty('errTpl'), array('msg' => $errorMsg));
- $this->modx->setPlaceholder('errors',$errorOutput);
- $success = false;
- }
- return $success;
- }
- /**
- * Run any post-logout hooks
- *
- * @param modProcessorResponse $response
- * @return boolean
- */
- public function runPostLogoutHooks(modProcessorResponse $response) {
- $success = true;
-
- /* do post hooks for logout */
- $postHooks = $this->getProperty('postHooks','');
- $this->loadHooks('postHooks');
- $fields = $this->dictionary->toArray();
- $fields['response'] = $response->getObject();
- $fields['contexts'] =& $contexts;
- $fields['loginContext'] =& $loginContext;
- $fields['logoutResourceId'] =& $logoutResourceId;
- $this->postHooks->loadMultiple($postHooks,$fields,array(
- 'mode' => Login::MODE_LOGOUT,
- ));
- /* log posthooks errors */
- if ($this->postHooks->hasErrors()) {
- $errors = $this->postHooks->getErrors();
- $this->modx->log(modX::LOG_LEVEL_ERROR,'[Login] Post-Hook errors: '.print_r($errors,true));
- $errorMsg = $this->postHooks->getErrorMessage();
- if (!empty($errorMsg)) {
- $this->modx->log(modX::LOG_LEVEL_ERROR,'[Login] Post-Hook error: '.$errorMsg);
- }
- $success = false;
- // Return JSON posthook logout errors if requested.
- if ($this->getProperty('jsonResponse')) {
- $jsonErrorOutput = array(
- 'success' => false,
- 'message' => $errorMsg,
- 'errors' => $errors
- );
- header('Content-Type: application/json;charset=utf-8');
- exit($this->modx->toJSON($jsonErrorOutput));
- }
- }
- return $success;
- }
- /**
- * Redirect the user after they logout
- *
- * @param modProcessorResponse $response
- * @return void
- */
- public function redirectAfterLogout(modProcessorResponse $response) {
- $responseArray = $response->getObject();
- /* redirect */
- $logoutResourceId = $this->getProperty('logoutResourceId',0);
- if (!empty($responseArray) && !empty($responseArray['url'])) {
- $this->modx->sendRedirect($responseArray['url']);
- } elseif (!empty($logoutResourceId)) {
- $logoutResourceParams = $this->getProperty('logoutResourceParams','');
- if (!empty($logoutResourceParams)) {
- $logoutResourceParams = $this->modx->fromJSON($logoutResourceParams);
- }
- $url = $this->modx->makeUrl($logoutResourceId,'',$logoutResourceParams,'full');
- $this->modx->sendRedirect($url);
- } else {
- $this->modx->sendRedirect($_SERVER['REQUEST_URI']);
- }
- }
- }
- return 'LoginLoginController';
|