diff --git a/README.txt b/README.txt index 202e99e..1a9ae69 100644 --- a/README.txt +++ b/README.txt @@ -18,6 +18,32 @@ What it does: - Remove the PHP and paranoia modules from the module admin page. - Provides a hook to let you remove other modules from the module admin page. + +Using the feature to scramble the password for stale accounts +============================================================= +Paranoia includes a feature to scramble the password of an account that has not +logged in for a while. This feature uses a queue so that it can scalably handle +scrambling the password of thousands of accounts. The "scramble" does not set a +new password. It sets the password to an invalid string which will +always fail when compared to any user input. To use this feature: + +1. Navigate to /admin/config/system/paranoia to configure how many days an + account must be inactive before it's password will be scrambled. Also + choose whether or not to email users letting them know their password was + reset. + +2. Use the Drush command to queue up accounts to be marked as stale: + + drush -v paranoia-reset + +3. Run the queue to process the stale expirations: + + drush -v queue-run paranoia_stale_expirations + +Using the -v option on drush will show extra information about the operations. + +You can also let cron handle processing the queue, though that may take a long time. + NOTE on disabling: ===== The only way to disable paranoia module is by changing its status in the diff --git a/paranoia.drush.inc b/paranoia.drush.inc index e2f46f1..27777fb 100644 --- a/paranoia.drush.inc +++ b/paranoia.drush.inc @@ -6,7 +6,7 @@ */ /** - * Implements hook_drush_command(). + * Implements hook_drush_sql_sync_sanitize(). */ function paranoia_drush_sql_sync_sanitize($site) { // Don't use DBTNG here so this mostly workis across old versions of Drupal. @@ -91,12 +91,11 @@ function paranoia_drush_help($command) { * Implements hook_drush_command(). */ function paranoia_drush_command() { - $items = array(); - $items['paranoia-reset'] = array( - 'description' => dt('Queue accounts to have their passwords reset.'), - 'aliases' => array('prs'), + return array( + 'paranoia-reset-stale-accounts' => array( + 'description' => dt('Queue accounts to have their passwords reset if they have not logged in recently.'), + ) ); - return $items; } /** @@ -109,15 +108,19 @@ function drush_paranoia_reset() { // avoid duplicate queue items if the cron queue iterator from a previous // cron run has not gotten through all of its queued items. if ($queue->numberOfItems() > 0) { + watchdog('paranoia', 'Skipping adding items to the queue as stale expiration items already exist.'); return; } // Check for accounts whose last access time is older than the threshold, // which defaults to 2 years (365 * 2 = 730 days). - $offset = time() - (variable_get('paranoia_access_threshold', 730) * 60 * 60 * 24); + $offset = REQUEST_TIME - (variable_get('paranoia_access_threshold', 730) * 60 * 60 * 24); $result = db_query("SELECT uid FROM {users} WHERE uid > 0 AND access > 0 AND access < :offset AND pass NOT LIKE 'ZZZ%'", array(':offset' => $offset)); + $count = 0; foreach ($result as $record) { + $count++; $queue->createItem($record->uid); } + watchdog('paranoia', 'Queued @count users to have their password reset', ['@count' => $count]); } diff --git a/paranoia.module b/paranoia.module index f357258..a19ba25 100644 --- a/paranoia.module +++ b/paranoia.module @@ -1,17 +1,11 @@ array( 'title' => t('Administer paranoia'), @@ -409,7 +403,6 @@ function devel_paranoia_risky_forms() { */ function paranoia_cron_queue_info() { $queues['paranoia_stale_expirations'] = array( - // This is the callback function for the queue item. 'worker callback' => 'paranoia_reset_stale', 'time' => variable_get('paranoia_queue_time', 15), ); @@ -420,21 +413,34 @@ function paranoia_cron_queue_info() { * Worker callback for the paranoia_stale_expirations queue. */ function paranoia_reset_stale($item) { - if ($account = user_load($item)) { + paranoia_reset_password_for_uid($item); +} + +/** + * Resets a password on a uid and sends a mail as appropriate. + * + * @param $uid + * A user ID that should have their password reset. + */ +function paranoia_reset_password_for_uid($uid) { + if ($account = user_load($uid)) { // The ZZZ prefix ensures the password comparison will fail until a reset. // See user_check_password(). - $result = db_query("UPDATE users SET pass = CONCAT('ZZZ', SHA(CONCAT(pass, MD5(RAND())))) WHERE uid = :uid", array(':uid' => $account->uid)); - watchdog('paranoia', 'Password randomized for @user.', array('@user' => $account->name)); - if (variable_get('paranoia_email_notification', FALSE)) { - paranoia_expired_mail_send($account->uid); + $result = db_query("UPDATE {users} SET pass = CONCAT('ZZZ', SHA(CONCAT(pass, MD5(RAND())))) WHERE uid = :uid", array(':uid' => $account->uid)); + if ($result) { + watchdog('paranoia', 'Password randomized for @user.', array('@user' => $account->name), WATCHDOG_INFO); + if (variable_get('paranoia_email_notification', FALSE)) { + paranoia_expired_mail_send($account->uid); + } + } + else { + watchdog('paranoia', 'Failed to randomize password for uid @uid.', array('@uid' => $uid), WATCHDOG_ERROR); } } } /** - * Implements hook_mail. - * - * @todo Add optional token module support, to allow email to be personalized. + * Implements hook_mail(). */ function paranoia_mail($key, &$message, $params) { switch ($key) { @@ -456,7 +462,7 @@ As a security precaution, since you have not logged in to your account for } /** - * Sends an e-mail. + * Sends an e-mail if a password has been reset. * * @param $uid * The User ID of an account to email, to notify that the account's @@ -471,9 +477,7 @@ function paranoia_expired_mail_send($uid) { $params = array('uid' => $account->uid); $send = TRUE; - // Send the mail, and check for success. Note that this does not guarantee - // message delivery; only that there were no PHP-related issues encountered - // while sending. + // Send the mail, and check for success. $result = drupal_mail('paranoia', 'paranoia_expired', $account->mail, language_default(), $params, $from, $send); if ($result['result'] == TRUE) { watchdog('paranoia', 'Notification of randomized password sent to @account.', array('@account' => $account->name), WATCHDOG_INFO);