You are here

function password_policy_cron in Password Policy 7

Same name and namespace in other branches
  1. 8.3 password_policy.module \password_policy_cron()
  2. 5 password_policy.module \password_policy_cron()
  3. 6 password_policy.module \password_policy_cron()
  4. 7.2 password_policy.module \password_policy_cron()

Implements hook_cron().

File

./password_policy.module, line 537
Allows enforcing restrictions on user passwords by defining policies.

Code

function password_policy_cron() {

  // Short circuit if no policies are active that use expiration.
  $expiration_policies = db_select('password_policy', 'p', array(
    'target' => 'slave',
  ))
    ->condition('enabled', 1)
    ->condition('expiration', 0, '>')
    ->countQuery()
    ->execute()
    ->fetchField();
  if ($expiration_policies == 0) {
    return;
  }
  $accounts = array();
  $warns = array();
  $unblocks = array();
  $pids = array();

  // Get all users' last password change time. Don't touch blocked accounts.
  $query = db_select('users', 'u', array(
    'target' => 'slave',
  ));
  $query
    ->leftJoin('password_policy_history', 'p', 'u.uid = p.uid');
  $query
    ->leftJoin('password_policy_expiration', 'e', 'u.uid = e.uid');
  $result = $query
    ->fields('u', array(
    'uid',
    'name',
    'created',
  ))
    ->fields('p', array(
    'created',
  ))
    ->fields('e', array(
    'pid',
    'unblocked',
    'warning',
  ))
    ->condition('u.uid', 0, '>')
    ->condition('u.status', 1)
    ->orderBy('p.created')
    ->orderBy('e.warning')
    ->execute();
  foreach ($result as $row) {
    if ($row->uid == 1 && !variable_get('password_policy_admin', 1)) {
      continue;
    }

    // Use account creation timestamp if there is no entry in password history
    // table.
    $accounts[$row->uid] = empty($row->p_created) ? $row->created : $row->p_created;

    // Last time a warning was mailed out (if was). We need it because we send
    // warnings only once a day, not on all cron runs.
    $warns[$row->uid] = $row->warning;

    // Last time user was unblocked (if was). We don't block this account again
    // for some period of time.
    $unblocks[$row->uid] = $row->unblocked;

    // Unique password policy expirations ID.
    $pids[$row->uid] = $row->pid;

    // Usernames.
    $names[$row->uid] = $row->name;
  }
  foreach ($accounts as $uid => $last_change) {
    $roles = array(
      DRUPAL_AUTHENTICATED_RID,
    );
    $result = db_select('users_roles', 'u', array(
      'target' => 'slave',
    ))
      ->fields('u', array(
      'rid',
    ))
      ->condition('uid', $uid)
      ->orderBy('u.rid')
      ->execute();
    foreach ($result as $row) {
      $roles[] = $row->rid;
    }
    $name = $names[$uid];
    $dummy_account = (object) array(
      'name' => $name,
      'uid' => $uid,
    );
    $policy = _password_policy_load_active_policy($roles, $dummy_account);
    if ($policy) {
      $expiration = $policy['expiration'];
      $warnings = !empty($policy['warning']) ? explode(',', $policy['warning']) : array();
      if (!empty($expiration)) {

        // Calculate expiration time.
        $expiration_seconds = $expiration * (60 * 60 * 24);
        $policy_start = $policy['created'];
        if (variable_get('password_policy_begin', 0) == 1) {
          $policy_start -= $expiration_seconds;
        }
        rsort($warnings, SORT_NUMERIC);
        $time = _password_policy_get_request_time();

        // Check expiration and warning days for each account.
        if (!empty($warnings)) {
          foreach ($warnings as $warning) {

            // Loop through all configured warning send-out days. If today is
            // the day, we send out the warning.
            $warning_seconds = $warning * (60 * 60 * 24);

            // Warning start time.
            $start_period = max($policy_start, $last_change) + $expiration_seconds - $warning_seconds;

            // Warning end time. We create a one day window for cron to run.
            $end_period = $start_period + 60 * 60 * 24;
            if ($warns[$uid] && $warns[$uid] > $start_period && $warns[$uid] < $end_period) {

              // A warning was already mailed out.
              continue;
            }
            if ($time > $start_period && $time < $end_period) {

              // A warning falls in the one day window, so we send out the
              // warning.
              $account = user_load($uid, TRUE);
              $message = drupal_mail('password_policy', 'warning', $account->mail, user_preferred_language($account), array(
                'account' => $account,
                'days_left' => $warning,
              ));
              if ($message['result']) {

                // The mail was sent out successfully.
                watchdog('password_policy', 'Password expiration warning mailed to %username at %email.', array(
                  '%username' => $account->name,
                  '%email' => $account->mail,
                ));
              }
              if ($pids[$uid]) {
                db_update('password_policy_expiration')
                  ->fields(array(
                  'warning' => $time,
                ))
                  ->condition('uid', $uid)
                  ->execute();
              }
              else {
                db_insert('password_policy_expiration')
                  ->fields(array(
                  'uid' => $uid,
                  'warning' => $time,
                ))
                  ->execute();
              }
            }
          }
        }
        if ($time > max($policy_start, $last_change) + $expiration_seconds && $time > $unblocks[$uid] + 60 * 60 * 24 && variable_get('password_policy_block', 0) == 0) {

          // Block expired accounts. Unblocked accounts are not blocked for 24h.
          // One time login lasts for a 24h.
          db_update('users')
            ->fields(array(
            'status' => 0,
          ))
            ->condition('uid', $uid)
            ->execute();
          if ($pids[$uid]) {
            db_update('password_policy_expiration')
              ->fields(array(
              'blocked' => $time,
            ))
              ->condition('uid', $uid)
              ->execute();
          }
          else {
            db_insert('password_policy_expiration')
              ->fields(array(
              'uid' => $uid,
              'blocked' => $time,
            ))
              ->execute();
          }
          $account = user_load($uid, TRUE);
          watchdog('password_policy', 'Password for user %name has expired.', array(
            '%name' => $account->name,
          ), WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
        }
      }
    }
  }
}