View source
<?php
function force_password_change_settings($form, &$form_state) {
$form['#attached']['css'] = array(
drupal_get_path('module', 'force_password_change') . '/css/force_password_change_settings.css',
);
$form['first_time_login_password_change'] = array(
'#type' => 'checkbox',
'#title' => t('Force password change on first-time login'),
'#default_value' => variable_get('force_password_change_first_time_login_password_change', 0),
);
$form['login_or_init'] = array(
'#type' => 'radios',
'#title' => t('Check for pending password change'),
'#options' => array(
0 => t('on every page load'),
1 => t('on login only'),
),
'#default_value' => variable_get('force_password_change_login_or_init', 0),
'#description' => t('Select when to check if a user has a pending password change. Checking on every page load adds a little overhead to every page load, but is the most secure method. Checking on login will only check if a change is pending when the user first logs in, but on sites where users may stay logged in for lengthy periods of time, it may be a long time before they are forced to change their password.'),
);
$all_roles = user_roles(TRUE);
foreach ($all_roles as $rid => $role) {
if ($rid > 2) {
$user_count = db_query('SELECT COUNT(uid) FROM {users_roles} WHERE rid = :rid', array(
':rid' => $rid,
))
->fetchCol();
$pending_count = db_query('SELECT COUNT(u.uid) ' . 'FROM {users} AS u ' . 'JOIN {users_roles} AS ur ' . 'ON ur.uid = u.uid ' . 'WHERE u.force_password_change = 1 AND u.uid > 0 AND ur.rid = :rid', array(
':rid' => $rid,
))
->fetchCol();
}
elseif ($rid == 2) {
$user_count = db_query('SELECT COUNT(uid) FROM {users} WHERE uid > 0')
->fetchCol();
$pending_count = db_query('SELECT COUNT(uid) FROM {users} WHERE force_password_change = 1 AND uid > 0')
->fetchCol();
}
$roles[$rid] = $role;
$stats[$rid] = array(
'user_count' => $user_count[0],
'pending_count' => $pending_count[0],
);
}
$form['roles'] = array(
'#type' => 'checkboxes',
'#options' => $roles,
'#title' => t('Force users in the following roles to change their password'),
'#description' => t('Users will be forced to change their password either on their next page load, or on their next login, depending on the setting in "Check for pending password change". If pending password changes are checked on every page load, logged in users will be forced to immediately change their password, and after changing it will be redirected back to the page they were attempting to access.') . '<br />' . t('Note: When you return to this page, no roles will be selected. This is because this setting is a trigger, not a persistant state.'),
);
$expiry_data = db_query('SELECT rid, expiry, weight from {force_password_change_expiry} ORDER BY weight ASC, rid ASC');
$expiry = array();
foreach ($expiry_data as $data) {
$expiry[$data->rid] = array(
'expiry' => $data->expiry,
'weight' => $data->weight,
);
}
$form['expiry_data'] = array(
'#type' => 'value',
'#value' => $expiry,
);
$form['expiry'] = array(
'#type' => 'fieldset',
'#title' => t('Password Expiry'),
'#collapsible' => TRUE,
);
$form['expiry']['expire_password'] = array(
'#type' => 'checkbox',
'#title' => t('Enable password expiration'),
'#default_value' => variable_get('force_password_change_expire_password', FALSE),
'#description' => t('When this box is checked, passwords will be set to expire according to the rules set out below. If this box is un-checked, password expiry will be disabled, and the password expiry options below will be ignored.'),
);
$form['expiry']['header'] = array(
'#markup' => '<p>' . t('Select the amount of time after which you would like users in a role to be automatically forced to change their password. Any users who do not change their password in this amount of time will be forced to change their password on their next login or page load (depending on the setting in "Check for pending password change"). If you do not wish passwords to expire for a certain role, leave/set the value for that role to zero.') . '</p>',
);
$form['expiry']['table'] = array(
'#tree' => TRUE,
'#theme' => 'force_password_change_expiry',
);
$time_period = array(
'hours',
'days',
'weeks',
'years',
);
$heaviest_weight = 0;
if (count($expiry)) {
foreach ($expiry as $rid => $data) {
$form['expiry']['table'][$rid]['role'] = array(
'#markup' => $roles[$rid],
);
if ($data['expiry'] != '' && $data['expiry']) {
$expires = $data['expiry'];
$year = 60 * 60 * 24 * 365;
if ($expires % $year === 0) {
$time_period_default = 3;
$time_quantity_default = $expires / $year;
}
else {
$week = 60 * 60 * 24 * 7;
if ($expires % $week === 0) {
$time_period_default = 2;
$time_quantity_default = $expires / $week;
}
else {
$day = 60 * 60 * 24;
if ($expires % $day === 0) {
$time_period_default = 1;
$time_quantity_default = $expires / $day;
}
else {
$hour = 60 * 60;
$time_period_default = 0;
if ($expires % $hour === 0) {
$time_quantity_default = $expires / $hour;
}
else {
$time_quantity_default = 0;
}
}
}
}
}
else {
$time_period_default = 0;
$time_quantity_default = 0;
}
$form['expiry']['table'][$rid]['time_quantity'] = array(
'#type' => 'textfield',
'#default_value' => $time_quantity_default,
);
$form['expiry']['table'][$rid]['time_period'] = array(
'#type' => 'select',
'#options' => $time_period,
'#default_value' => $time_period_default,
);
$form['expiry']['table'][$rid]['weight'] = array(
'#type' => 'weight',
'#delta' => count($roles),
'#default_value' => $data['weight'] != '' ? $data['weight'] : 0,
);
$heaviest_weight = $data['weight'] != '' ? $data['weight'] : 0;
}
}
foreach ($roles as $rid => $r) {
if (!isset($form['expiry']['table'][$rid])) {
$heaviest_weight++;
$form['expiry']['table'][$rid]['role'] = array(
'#markup' => $r,
);
$form['expiry']['table'][$rid]['time_quantity'] = array(
'#type' => 'textfield',
'#default_value' => 0,
);
$form['expiry']['table'][$rid]['time_period'] = array(
'#type' => 'select',
'#options' => $time_period,
);
$form['expiry']['table'][$rid]['weight'] = array(
'#type' => 'textfield',
'#default_value' => $heaviest_weight,
);
}
}
$form['expiry']['footer'] = array(
'#markup' => '<p>' . t('Drag and drop the rows to set the priority for password expiry. The roles with the highest priority should be placed at the top of the list. If a user is a member of more than one role, then the time after which their password expires will be determined by whichever of their roles has the highest priority (highest in the list). Expiry rules for any roles of lower priority (lower in the list) will be ignored. As such, any roles lower in priority (below) the authenticated user role will effectively be ignored, since all users are members of the authenticated users role.') . '</p>',
);
$form['stats'] = array(
'#type' => 'value',
'#value' => $stats,
);
$form['change_password_url'] = array(
'#type' => 'textfield',
'#title' => t('Path to password change URL'),
'#description' => t('Only change this URL you have implemented a module that changes the user password URL from user/[UID]/edit to something else. Use !uid in place of the user id') . '<br />' . t('WARNING: if you set this URL to an invalid URL, you could break your site, so backup your files first, and double check the path before setting it.'),
'#default_value' => variable_get('force_password_change_change_password_url', 'user/!uid/edit'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
function force_password_change_settings_submit($form, &$form_state) {
$selected_roles = array();
variable_set('force_password_change_change_password_url', $form_state['values']['change_password_url']);
variable_set('force_password_change_first_time_login_password_change', $form_state['values']['first_time_login_password_change']);
variable_set('force_password_change_login_or_init', $form_state['values']['login_or_init']);
$au = FALSE;
foreach ($form_state['values']['roles'] as $rid) {
if ($rid > 2) {
$selected_roles[] = $rid;
if (!$au) {
$db_uids = db_query('SELECT uid ' . 'FROM {users_roles} ' . 'WHERE rid = :rid', array(
':rid' => $rid,
));
$uids = array();
foreach ($db_uids as $uid) {
$uids[] = $uid->uid;
}
if (isset($uids[0])) {
force_password_change_force_users($uids);
}
}
}
elseif ($rid == 2) {
force_password_change_force_users();
$selected_roles[] = $rid;
$au = TRUE;
}
}
if (isset($selected_roles[0])) {
$query = db_update('force_password_change_roles')
->fields(array(
'last_force' => REQUEST_TIME,
))
->condition('rid', $selected_roles, 'IN')
->execute();
$roles = user_roles(TRUE);
$list = '<ul>';
foreach ($selected_roles as $sr) {
$list .= '<li>' . $roles[$sr] . '</li>';
}
$list .= '</ul>';
if ($form_state['values']['login_or_init']) {
drupal_set_message(t('Users in the following roles will be required to change their password on their next login: !list', array(
'!list' => $list,
)), 'status');
}
else {
drupal_set_message(t('Users in the following roles will be required to immediately change their password: !list', array(
'!list' => $list,
)), 'status');
}
}
variable_set('force_password_change_expire_password', $form_state['values']['expire_password']);
$query = db_insert('force_password_change_expiry')
->fields(array(
'rid',
'expiry',
'weight',
));
$execute_query = FALSE;
foreach ($form_state['values']['table'] as $rid => $expiry) {
$multiplier = array(
60 * 60,
60 * 60 * 24,
60 * 60 * 24 * 7,
60 * 60 * 24 * 365,
);
$time_period = $expiry['time_quantity'] * $multiplier[$expiry['time_period']];
if (isset($form_state['values']['expiry_data'][$rid]) && ($time_period != $form_state['values']['expiry_data'][$rid]['expiry'] || $expiry['weight'] != $form_state['values']['expiry_data'][$rid]['weight'])) {
$update_query = db_update('force_password_change_expiry')
->fields(array(
'expiry' => $time_period,
'weight' => $expiry['weight'],
))
->condition('rid', $rid)
->execute();
}
elseif (!isset($form_state['values']['expiry_data'][$rid])) {
$query
->values(array(
'rid' => $rid,
'expiry' => $time_period,
'weight' => $expiry['weight'],
));
$execute_query = TRUE;
}
}
if ($execute_query) {
$query
->execute();
}
}
function force_password_change_list($rid) {
$roles = user_roles(TRUE);
if ($rid < 2 || !$rid) {
drupal_set_title(t("Error: role doesn't exist"));
return t("Error: role doesn't exist.");
}
else {
$exists = db_query('SELECT 1 FROM {role} WHERE rid = :rid', array(
':rid' => $rid,
))
->fetchCol();
if (!isset($exists[0])) {
drupal_set_title(t("Error: role doesn't exist"));
return t("Error: role doesn't exist.");
}
}
drupal_set_title(t('Force Password Change details for !role', array(
'!role' => $roles[$rid],
)));
$last_change = db_query('SELECT last_force FROM {force_password_change_roles} WHERe rid = :rid', array(
':rid' => $rid,
))
->fetchCol();
$last_change = $last_change[0] != '' ? format_date($last_change[0], 'small') : t('Never');
$variables['last_change'] = $last_change;
$pending_query = db_select('users', 'u')
->extend('PagerDefault')
->extend('TableSort')
->element(0);
$alias = $pending_query
->join('force_password_change_users', 'fpcu', 'fpcu.uid = u.uid');
$pending_query
->addTag('force_password_change_pending_users')
->fields('u', array(
'uid',
'name',
'created',
))
->fields($alias, array(
'last_force',
'last_password_change',
))
->limit(100)
->condition('u.force_password_change', 1);
if ($rid > 2) {
$alias2 = $pending_query
->join('users_roles', 'ur', 'ur.uid = u.uid');
$pending_query
->condition($alias2 . '.rid', $rid);
}
$pending_header = array(
array(
'data' => t('Username'),
'field' => 'u.name',
'sort' => 'asc',
),
array(
'data' => t('Last Forced Password Change'),
'field' => $alias . '.last_force',
),
array(
'data' => t('Last Password Change'),
'field' => $alias . '.last_password_change',
),
);
$pending_query
->orderByHeader($pending_header);
$pending_user_data = $pending_query
->execute();
$rows = array();
$force_password_change_installation_date = variable_get('force_password_change_installation_date', 0);
$forced_uids = variable_get('force_password_change_first_time_uids', array());
foreach ($pending_user_data as $pending_user) {
$row = array();
$row[] = user_access('access user profiles') ? l($pending_user->name, 'user/' . $pending_user->uid) : $pending_user->name;
if ($pending_user->last_force != '') {
$last_force = format_date($pending_user->last_force, 'small');
}
elseif (variable_get('force_password_change_first_login_change', FALSE) && $pending_user->created > $force_password_change_installation_date) {
$last_force = t('Their first login');
}
else {
if (count($forced_uids) && isset($forced_uids[$pending_user->uid])) {
$last_force = t('Their first login');
}
elseif ($pending_user->last_password_change != '') {
$last_force = t('Their first login');
}
else {
$last_force = t('Never');
}
}
$row[] = $last_force;
$row[] = $pending_user->last_password_change != '' ? format_date($pending_user->last_password_change, 'small') : t('Never');
$rows[] = $row;
}
if (!count($rows)) {
$row = array();
$row[] = array(
'data' => t('No users found'),
'colspan' => 3,
);
$rows[] = $row;
}
$variables['pending_users_table'] = theme('table', array(
'header' => $pending_header,
'rows' => $rows,
)) . theme('pager');
$nonpending_query = db_select('users', 'u')
->extend('PagerDefault')
->extend('TableSort')
->element(1);
$alias = $nonpending_query
->join('force_password_change_users', 'fpcu', 'fpcu.uid = u.uid');
$nonpending_query
->addTag('force_password_change_nonpending_users')
->fields('u', array(
'uid',
'name',
'created',
))
->fields($alias, array(
'last_force',
'last_password_change',
))
->limit(100)
->condition('u.force_password_change', 0);
if ($rid > 2) {
$alias2 = $nonpending_query
->join('users_roles', 'ur', 'ur.uid = u.uid');
$nonpending_query
->condition($alias2 . '.rid', $rid);
}
$nonpending_header = array(
array(
'data' => t('Username'),
'field' => 'u.name',
'sort' => 'asc',
),
array(
'data' => t('Last Forced Password Change'),
'field' => $alias . '.last_force',
),
array(
'data' => t('Last Password Change'),
'field' => $alias . '.last_password_change',
),
);
$nonpending_query
->orderByHeader($nonpending_header);
$nonpending_user_data = $nonpending_query
->execute();
$rows = array();
foreach ($nonpending_user_data as $nonpending_user) {
$row = array();
$row[] = l($nonpending_user->name, 'user/' . $nonpending_user->uid);
if ($nonpending_user->last_force != '') {
$last_force = format_date($nonpending_user->last_force, 'small');
}
elseif (variable_get('force_password_change_first_login_change', FALSE) && $nonpending_user->created > $force_password_change_installation_date) {
$last_force = t('Their first login');
}
else {
if (count($forced_uids) && isset($forced_uids[$nonpending_user->uid])) {
$last_force = t('Their first login');
}
elseif ($nonpending_user->last_password_change != '') {
$last_force = t('Their first login');
}
else {
$last_force = t('Never');
}
}
$row[] = $last_force;
$row[] = $nonpending_user->last_password_change != '' ? format_date($nonpending_user->last_password_change, 'small') : t('Never');
$rows[] = $row;
}
if (!count($rows)) {
$row = array();
$row[] = array(
'data' => t('No users found'),
'colspan' => 3,
);
$rows[] = $row;
}
$variables['nonpending_users_table'] = theme('table', array(
'header' => $nonpending_header,
'rows' => $rows,
)) . theme('pager');
$elements = drupal_get_form('force_password_change_single_role', $rid);
$variables['force_password_change_form'] = drupal_render($elements);
if (arg(6)) {
if (arg(6) == 'settings') {
$back_button = l(t('Back to settings page'), 'admin/config/people/force_password_change');
}
elseif (arg(6) == 'roles') {
$back_button = l(t('Back to roles page'), 'admin/people/permissions/roles');
}
}
else {
$back_button = '';
}
$variables['back_button'] = $back_button;
return theme('force_password_change_list', $variables);
}
function force_password_change_single_role($form, &$form_state, $rid) {
if (variable_get('force_password_change_login_or_init', 0)) {
$description = t('Users who are not signed in will be required to change their password immediately upon login. Users who are currently signed in will be required to change their password upon their next page click, but after changing their password will be redirected back to the page they were attempting to access.');
}
else {
$description = t('Users will be required to change their password upon their next login.');
}
$description .= '<br />' . t('Note: When you return to this page, this box will be unchecked. This is because this setting is a trigger, not a persistant state.');
$form['force_password_change'] = array(
'#type' => 'checkbox',
'#title' => t('Force users in this role to change their password'),
'#description' => $description,
'#weight' => -1,
);
$form['rid'] = array(
'#type' => 'value',
'#value' => $rid,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Force Password Change'),
);
return $form;
}
function force_password_change_single_role_submit($form, &$form_state) {
if ($form_state['values']['force_password_change']) {
$uids = array();
$rid = $form_state['values']['rid'];
if ($rid > 2) {
$db_uids = db_query('SELECT uid ' . 'FROM {users_roles} ' . 'WHERE rid = :rid', array(
':rid' => $rid,
));
foreach ($db_uids as $uid) {
$uids[] = $uid->uid;
}
if (isset($uids[0])) {
force_password_change_force_users($uids);
}
}
else {
force_password_change_force_users();
}
$query = db_update('force_password_change_roles')
->fields(array(
'last_force' => REQUEST_TIME,
))
->condition('rid', $rid)
->execute();
if (variable_get('force_password_change_login_or_init', 0)) {
drupal_set_message(t('Users in this role will be required to change their password on next login'));
}
else {
drupal_set_message(t('Users in this role will be required to immediately change their password'));
}
}
}
function theme_force_password_change_list($variables) {
$output = '<p><strong>' . t('Last forced password change for this role:') . '</strong> ';
$output .= $variables['last_change'];
$output .= '</p>';
$output .= '<h3>' . t('Users with a pending password change') . '</h3>';
$output .= $variables['pending_users_table'];
$output .= '<h3>' . t('Users without a pending password change') . '</h3>';
$output .= $variables['nonpending_users_table'];
$output .= $variables['force_password_change_form'];
$output .= '<p>' . $variables['back_button'] . '</p>';
return $output;
}
function theme_force_password_change_user_admin_roles_form($variables) {
$form =& $variables['form'];
$header = array(
t('Name'),
t('Weight'),
array(
'data' => t('Operations'),
'colspan' => 3,
),
);
foreach (element_children($form['roles']) as $rid) {
$name = $form['roles'][$rid]['#role']->name;
$row = array();
$edit_permissions = l(t('edit permissions'), 'admin/user/permissions/' . $rid);
if (in_array($rid, array(
DRUPAL_ANONYMOUS_RID,
DRUPAL_AUTHENTICATED_RID,
))) {
$row[] = t('@name <em>(locked)</em>', array(
'@name' => $name,
));
$row[] = drupal_render($form['roles'][$rid]['weight']);
$row[] = '';
$row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
}
else {
$row[] = check_plain($name);
$row[] = drupal_render($form['roles'][$rid]['weight']);
$row[] = l(t('edit role'), 'admin/people/permissions/roles/edit/' . $rid);
$row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
}
if ($rid != DRUPAL_ANONYMOUS_RID) {
$row[] = l(t('Force Password Change'), 'admin/config/people/force_password_change/list/' . $rid . '/roles');
}
else {
$row[] = '';
}
$rows[] = array(
'data' => $row,
'class' => array(
'draggable',
),
);
}
$rows[] = array(
array(
'data' => drupal_render($form['name']) . drupal_render($form['add']),
'colspan' => 4,
'class' => 'edit-name',
),
);
drupal_add_tabledrag('user-roles', 'order', 'sibling', 'role-weight');
$output = theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'id' => 'user-roles',
),
));
$output .= drupal_render_children($form);
return $output;
}
function theme_force_password_change_settings($variables) {
$form = $variables['form'];
$output = drupal_render($form['first_time_login_password_change']);
foreach (element_children($form['roles']) as $rid) {
$form['roles'][$rid]['#suffix'] = '<p>(' . t('Users in role: !user_count | Users with pending forced password change: !pending_count | !details', array(
'!user_count' => $form['stats']['#value'][$rid]['user_count'],
'!pending_count' => $form['stats']['#value'][$rid]['pending_count'],
'!details' => l(t('Details'), 'admin/config/people/force_password_change/list/' . $rid . '/settings'),
)) . ')</p>';
}
$output .= drupal_render($form['roles']);
$output .= drupal_render_children($form);
return $output;
}
function theme_force_password_change_expiry($variables) {
$form = $variables['form'];
$header = array(
t('Role'),
t('Expire password after:'),
t('Weight'),
);
$rows = array();
foreach (element_children($form) as $key) {
$row = array();
$element =& $form[$key];
$row[] = drupal_render($element['role']);
$row[] = drupal_render($element['time_quantity']) . drupal_render($element['time_period']);
$element['weight']['#attributes']['class'] = array(
'password-expiry-weight',
);
$row[] = array(
'data' => drupal_render($element['weight']),
'class' => array(),
);
$rows[] = array(
'data' => $row,
'class' => array(
'draggable',
),
);
}
drupal_add_tabledrag('password-expiry-table', 'order', 'sibling', 'password-expiry-weight');
$output = theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'id' => 'password-expiry-table',
),
)) . drupal_render_children($form);
return $output;
}
function theme_force_password_change_stats($variables) {
$items[] = t('User has a pending forced password change: !pending', array(
'!pending' => $variables['pending_change'],
));
$items[] = t('User was last forced to change their password on: !last_force', array(
'!last_force' => $variables['last_force'],
));
$items[] = t("User's password was last changed on: !last_change", array(
'!last_change' => $variables['last_change'],
));
$password_stats = '<p><strong>' . t('Password Stats:') . '</strong></p>';
$password_stats .= theme('item_list', array(
'items' => $items,
));
return $password_stats;
}