I've been testing the use of the Memcache session handling, and noticed that:

  1. There are no database writebacks for session information like there is for cache information.
  2. sess_destroy_uid(); is not implemented. Isn't that a security problem if a user is disabled while still logged in?

Perhaps there's a reasoning for this that I'm not able to see, but why shouldn't the session information be written back to the database? Is there a performance hit? If the writeback was there, it would be really easy to clear sessions by uid. I bring this up because I need to use the sess_destroy_uid(); function, but am unable to get my code to work when using Memcache session handling.

Comments

matt_paz’s picture

Category: feature » bug

+1

jeremy’s picture

Status: Active » Needs review
StatusFileSize
new554 bytes

The attached patch fixes this by looking up the memcache session by first retrieving the user object from memcache. It then uses this object to destroy the session. Please test.

jeremy’s picture

StatusFileSize
new545 bytes

Whoops -- the previous patch had a typo. This one should work. Please test.

jeremy’s picture

StatusFileSize
new1.01 KB

There was a code path where the session id wasn't saved in the user object, causing the sess_destroy_uid() to fail. The attached patch is updated to fix this. It works in all my testing.

jeremy’s picture

Status: Needs review » Fixed

Committed.

jeremy’s picture

Link to the commit for reference:
http://drupal.org/cvs?commit=237454

doq’s picture

Status: Fixed » Active

Only one user session (probably latest) gets deleted.

 function sess_destroy_uid($uid) {
+  $user = dmemcache_get($uid, 'users');
+  if (is_object($user) && isset($user->sid)) {
+    dmemcache_delete($user->sid, 'session');
+  }
+  dmemcache_delete($uid, 'users');
 }
darren oh’s picture

This could be fixed by storing an array of session IDs in the user object.

catch’s picture

Title: Session DB Writeback » sess_destroy_uid() implementation only deletes latest session
Version: 6.x-1.2 » 6.x-1.x-dev
darren oh’s picture

Status: Active » Needs review
StatusFileSize
new1.38 KB

This still needs to be fixed for situations where a user has multiple browsers, each with a different session.

darren oh’s picture

StatusFileSize
new1.51 KB

Patch for anyone else who still uses Drupal 5.

darren oh’s picture

Modified to prevent accumulation of dead sessions in the user object.

quotesbro’s picture

#12 looks reasonable, I applied it on production site

premanup’s picture

Issue summary: View changes
Status: Needs review » Needs work
function filter_user($op, &$edit, &$account, $category = NULL) {
  if ($op == 'update') {
    // Invalidate cached user object.
    cache_clear_all($account->uid, 'users');
  }
}

function sess_destroy_uid($uid) {
  $user = dmemcache_get($uid, 'users');
  if (is_object($user) && !empty($user->sids)) {
    foreach ($user->sids as $sid) {
      dmemcache_delete($sid, 'session');
    }
  }
  dmemcache_delete($uid, 'users');
}

As far as I can see if someone updates user's status or password then function filter_user() in memcache-session.inc is called before sess_destroy_uid(). See the user_save() in user.module:

function user_save($account, $array = array(), $category = 'account') {
    // ...

    user_module_invoke('update', $array, $account, $category);

    // ...

    // Delete a blocked user's sessions to kick them if they are online.
    if (isset($array['status']) && $array['status'] == 0) {
      sess_destroy_uid($account->uid);
    }

    // If the password changed, delete all open sessions and recreate
    // the current one.
    if (!empty($array['pass'])) {
      sess_destroy_uid($account->uid);
      if ($account->uid == $GLOBALS['user']->uid) {
        drupal_session_regenerate();
      }
    }
    // ...
}

Therefore when function dmemcache_get($uid, 'users') is called in sess_destroy_uid() it can't get $user object ($user == false). Therefore dmemcache_delete($sid, 'session') is not called at all and all session information stay in the session bin.

If I comment out line cache_clear_all($account->uid, 'users') in filter_user() then patch works as expected.

premanup’s picture

Status: Needs work » Needs review
StatusFileSize
new4.15 KB

I changed $op in filter_user() from 'update' to 'after_update'. It solves the problem. Here is the new patch.

japerry’s picture

Status: Needs review » Closed (outdated)

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.