hibernian has asked for the wisdom of the Perl Monks concerning the following question:

Brothers,

This could be me attempting to drive a square peg into a round hole - however, please humour me as I have a small problem.

A web application uses Apache and auth_mysql to provide password-protected access. The application then uses REMOTE_USER to determine how it runs and what is available to the authenticated user.

Now, I would like the opportunity to allow the user to log out and log in again as a different user, without closing the browser or restarting the web client.

I stupidly assumed that I could ask the web browser to undef the REMOTE_USER variable, but life is never as simple as this, is it?

Am I barking up the wrong tree or is there a method I can use in Perl?

My thanks in advance.

-Gregor-

  • Comment on undef-ing $ENV{'REMOTE_USER'} from within Perl?

Replies are listed 'Best First'.
Re: undef-ing $ENV{'REMOTE_USER'} from within Perl?
by tadman (Prior) on Jul 11, 2001 at 20:54 UTC
    While your "round peg into a square hole" solution might work, you could actually just do it by the book and be done with it. Square peg, square hole and all that.

    The gist of it is that you need a page or script that generates a "401 Unauthorized" error. This is a message to your browser that it should prompt for authentication, and then you can go back to doing whatever you wanted.

    This can be done through CGI.pm using the standard header method, such as a script called "logout.cgi" which has the following statement inside it:
    print $q->header ( -status => 401 );
    When they run the script again, you should redirect them using $q->redirect() to the main page.

    To figure out when this script has been run the first time (i.e. logout request) and the second (i.e. redirect request), you will have to track who ran it, and from where, using some method, which could be as basic as temporary files, or a database column if you have such a thing available.

    One trick that I once used was something like this. The page had a link to "logout.cgi?sess=4190141041&page=/home" where the stuff on the end was some random number. The "logout program" looked something like:
    use strict; use CGI; my $q = new CGI; my $lock_dir = "/tmp/lock"; my $other_url = my ($sess) = $q->param{sess} =~ /^(\d+)/; if (-f "$lock_dir/$sess.logout") { # Check for stale lock files here, too, # such as all those over 1 day old. # Remove this particular lock file unlink ("$lock_dir/$sess.logout"); print $q->redirect ($q->param{page}); } else { # Create a zero byte lock file for this session open (LOCK, ">$lock_dir/$sess.logout"); close (LOCK); # Return a refused message which causes the # browser to prompt for authentication. print $q->header ( -status => 401 ); }
      Indeed.

      This occurred to me last night once I was away from the machine. It's amazing what a couple of glasses of wine can do for lateral thought.

      I knew there was a square peg - square hole solution somewhere ; I just could not see it.

      Your solution is more than adequate. Thanks for all your help.

      -Gregor-

Re: undef-ing $ENV{'REMOTE_USER'} from within Perl?
by arturo (Vicar) on Jul 11, 2001 at 20:57 UTC

    Update I didn't read hard enough. Indeed, if you send a 401 error, the credentials the browser supplies are rejected, and most clients on the market today will in fact clear the user name after receiving such a response.

    If the request already included Authorization 
    credentials, then the 401 response indicates
    that authorization has been refused for 
    those credentials.
    

    Note it doesn't say what the client *must* do at this point ... herendeth the update)

    Looking over the HTTP RFC (RFC1945 for 1.0) I come to the conclusion that REMOTE_USER is derived from a part of the HTTP header sent by the *client* to the webserver, so in general, the answer would be that the client must unset it -- the RFC does not explicitly state that there must be a method for ending a session, so the browser manufacturers wouldn't necessarily have a uniform method -- or any method at all -- for ending a Basic Auth session. For obvious reasons (you don't want some guy on a remote site mangling your clients), unless the user gives explicit permission, you can't unset it with server-side code. You can, of course, unset it for the duration of the a single request using tachyon's method, but on the next request, it will be re-sent by the client.

    Basically, it's determined on a client-by-client basis. There *might* be some Javascript-based way of doing it, but that, too would require that the user allow your Javascript to modify their browser's setup.

    perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'
      the RFC does not explicitly state that there must be a method for ending a session

      Well, that's kind of logical, isn't? HTTP is a stateless, sessionless protocol. Hence, the RFC will not give you methods to end sessions - there are no sessions to begin with. You might want to kludge sessions on top of HTTP one way or the other (there are ways, cookies being a popular kludge), but that's outside the HTTP protocol itself.

      -- Abigail

Re: undef-ing $ENV{'REMOTE_USER'} from within Perl?
by tachyon (Chancellor) on Jul 11, 2001 at 20:36 UTC

    You can just set it to undef like this:

    $ENV{'REMOTE_USER'} = undef; # to see all the keys in the %ENV hash for $key (keys %ENV) { print "$key $ENV{$key}\n"; }

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print