For Drupal running over PostgreSQL, I've found that on certain conditions the expiration warnings are sent multiple times.

This seems to depend on the way password policy get the data from the database in the function password_policy_cron() in password_policy.module:561:

  // Get all users' last password change time. We 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', 'created'))
    ->fields('p', array('created'))
    ->fields('e', array('pid', 'unblocked', 'warning'))
    ->condition('u.uid', 0, '>')
    ->condition('u.status', 1)
    ->orderBy('p.created')
    ->execute();

This code results in the following query:

SELECT u.uid AS uid, u.created AS created, p.created AS p_created, e.pid AS pid, e.unblocked AS unblocked, e.warning AS warning
FROM 
drupal_users u
LEFT OUTER JOIN drupal_password_policy_history p ON u.uid = p.uid
LEFT OUTER JOIN drupal_password_policy_expiration e ON u.uid = e.uid
WHERE  (u.uid > 1) AND (u.status = 1) ORDER BY p.created;

This query will not produce the expected results in every situation. For example, I report the last lines for an user in our database:

 uid |  created   | p_created  | pid | unblocked |  warning   
-----+------------+------------+-----+-----------+------------
  92 | 1424875056 | 1473749500 |     |           | 1481108701
  92 | 1424875056 | 1473749500 |     |           | 1480247401
  92 | 1424875056 | 1473749500 |     |           | 1480243801
  92 | 1424875056 | 1473749500 |     |           | 1438788782
  92 | 1424875056 | 1473749500 |     |           | 1438810385
  92 | 1424875056 | 1473749500 |     |           | 1481105101
  92 | 1424875056 | 1473749500 |     |           | 1480240201
  92 | 1424875056 | 1473749500 |     |           | 1438828382
  92 | 1424875056 | 1473749500 |     |           | 1480236601
  92 | 1424875056 | 1473749500 |     |           | 1438795982
  92 | 1424875056 | 1473749500 |     |           | 1452877718
  92 | 1424875056 | 1473749500 |     |           | 1480233001
  92 | 1424875056 | 1473749500 |     |           | 1452527842

As you can see, the results are only ordered by p_created column. We need to order them also for the warning column, to obtain the last time a expiration warning was sent for the user.
In the above situation, if the cron run more than a time during the day, the expiration warning is sent more than once.

The proposed solution is to add the column e.warning for ordering the mentioned query.

  // Get all users' last password change time. We 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', 'created'))
    ->fields('p', array('created'))
    ->fields('e', array('pid', 'unblocked', 'warning'))
    ->condition('u.uid', 0, '>')
    ->condition('u.status', 1)
    ->orderBy('p.created, e.warning')
    ->execute();

Regards,

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mithenks created an issue. See original summary.

mithenks’s picture

Version: 7.x-2.x-dev » 7.x-1.x-dev
Status: Active » Needs review
FileSize
752 bytes

Here is my patch for 7.x-1.x

Status: Needs review » Needs work

The last submitted patch, 2: password_policy-fix-multiple-warnings-mail-2833776-2.patch, failed testing.

mithenks’s picture

Status: Needs work » Needs review

The patch submitted on comment #2 fails the test against Drupal 7.43, but it works well with Drupal 7.52/7.53 .
Furthermore, the actual 7.x-1.x-dev fails test against Drupal 7.52/7.53.

AohRveTPV’s picture

Changed to use multiple orderBy() calls to sort on multiple fields. From https://api.drupal.org/api/drupal/includes!database!select.inc/function/..., it looks like it is the preferred way to do that. mithenks, is it easy for you to test that this patch also works?

Thanks for the bug report and fix. I have not tried reproducing the problem but it makes sense that the order of the warnings column is not guaranteed by the unpatched code.

  • AohRveTPV committed 0b8babe on 7.x-1.x authored by mithenks
    Issue #2833776 by mithenks, AohRveTPV: Multiple warning mails sent per...
AohRveTPV’s picture

Status: Needs review » Fixed

Feel confident my patch is functionally equivalent, so I've gone ahead and committed. Thanks for the bug report and patch.

The tests failed before likely due to #2857748: Password expiration tests do not reliably pass.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.