PageRenderTime 26ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/manager/controllers/default/security/login.class.php

https://github.com/Mark-H/revolution
PHP | 303 lines | 192 code | 32 blank | 79 comment | 29 complexity | ee9860fa9461bca92855d303ebca8824 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of MODX Revolution.
  4. *
  5. * Copyright (c) MODX, LLC. All Rights Reserved.
  6. *
  7. * For complete copyright and license information, see the COPYRIGHT and LICENSE
  8. * files found in the top-level directory of this distribution.
  9. */
  10. /**
  11. * Loads the login screen
  12. *
  13. * @package modx
  14. * @subpackage manager.controllers
  15. */
  16. class SecurityLoginManagerController extends modManagerController {
  17. public $loadHeader = false;
  18. public $loadFooter = false;
  19. public function initialize() {
  20. $this->handleLanguageChange();
  21. return true;
  22. }
  23. /**
  24. * Check for any permissions or requirements to load page
  25. * @return bool
  26. */
  27. public function checkPermissions() {
  28. return true;
  29. }
  30. /**
  31. * Register custom CSS/JS for the page
  32. * @return void
  33. */
  34. public function loadCustomCssJs() {}
  35. /**
  36. * Custom logic code here for setting placeholders, etc
  37. * @param array $scriptProperties
  38. * @return mixed
  39. */
  40. public function process(array $scriptProperties = array()) {
  41. $this->handleForgotLoginHash();
  42. $this->preserveReturnUrl();
  43. if (!empty($this->scriptProperties)) {
  44. $this->handlePost();
  45. }
  46. /* invoke OnManagerLoginFormPrerender event */
  47. $eventInfo= $this->modx->invokeEvent('OnManagerLoginFormPrerender');
  48. $eventInfo= is_array($eventInfo) ? implode("\n", $eventInfo) : (string) $eventInfo;
  49. $this->setPlaceholder('onManagerLoginFormPrerender', $eventInfo);
  50. $this->checkForActiveInstallation();
  51. $this->checkForAllowManagerForgotPassword();
  52. /* invoke OnManagerLoginFormRender event */
  53. $eventInfo= $this->modx->invokeEvent('OnManagerLoginFormRender');
  54. $eventInfo= is_array($eventInfo) ? implode("\n", $eventInfo) : (string) $eventInfo;
  55. $eventInfo= str_replace('\'','\\\'',$eventInfo);
  56. $this->setPlaceholder('onManagerLoginFormRender', $eventInfo);
  57. }
  58. /**
  59. * Set the cultureKey for the login page and get the list of languages
  60. * @return string The loaded cultureKey
  61. */
  62. public function handleLanguageChange() {
  63. $cultureKey = $this->modx->getOption('cultureKey',$_REQUEST,'en');
  64. if ($cultureKey) {
  65. $cultureKey = $this->modx->sanitizeString($cultureKey);
  66. $this->modx->setOption('cultureKey',$cultureKey);
  67. $this->modx->setOption('manager_language',$cultureKey);
  68. }
  69. $this->setPlaceholder('cultureKey',$cultureKey);
  70. $languages = $this->modx->lexicon->getLanguageList('core');
  71. $list = array();
  72. foreach ($languages as $language) {
  73. $selected = $language == $cultureKey ? ' selected="selected"' : '';
  74. $list[] = '<option value="'.$language.'"'.$selected.'>'.$language.'</option>';
  75. }
  76. $this->setPlaceholder('languages',implode("\n",$list));
  77. $this->modx->lexicon->load('login');
  78. $languageString = $this->modx->lexicon('login_language');
  79. if (empty($languageString) || strcmp($languageString,'login_language') == 0) {
  80. $this->modx->lexicon->load('en:core:login');
  81. $languageString = $this->modx->lexicon('login_language',array(),'en');
  82. }
  83. $this->setPlaceholder('language_str',$languageString);
  84. return $cultureKey;
  85. }
  86. public function checkForAllowManagerForgotPassword() {
  87. $allow = $this->modx->getOption('allow_manager_login_forgot_password',null,true);
  88. if ($allow) {
  89. $this->setPlaceholder('allow_forgot_password',true);
  90. }
  91. }
  92. /**
  93. * Handle and sanitize the forgot login hash, if existent
  94. *
  95. * @return void
  96. */
  97. public function handleForgotLoginHash() {
  98. if (isset($_GET['modahsh'])) {
  99. $this->scriptProperties['modahsh'] = $this->modx->sanitizeString($_GET['modahsh']);
  100. $this->setPlaceholder('modahsh',$this->scriptProperties['modahsh']);
  101. }
  102. }
  103. /**
  104. * If the user is coming from a specific mgr action, preserve the return URL and redirect post-login
  105. * @return void
  106. */
  107. public function preserveReturnUrl() {
  108. if (!empty($_SERVER['REQUEST_URI'])) {
  109. $chars = array("'",'"','(',')',';','>','<','!');
  110. $returnUrl = str_replace($chars,'',$_SERVER['REQUEST_URI']);
  111. $this->setPlaceholder('returnUrl',$returnUrl);
  112. }
  113. }
  114. /**
  115. * Check to see if there's an active installation in process; if so, notify the user.
  116. * @return void
  117. */
  118. public function checkForActiveInstallation() {
  119. if (isset($this->scriptProperties['installGoingOn'])) {
  120. $installGoingOn = $this->modx->sanitizeString($this->scriptProperties['installGoingOn']);
  121. }
  122. if (isset ($installGoingOn)) {
  123. switch ($installGoingOn) {
  124. case 1 : $this->setPlaceholder('login_message',$this->modx->lexicon('login_cancelled_install_in_progress').$this->modx->lexicon('login_message')); break;
  125. case 2 : $this->setPlaceholder('login_message',$this->modx->lexicon('login_cancelled_site_was_updated').$this->modx->lexicon('login_message')); break;
  126. }
  127. }
  128. }
  129. /**
  130. * Handle and sanitize any POST actions that come through
  131. *
  132. * @return void
  133. */
  134. public function handlePost() {
  135. $san = array("'",'"','(',')',';','>','<','../');
  136. foreach ($this->scriptProperties as $k => $v) {
  137. if (!in_array($k,array('returnUrl'))) {
  138. $this->scriptProperties[$k] = str_replace($san,'',$v);
  139. } else {
  140. $chars = array("'",'"','(',')',';','>','<','!','../');
  141. $this->scriptProperties[$k] = str_replace($chars,'',$v);
  142. }
  143. }
  144. /* handle login */
  145. if (!empty($this->scriptProperties['login'])) {
  146. $this->handleLogin();
  147. } else if (!empty($this->scriptProperties['forgotlogin']) && $this->modx->getOption('allow_manager_login_forgot_password',null,true)) {
  148. $this->handleForgotLogin();
  149. }
  150. $this->setPlaceholder('_post',$this->scriptProperties);
  151. }
  152. /**
  153. * Handle when a user attempts to log in
  154. * @return void
  155. */
  156. public function handleLogin() {
  157. $validated = true;
  158. /** @var modUser $user */
  159. $user = $this->modx->getObject('modUser',array(
  160. 'username' => $this->scriptProperties['username'],
  161. ));
  162. /* first if there's an activation hash, process that */
  163. if ($user) {
  164. if (array_key_exists('modahsh', $this->scriptProperties) && !empty($this->scriptProperties['modahsh'])) {
  165. $activated = $user->activatePassword($this->scriptProperties['modahsh']);
  166. if ($activated === false) {
  167. $this->modx->smarty->assign('error_message',$this->modx->lexicon('login_activation_key_err'));
  168. $validated = false;
  169. }
  170. }
  171. }
  172. if ($validated) {
  173. /** @var modProcessorResponse $response */
  174. $response = $this->modx->runProcessor('security/login',$this->scriptProperties);
  175. if (($response instanceof modProcessorResponse) && !$response->isError()) {
  176. $url = !empty($this->scriptProperties['returnUrl']) ? $this->scriptProperties['returnUrl'] : $this->modx->getOption('manager_url',null,MODX_MANAGER_URL);
  177. $url = $this->modx->getOption('url_scheme', null, MODX_URL_SCHEME).$this->modx->getOption('http_host', null, MODX_HTTP_HOST).$url;
  178. $this->modx->sendRedirect($url);
  179. } else {
  180. $errors = $response->getAllErrors();
  181. $error_message = implode("\n",$errors);
  182. $this->setPlaceholder('error_message',$error_message);
  183. }
  184. }
  185. }
  186. /**
  187. * Handles the action when a user forgets their login
  188. *
  189. * @return void
  190. */
  191. public function handleForgotLogin() {
  192. $c = $this->modx->newQuery('modUser');
  193. $c->select(array('modUser.*','Profile.email','Profile.fullname'));
  194. $c->innerJoin('modUserProfile','Profile');
  195. $c->where(array(
  196. 'modUser.username' => $this->scriptProperties['username_reset'],
  197. 'OR:Profile.email:=' => $this->scriptProperties['username_reset'],
  198. ));
  199. /** @var modUser $user */
  200. $user = $this->modx->getObject('modUser',$c);
  201. if ($user) {
  202. $activationHash = md5(uniqid(md5($user->get('email') . '/' . $user->get('id')), true));
  203. $this->modx->getService('registry', 'registry.modRegistry');
  204. $this->modx->registry->getRegister('user', 'registry.modDbRegister');
  205. $this->modx->registry->user->connect();
  206. $this->modx->registry->user->subscribe('/pwd/reset/');
  207. $this->modx->registry->user->send('/pwd/reset/', array(md5($user->get('username')) => $activationHash), array('ttl' => 86400));
  208. $newPassword = $user->generatePassword();
  209. $user->set('cachepwd', $newPassword);
  210. $user->save();
  211. /* send activation email */
  212. $message = $this->modx->getOption('forgot_login_email');
  213. $placeholders = $user->toArray();
  214. $placeholders['url_scheme'] = $this->modx->getOption('url_scheme');
  215. $placeholders['http_host'] = $this->modx->getOption('http_host');
  216. $placeholders['manager_url'] = $this->modx->getOption('manager_url');
  217. $placeholders['hash'] = $activationHash;
  218. $placeholders['password'] = $newPassword;
  219. // Store previous placeholders
  220. $ph = $this->modx->placeholders;
  221. // now set those useful for modParser
  222. $this->modx->setPlaceholders($placeholders);
  223. $this->modx->getParser()->processElementTags('', $message, false, false);
  224. // Then restore previous placeholders to prevent any breakage
  225. $this->modx->placeholders = $ph;
  226. $this->modx->getService('mail', 'mail.modPHPMailer');
  227. $this->modx->mail->set(modMail::MAIL_BODY, $message);
  228. $this->modx->mail->set(modMail::MAIL_FROM, $this->modx->getOption('emailsender'));
  229. $this->modx->mail->set(modMail::MAIL_FROM_NAME, $this->modx->getOption('site_name'));
  230. $this->modx->mail->set(modMail::MAIL_SENDER, $this->modx->getOption('emailsender'));
  231. $this->modx->mail->set(modMail::MAIL_SUBJECT, $this->modx->getOption('emailsubject'));
  232. $this->modx->mail->address('to', $user->get('email'),$user->get('fullname'));
  233. $this->modx->mail->address('reply-to', $this->modx->getOption('emailsender'));
  234. $this->modx->mail->setHTML(true);
  235. if (!$this->modx->mail->send()) {
  236. /* if for some reason error in email, tell user */
  237. $err = $this->modx->lexicon('error_sending_email_to').$user->get('email');
  238. $this->modx->log(modX::LOG_LEVEL_ERROR,$err);
  239. $this->setPlaceholder('error_message',$err);
  240. } else {
  241. $this->setPlaceholder('success_message',$this->modx->lexicon('login_password_reset_act_sent'));
  242. }
  243. $this->modx->mail->reset();
  244. } else {
  245. $this->setPlaceholder('success_message',$this->modx->lexicon('login_user_err_nf_email'));
  246. }
  247. }
  248. /**
  249. * Return the pagetitle
  250. *
  251. * @return string
  252. */
  253. public function getPageTitle() {
  254. return $this->modx->lexicon('login');
  255. }
  256. /**
  257. * Return the location of the template file
  258. * @return string
  259. */
  260. public function getTemplateFile() {
  261. return 'security/login.tpl';
  262. }
  263. /**
  264. * Specify the language topics to load
  265. * @return array
  266. */
  267. public function getLanguageTopics() {
  268. return array('login');
  269. }
  270. }