login.class.php 11 KB

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