[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/login/ -> lib.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   *
  19   * Login library file of login/password related Moodle functions.
  20   *
  21   * @package    core
  22   * @subpackage lib
  23   * @copyright  Catalyst IT
  24   * @copyright  Peter Bulmer
  25   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26   */
  27  define('PWRESET_STATUS_NOEMAILSENT', 1);
  28  define('PWRESET_STATUS_TOKENSENT', 2);
  29  define('PWRESET_STATUS_OTHEREMAILSENT', 3);
  30  define('PWRESET_STATUS_ALREADYSENT', 4);
  31  
  32  /**
  33   *  Processes a user's request to set a new password in the event they forgot the old one.
  34   *  If no user identifier has been supplied, it displays a form where they can submit their identifier.
  35   *  Where they have supplied identifier, the function will check their status, and send email as appropriate.
  36   */
  37  function core_login_process_password_reset_request() {
  38      global $DB, $OUTPUT, $CFG, $PAGE;
  39      $systemcontext = context_system::instance();
  40      $mform = new login_forgot_password_form();
  41  
  42      if ($mform->is_cancelled()) {
  43          redirect(get_login_url());
  44  
  45      } else if ($data = $mform->get_data()) {
  46          // Requesting user has submitted form data.
  47          // Next find the user account in the database which the requesting user claims to own.
  48          if (!empty($data->username)) {
  49              // Username has been specified - load the user record based on that.
  50              $username = core_text::strtolower($data->username); // Mimic the login page process.
  51              $userparams = array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id, 'deleted' => 0, 'suspended' => 0);
  52              $user = $DB->get_record('user', $userparams);
  53          } else {
  54              // Try to load the user record based on email address.
  55              // this is tricky because
  56              // 1/ the email is not guaranteed to be unique - TODO: send email with all usernames to select the account for pw reset
  57              // 2/ mailbox may be case sensitive, the email domain is case insensitive - let's pretend it is all case-insensitive.
  58  
  59              $select = $DB->sql_like('email', ':email', false, true, false, '|') .
  60                      " AND mnethostid = :mnethostid AND deleted=0 AND suspended=0";
  61              $params = array('email' => $DB->sql_like_escape($data->email, '|'), 'mnethostid' => $CFG->mnet_localhost_id);
  62              $user = $DB->get_record_select('user', $select, $params, '*', IGNORE_MULTIPLE);
  63          }
  64  
  65          // Target user details have now been identified, or we know that there is no such account.
  66          // Send email address to account's email address if appropriate.
  67          $pwresetstatus = PWRESET_STATUS_NOEMAILSENT;
  68          if ($user and !empty($user->confirmed)) {
  69              $userauth = get_auth_plugin($user->auth);
  70              if (!$userauth->can_reset_password() or !is_enabled_auth($user->auth)
  71                or !has_capability('moodle/user:changeownpassword', $systemcontext, $user->id)) {
  72                  if (send_password_change_info($user)) {
  73                      $pwresetstatus = PWRESET_STATUS_OTHEREMAILSENT;
  74                  } else {
  75                      print_error('cannotmailconfirm');
  76                  }
  77              } else {
  78                  // The account the requesting user claims to be is entitled to change their password.
  79                  // Next, check if they have an existing password reset in progress.
  80                  $resetinprogress = $DB->get_record('user_password_resets', array('userid' => $user->id));
  81                  if (empty($resetinprogress)) {
  82                      // Completely new reset request - common case.
  83                      $resetrecord = core_login_generate_password_reset($user);
  84                      $sendemail = true;
  85                  } else if ($resetinprogress->timerequested < (time() - $CFG->pwresettime)) {
  86                      // Preexisting, but expired request - delete old record & create new one.
  87                      // Uncommon case - expired requests are cleaned up by cron.
  88                      $DB->delete_records('user_password_resets', array('id' => $resetinprogress->id));
  89                      $resetrecord = core_login_generate_password_reset($user);
  90                      $sendemail = true;
  91                  } else if (empty($resetinprogress->timererequested)) {
  92                      // Preexisting, valid request. This is the first time user has re-requested the reset.
  93                      // Re-sending the same email once can actually help in certain circumstances
  94                      // eg by reducing the delay caused by greylisting.
  95                      $resetinprogress->timererequested = time();
  96                      $DB->update_record('user_password_resets', $resetinprogress);
  97                      $resetrecord = $resetinprogress;
  98                      $sendemail = true;
  99                  } else {
 100                      // Preexisting, valid request. User has already re-requested email.
 101                      $pwresetstatus = PWRESET_STATUS_ALREADYSENT;
 102                      $sendemail = false;
 103                  }
 104  
 105                  if ($sendemail) {
 106                      $sendresult = send_password_change_confirmation_email($user, $resetrecord);
 107                      if ($sendresult) {
 108                          $pwresetstatus = PWRESET_STATUS_TOKENSENT;
 109                      } else {
 110                          print_error('cannotmailconfirm');
 111                      }
 112                  }
 113              }
 114          }
 115  
 116          // Any email has now been sent.
 117          // Next display results to requesting user if settings permit.
 118          echo $OUTPUT->header();
 119  
 120          if (!empty($CFG->protectusernames)) {
 121              // Neither confirm, nor deny existance of any username or email address in database.
 122              // Print general (non-commital) message.
 123              notice(get_string('emailpasswordconfirmmaybesent'), $CFG->wwwroot.'/index.php');
 124              die; // Never reached.
 125          } else if (empty($user)) {
 126              // Protect usernames is off, and we couldn't find the user with details specified.
 127              // Print failure advice.
 128              notice(get_string('emailpasswordconfirmnotsent'), $CFG->wwwroot.'/forgot_password.php');
 129              die; // Never reached.
 130          } else if (empty($user->email)) {
 131              // User doesn't have an email set - can't send a password change confimation email.
 132              notice(get_string('emailpasswordconfirmnoemail'), $CFG->wwwroot.'/index.php');
 133              die; // Never reached.
 134          } else if ($pwresetstatus == PWRESET_STATUS_ALREADYSENT) {
 135              // User found, protectusernames is off, but user has already (re) requested a reset.
 136              // Don't send a 3rd reset email.
 137              $stremailalreadysent = get_string('emailalreadysent');
 138              notice($stremailalreadysent, $CFG->wwwroot.'/index.php');
 139              die; // Never reached.
 140          } else if ($pwresetstatus == PWRESET_STATUS_NOEMAILSENT) {
 141              // User found, protectusernames is off, but user is not confirmed.
 142              // Pretend we sent them an email.
 143              // This is a big usability problem - need to tell users why we didn't send them an email.
 144              // Obfuscate email address to protect privacy.
 145              $protectedemail = preg_replace('/([^@]*)@(.*)/', '******@$2', $user->email);
 146              $stremailpasswordconfirmsent = get_string('emailpasswordconfirmsent', '', $protectedemail);
 147              notice($stremailpasswordconfirmsent, $CFG->wwwroot.'/index.php');
 148              die; // Never reached.
 149          } else {
 150              // Confirm email sent. (Obfuscate email address to protect privacy).
 151              $protectedemail = preg_replace('/([^@]*)@(.*)/', '******@$2', $user->email);
 152              // This is a small usability problem - may be obfuscating the email address which the user has just supplied.
 153              $stremailresetconfirmsent = get_string('emailresetconfirmsent', '', $protectedemail);
 154              notice($stremailresetconfirmsent, $CFG->wwwroot.'/index.php');
 155              die; // Never reached.
 156          }
 157          die; // Never reached.
 158      }
 159  
 160      // Make sure we really are on the https page when https login required.
 161      $PAGE->verify_https_required();
 162  
 163      // DISPLAY FORM.
 164  
 165      echo $OUTPUT->header();
 166      echo $OUTPUT->box(get_string('passwordforgotteninstructions2'), 'generalbox boxwidthnormal boxaligncenter');
 167      $mform->display();
 168  
 169      echo $OUTPUT->footer();
 170  }
 171  
 172  /**
 173   * This function processes a user's submitted token to validate the request to set a new password.
 174   * If the user's token is validated, they are prompted to set a new password.
 175   * @param string $token the one-use identifier which should verify the password reset request as being valid.
 176   * @return void
 177   */
 178  function core_login_process_password_set($token) {
 179      global $DB, $CFG, $OUTPUT, $PAGE, $SESSION;
 180      require_once($CFG->dirroot.'/user/lib.php');
 181  
 182      $pwresettime = isset($CFG->pwresettime) ? $CFG->pwresettime : 1800;
 183      $sql = "SELECT u.*, upr.token, upr.timerequested, upr.id as tokenid
 184                FROM {user} u
 185                JOIN {user_password_resets} upr ON upr.userid = u.id
 186               WHERE upr.token = ?";
 187      $user = $DB->get_record_sql($sql, array($token));
 188  
 189      $forgotpasswordurl = "{$CFG->httpswwwroot}/login/forgot_password.php";
 190      if (empty($user) or ($user->timerequested < (time() - $pwresettime - DAYSECS))) {
 191          // There is no valid reset request record - not even a recently expired one.
 192          // (suspicious)
 193          // Direct the user to the forgot password page to request a password reset.
 194          echo $OUTPUT->header();
 195          notice(get_string('noresetrecord'), $forgotpasswordurl);
 196          die; // Never reached.
 197      }
 198      if ($user->timerequested < (time() - $pwresettime)) {
 199          // There is a reset record, but it's expired.
 200          // Direct the user to the forgot password page to request a password reset.
 201          $pwresetmins = floor($pwresettime / MINSECS);
 202          echo $OUTPUT->header();
 203          notice(get_string('resetrecordexpired', '', $pwresetmins), $forgotpasswordurl);
 204          die; // Never reached.
 205      }
 206  
 207      if ($user->auth === 'nologin' or !is_enabled_auth($user->auth)) {
 208          // Bad luck - user is not able to login, do not let them set password.
 209          echo $OUTPUT->header();
 210          print_error('forgotteninvalidurl');
 211          die; // Never reached.
 212      }
 213  
 214      // Check this isn't guest user.
 215      if (isguestuser($user)) {
 216          print_error('cannotresetguestpwd');
 217      }
 218  
 219      // Token is correct, and unexpired.
 220      $mform = new login_set_password_form(null, $user, 'post', '', 'autocomplete="yes"');
 221      $data = $mform->get_data();
 222      if (empty($data)) {
 223          // User hasn't submitted form, they got here directly from email link.
 224          // Next, display the form.
 225          $setdata = new stdClass();
 226          $setdata->username = $user->username;
 227          $setdata->username2 = $user->username;
 228          $setdata->token = $user->token;
 229          $mform->set_data($setdata);
 230          $PAGE->verify_https_required();
 231          echo $OUTPUT->header();
 232          echo $OUTPUT->box(get_string('setpasswordinstructions'), 'generalbox boxwidthnormal boxaligncenter');
 233          $mform->display();
 234          echo $OUTPUT->footer();
 235          return;
 236      } else {
 237          // User has submitted form.
 238          // Delete this token so it can't be used again.
 239          $DB->delete_records('user_password_resets', array('id' => $user->tokenid));
 240          $userauth = get_auth_plugin($user->auth);
 241          if (!$userauth->user_update_password($user, $data->password)) {
 242              print_error('errorpasswordupdate', 'auth');
 243          }
 244          user_add_password_history($user->id, $data->password);
 245          if (!empty($CFG->passwordchangelogout)) {
 246              \core\session\manager::kill_user_sessions($user->id, session_id());
 247          }
 248          // Reset login lockout (if present) before a new password is set.
 249          login_unlock_account($user);
 250          // Clear any requirement to change passwords.
 251          unset_user_preference('auth_forcepasswordchange', $user);
 252          unset_user_preference('create_password', $user);
 253  
 254          if (!empty($user->lang)) {
 255              // Unset previous session language - use user preference instead.
 256              unset($SESSION->lang);
 257          }
 258          complete_user_login($user); // Triggers the login event.
 259  
 260          \core\session\manager::apply_concurrent_login_limit($user->id, session_id());
 261  
 262          $urltogo = core_login_get_return_url();
 263          unset($SESSION->wantsurl);
 264          redirect($urltogo, get_string('passwordset'), 1);
 265      }
 266  }
 267  
 268  /** Create a new record in the database to track a new password set request for user.
 269   * @param object $user the user record, the requester would like a new password set for.
 270   * @return record created.
 271   */
 272  function core_login_generate_password_reset ($user) {
 273      global $DB;
 274      $resetrecord = new stdClass();
 275      $resetrecord->timerequested = time();
 276      $resetrecord->userid = $user->id;
 277      $resetrecord->token = random_string(32);
 278      $resetrecord->id = $DB->insert_record('user_password_resets', $resetrecord);
 279      return $resetrecord;
 280  }
 281  
 282  /**  Determine where a user should be redirected after they have been logged in.
 283   * @return string url the user should be redirected to.
 284   */
 285  function core_login_get_return_url() {
 286      global $CFG, $SESSION, $USER;
 287      // Prepare redirection.
 288      if (user_not_fully_set_up($USER)) {
 289          $urltogo = $CFG->wwwroot.'/user/edit.php';
 290          // We don't delete $SESSION->wantsurl yet, so we get there later.
 291  
 292      } else if (isset($SESSION->wantsurl) and (strpos($SESSION->wantsurl, $CFG->wwwroot) === 0
 293              or strpos($SESSION->wantsurl, str_replace('http://', 'https://', $CFG->wwwroot)) === 0)) {
 294          $urltogo = $SESSION->wantsurl;    // Because it's an address in this site.
 295          unset($SESSION->wantsurl);
 296      } else {
 297          // No wantsurl stored or external - go to homepage.
 298          $urltogo = $CFG->wwwroot.'/';
 299          unset($SESSION->wantsurl);
 300      }
 301  
 302      // If the url to go to is the same as the site page, check for default homepage.
 303      if ($urltogo == ($CFG->wwwroot . '/')) {
 304          $homepage = get_home_page();
 305          // Go to my-moodle page instead of site homepage if defaulthomepage set to homepage_my.
 306          if ($homepage == HOMEPAGE_MY && !is_siteadmin() && !isguestuser()) {
 307              if ($urltogo == $CFG->wwwroot or $urltogo == $CFG->wwwroot.'/' or $urltogo == $CFG->wwwroot.'/index.php') {
 308                  $urltogo = $CFG->wwwroot.'/my/';
 309              }
 310          }
 311      }
 312      return $urltogo;
 313  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1