View source
<?php
$plugin = array(
'admin form callback' => 'password_policy_expire_admin_form',
'prime value' => 'expire_limit',
'class' => 'PasswordPolicyExpire',
'config' => array(
'expire_enabled' => FALSE,
'expire_limit' => '6 months',
'expire_warning_message' => t('Your password has expired. Please change it now.'),
'expire_warning_email_sent' => '-14 days',
'expire_warning_email_message' => '',
'expire_warning_email_subject' => '[user:name], your password on [site:name] shall expire in [password_expiration_date:interval] ',
),
);
function password_policy_expire_admin_form($form, &$form_state, $constraint) {
$sub_form['expire_fieldset'] = array(
'#type' => 'fieldset',
'#title' => 'Password expiration',
'#collapsible' => TRUE,
'#collapsed' => !$constraint->config['expire_enabled'],
);
$sub_form['expire_fieldset']['expire_enabled'] = array(
'#type' => 'checkbox',
'#title' => 'Expire passwords',
'#default_value' => $constraint->config['expire_enabled'],
'#description' => t('Enable password expiration.'),
);
$sub_form['expire_fieldset']['enabled_container'] = array(
'#type' => 'container',
'#states' => array(
'visible' => array(
':input[name="expire_enabled"]' => array(
'checked' => TRUE,
),
),
),
);
$enabled_container =& $sub_form['expire_fieldset']['enabled_container'];
$enabled_container['expire_limit'] = array(
'#type' => 'textfield',
'#title' => 'Expire limit',
'#default_value' => $constraint->config['expire_limit'],
'#description' => t('Password will expire after being used for this long. (Use normal English, like 90 days or 5 hours.)'),
);
$enabled_container['expire_warning_message'] = array(
'#type' => 'textfield',
'#title' => 'Warning message',
'#default_value' => $constraint->config['expire_warning_message'],
'#description' => t('A message to show to users on screen when requiring them to change password. <strong>If left empty, no message will be shown.</strong>'),
);
$enabled_container['expire_warning_email_sent'] = array(
'#type' => 'textfield',
'#title' => 'When to send warning e-mails',
'#default_value' => $constraint->config['expire_warning_email_sent'],
'#description' => t('A comma separated list of time intervals, when to send warning e-mails. (Use normal English, like 90 days or 5 hours.) If prefixed with a negative (like -2 days) then this will be before the expiration. If left empty, no e-mail will be sent.'),
);
$enabled_container['expire_warning_email_subject'] = array(
'#type' => 'textfield',
'#title' => 'Warning e-mail subject',
'#default_value' => $constraint->config['expire_warning_email_subject'],
'#maxlength' => 180,
'#states' => array(
'visible' => array(
':input[name="expire_warning_email_sent"]' => array(
'empty' => FALSE,
),
),
),
);
$enabled_container['expire_warning_email_message'] = array(
'#type' => 'textarea',
'#title' => 'Warning e-mail message',
'#default_value' => $constraint->config['expire_warning_email_message'],
'#states' => array(
'visible' => array(
':input[name="expire_warning_email_sent"]' => array(
'empty' => FALSE,
),
),
),
);
if (module_exists('token')) {
$enabled_container['expire_warning_email_message_token'] = array(
'#theme' => 'token_tree',
'#token_types' => array(
'user',
'site',
'current-date',
'password_expiration_date',
),
'#global_types' => FALSE,
'#click_insert' => TRUE,
'#states' => array(
'visible' => array(
':input[name="expire_warning_email_sent"]' => array(
'empty' => FALSE,
),
),
),
);
}
return $sub_form;
}
function _password_policy_expire_notify($account, $candidate, $expire, PasswordPolicyExpire $item) {
$body = token_replace($item->config['expire_warning_email_message'], array(
'user' => $account,
'password_expiration_date' => $expire,
));
$subject = token_replace($item->config['expire_warning_email_subject'], array(
'user' => $account,
'password_expiration_date' => $expire,
));
$message = drupal_mail('password_policy', 'warning', $account->mail, user_preferred_language($account), array(
'body' => $body,
'subject' => $subject,
));
return $message;
}
function _password_policy_expire_query_users($notice_int, $policy_name) {
$current_pw_query = db_select('password_policy_history', 'c');
$current_pw_query
->fields('c', array(
'uid',
))
->groupBy('uid')
->addExpression('MAX(created)', 'created');
$query = db_select('password_policy_history', 'p');
$query
->fields('p', array(
'uid',
'hid',
'created',
));
$query
->join($current_pw_query, 'c', 'p.created = c.created AND p.uid = c.uid');
$query
->leftJoin('password_policy_notice_history', 'nh', 'nh.hid = p.hid AND nh.name = :policy_name AND nh.timeframe = :notice_int', array(
':policy_name' => $policy_name,
':notice_int' => $notice_int,
));
$query
->isNull('nh.hid');
$query
->condition('p.created', REQUEST_TIME - $notice_int, '<');
$candidates = array();
$result = $query
->execute();
foreach ($result as $row) {
$candidates[$row->uid] = $row;
}
return $candidates;
}
class PasswordPolicyExpire extends PasswordPolicyItem {
public $ppType = array(
'item',
'cron',
'init',
);
public function init($account) {
$enabled = $this->config['expire_enabled'];
if (!$enabled) {
return;
}
$expire_int = password_policy_parse_interval($this->config['expire_limit']);
if (!$expire_int) {
return;
}
if (drupal_is_cli()) {
return FALSE;
}
$stop = module_invoke_all('password_policy_expire_url_exclude', $account);
if (!empty($stop)) {
return FALSE;
}
password_policy_user_load(array(
$account->uid => $account,
));
if ($account->uid == 0) {
return;
}
if (!isset($account->password_history[0])) {
$account->password_history[0] = (object) array(
'uid' => $account->uid,
'pass' => $account->pass,
'created' => REQUEST_TIME,
'is_generated' => FALSE,
);
password_policy_update_password_history($account->password_history[0]);
}
if ($account->password_history[0]->created + $expire_int < REQUEST_TIME) {
if (current_path() != 'password_policy/check') {
$password_change_path = $this
->getPasswordChangePath($account);
if (current_path() != $password_change_path) {
$this
->setExpiredWarningMessage();
$this
->goToPasswordChangePath($account);
}
}
}
}
public function getPasswordChangePath($account) {
return "user/{$account->uid}/edit";
}
public function goToPasswordChangePath($account) {
$password_change_path = $this
->getPasswordChangePath($account);
$options = array(
'query' => drupal_get_destination(),
);
unset($_GET['destination']);
drupal_goto($password_change_path, $options);
}
public function setExpiredWarningMessage() {
if (!empty($this->config['expire_warning_message'])) {
drupal_set_message($this->config['expire_warning_message'], 'warning');
}
}
public function cron() {
$enabled = $this->config['expire_enabled'];
if (!$enabled) {
return;
}
if (empty($this->config['expire_warning_email_sent'])) {
return;
}
$notice_interval_strings = explode(',', $this->config['expire_warning_email_sent']);
$expire_interval_string = $this->config['expire_limit'];
$policy_name = $this->policy->name;
foreach ($notice_interval_strings as $notice_interval_string) {
$notice_interval_string = trim($notice_interval_string);
$from_interval = drupal_substr($notice_interval_string, 0, 1) == '-';
$notice_interval_string = ltrim($notice_interval_string, '-');
$notice_int = password_policy_parse_interval($notice_interval_string);
$expire_int = password_policy_parse_interval($expire_interval_string);
if ($from_interval) {
$notice_int = $expire_int - $notice_int;
}
$candidates = _password_policy_expire_query_users($notice_int, $policy_name);
foreach ($candidates as $candidate) {
$account = user_load($candidate->uid, TRUE);
if ($this->policy
->match($account)) {
$message = _password_policy_expire_notify($account, $candidate, $candidate->created + $expire_int, $this);
if ($message['result']) {
watchdog('password_policy', 'Password expiration warning mailed to %username at %email.', array(
'%username' => $account->name,
'%email' => $account->mail,
));
$notice_history = (object) array(
'hid' => $candidate->hid,
'name' => $this->policy->name,
'timeframe' => $notice_int,
'sent' => time(),
);
drupal_write_record('password_policy_notice_history', $notice_history);
}
}
}
}
}
}