Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

how do I force a specific session, not my own, to end?

by ted.byers (Monk)
on Mar 08, 2013 at 19:38 UTC ( [id://1022481]=perlquestion: print w/replies, xml ) Need Help??

ted.byers has asked for the wisdom of the Perl Monks concerning the following question:

I am using CGI::Session, and for the most part, all is well. However, I have one requrement that I have not found even mentioned in the documentation.

One of the session parameters that I set is user_id (guaranteed to be unique). The use case I need to address involves an administrator who needs to disable a given user's account. However, there is the possibility of a problem since all users can change their own password. Since the obvious solution to disable an account is to change the password to something random, if the user has a current session, it is entirely possible that he might change his password to something else after the administrator has attempted to disable the account. On writing this, it occurs to me that I could require the user to re-enter his password in order to change it (solving one problem), but that still doesn't prevent the user from keeping a currently active session open indefinitely after the account is supposed to be disabled. If the user is an employee who has just been fired, he could do significant damage if I can't expire his sessions the instant his account is disabled.

Is it possible to iterate through all sessions that have not expired, and force those with a specific user ID to expire, in an operation that is simultaneous to the operation that changes the password in the DB?

NB: In this case, it is not the current user's session that must be forced to expire but rather any connected to a user who is no longer to be permitted to access or edit the data in the system.

NB: It is not acceptable to just delete the account as there may have accumulated a significant amount of data that must remain auditable, and relatable to a specific person.

Any thoughts on how I might do this would be greatly appreciated.

Thanks

Ted

Replies are listed 'Best First'.
Re: how do I force a specific session, not my own, to end?
by scorpio17 (Canon) on Mar 08, 2013 at 20:28 UTC

    You need to use the find() method. In the docs, they show how to use it to expire sessions 10+ days old. You should modify it something like this (where $bad_user_id is the user you want to remove):

    CGI::Session->find( \&purge ); sub purge { my ($session) = @_; next if $session->is_empty; # <-- already expired?! if ( ($session->param('user_id') eq $bad_user_id) ) { $session->delete(); $session->flush(); } } # now change password associated with $bad_user_id...

      Thanks. That put me on track to find the solution.

      What you didn't show was how to pass $bad_user_id to function purge. Here is my solution:

      sub purge_bad_user { my $bad_user = shift; $bad_user = -10 unless defined $bad_user; CGI::Session->find( sub { purge(@_,$bad_user) } ); } sub purge { my ($session,$bad_user_id) = @_; next if $session->is_empty; # <-- already expired?! if ( ($session->param('user_id') == $bad_user_id) ) { $session->delete(); $session->flush(); } my $db = 'test'; my $hostname = 'localhost'; my $user = 'rejbyers'; my $dbpwd = 'Didr39Qcab'; my $dbh = DBI->connect_cached("DBI:mysql:database=$db;host=$hostname +",$user,$dbpwd,{RaiseError => 1}) or die "Failed to connect to the DB.\n"; use Math::Random::MT::Auto::Range; my %prng_options; $prng_options{'LOW'} = 1000000000; $prng_options{'HIGH'} = 9999999999; $prng_options{'TYPE'} = 'INTEGER'; my $prng = Math::Random::MT::Auto::Range->new(%prng_options); my $p = $prng->rrand(); my $sql = "UPDATE users SET password = '$p' WHERE idusers = $bad_use +r_id"; $dbh->do($sql); $dbh->disconnect; }

      Please let me know if I missed something in this. I am still working on testing it.

      Thanks

      ted

      :) hurricane
      sub ban_user { my $banneduser = shift; my $purge = sub { my( $session ) = @_; next if $session->is_empty; # <-- already expired?! if ( ($session->param('user_id') eq $bad_user_id) ) { $session->delete(); $session->flush(); } }; DeAuthorize( $banneduser ); CGI::Session->find( $dsn, $purge, $dsn_args ); }
Re: how do I force a specific session, not my own, to end? (delete)
by Anonymous Monk on Mar 08, 2013 at 20:27 UTC

    delete the session

    The real problem here, is you're confusing a session with authorization

    autentication -- user proves he is a user -- could be he's got a valid session

    authorization -- permissions -- if account is disabled, doesn't matter if user has a valid session (authenticated, logged it), he can no longer change password, make posts ...

    If your code base doesn't distinguish from authentication and authorization, you've got a problem

      No, I don't have them confused. Rather, the two ideas are related in this specific use case, in that we're revoking all authorization for a specific user as well as making it impossible for him to authenticate himself in the future

      As it turned out, I had missed the fnd function provided by CGI__Session. That was what I needed

      thanks

      Ted

        In line with the previous post by anonymous, I think you're making this more complicated than it needs to be.

        An approach that allows you to skip purging sessions is to create an active_disabled flag for user accounts and at the authorization/permissions level don't allow disabled users to see anything they shouldn't see on the site. That way all that needs to be done to disable a user is to change this flag.

        No, I don't have them confused.

        Then your code is confusing them :)

        return if $user->isDisAllowed;

Re: how do I force a specific session, not my own, to end?
by sundialsvc4 (Abbot) on Mar 11, 2013 at 15:44 UTC

    Here’s what I would do, at least in a corporate setting:   I would use LDAP (nee OpenDirectory) as the basis of both authentication and authorization.   This is a well-known and of course well-supported source that can be used throughout a company.   The department responsible for security can click a button to update a record, knowing that all of the applications, badge-readers, and what not throughout the company will instantly and uniformly respect it.   This can be done on the web-server level, making the entire app inaccessible to those not authorized to use it.

    LDAP (or Kerberos) is used both for authentication and authorization.   The company should set a standard for how it wants to consistently manage these two concerns, and every securable thing in the company including this application should then follow suit.   If you want to know whether a user can do something, you query LDAP to find out.   You do this each time, so that changes take effect immediately.

    At the very least, your “home grown” system needs an Account Disabled boolean flag.   If the account is disabled, you can’t log in or stay logged in.   If the (internal) user-ID is part of the HTTP sessions table, all existing sessions associated with the user can be deleted.   Presto, he is no longer logged-in and cannot log in again.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1022481]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-03-19 07:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found