You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by ap...@dairylogic.co.uk on 2000/12/19 19:28:16 UTC

HTTP authentication based sessioning with logout ability

Hi there.

I've been trying to write a system to perform authentication using the www-authenticate (http authenatication) method. However, I need a client visiting the page and having been authenticated to be able to logout and have their browser forget the information (or at least be able to force the browser to re-authenticate within the same browser session).

As most browsers cache login details (sensibly - you don't want to enter your login details for each page you visit) the best system I can think of is to use dynamic realms. This would mean that when someone first visits the site, they will be given a random/sequential realm. When they then click on a logout button, the old realm is discarded, and if the browser tries to authenticate with the same realm it is refused (or alternatively the server just starts sending a different realm and the browser re-authenticates on the new realm). Significantly, the system needs to be accessible by several people simultaneously. The purpose is actually to allow someone accessing the site to log in, be served dynamic content on the basis of username (which I'm already doing), but have the option to log out and then back in as a different user.

I've been looking at different ways to do this, but haven't had any sucess as of yet. My first attempt was to use the module mod_auth_external to deal with authentication using a perl script (which would allow me to arbitrarily refuse login details even if they are correct, on the basis of other details such as realm). This is my preferable method (mainly because I understand it), but it seems that there's no way to integrate the realm into the auth_external system. This means that although I could refuse a username and password, I can't change the realm dynamically, and so I can't force the browser to re-authenticate (and without the realm information being passed to the script, I don't know if a visitor has re-authenticated with the same username or if their browser has simply sent the cached copy of the details).

After searching around for methods of dynamically assigning an authname, I stumbled across mod_perl. I've never in my life even looked at mod_perl (and I don't really understand object-oriented perl, I'm sorry to say - I came from a BASIC background - in more ways than one apparently). I also found an example script for assigning dynamic realms, but haven't been able to get it to work.

I have only been trying for a day, and I know it's bad of me to resort to a mailing list after such a short space of time, but I've trawled the Web for as much information as I can find but with no success.

The example mod_perl script I found was as follows:

<From http://www.davin.ottawa.on.ca/archive/modperl/2000-09/msg00839.phtml>

#############################################################################

Here's a simple handler that will set the AuthType and AuthName
dynamically and handle the authentication for you. This handler will
prompt you for a password when you try to acess /manual with the
AuthName, "The Manual" and prompt with the AuthName "The Icons" when you
try to access /icons. These urls are part of Apaches basic installation
(that's if you did not remove the manual from your htdocs directory).
The authentication phase will let you in just as long you supply a
username and password. You can of course code such that it you can
authenicate against a .htpassword file, using Apache::Htpasswd.

Anyhow, this should show you that you can indeed change the AuthName
on-the-fly and also handle 
authentication without having to include AuthName,AuthType,AuthUserFile
explicitly in your httpd.conf.

Note: the authentication subroutine acted flaky, sometimes it worked and
other times it didn't. But the realms did change for the each uri. 

i hope this helps you....have fun ;)


Setting it up:

In your httpd.conf ( in a global area):

PerlHeaderParserHandler Apache::SetRealm;


=code

package Apache::SetRealm;

use Apache;
use Apache::Constants qw(:common);
sub handler {
    my $r   = shift;

    ## Make Apache aware the we want to also handle the Authentication
phase using a custom
    ## handler, in this case the subroutine authenticate()
          $r->push_handlers(PerlAuthenHandler => \&authenticate);
    my $uri = $r->uri;

   ## only handle uri that are defined as protected, in this case the
only protected
   ## uri's are /icons and /manuals
    return OK unless is_protected($r);
    my $realm = get_realm($r);

    ## Construct the Header Field containing the type of authenticate
(Basic) and our
   ## realmname return by get_realm()
    my $authheader = 'Basic realm="'.$realm.'"';

    $r->header_out("WWW-Authenticate" ,$authheader);

    ## Return 401 to browser and prompt for login
    $r->status(AUTH_REQUIRED);
    $r->send_http_header("text/html");
    return AUTH_REQUIRED;
}

sub get_realm {
     ## Get the AuthName for a specific uri. You can probably read these
off of a file that
     ## contains a list of uri's and realmNames
      my $r = shift;
      return "The Icons"  if ($r->uri =~ /\/icons/);
      return "The Manual" if ($r->uri =~ /\/manual/);
}

sub is_protected {
      ## Check the $uri requested matches our set of "Restricted"
locations
     ## 1 = isProtected, 0 = NotProtected
     ## You can probably have these protected areas in a seperate file,
the eagle book
     ## has some excellent ideas on how to acomplish this
      my $r = shift;
      my @protected = ('\/manual','\/icons');

      for (@protected) { return 1 if ($r->uri =~ /$_/); }
      return 0;
}

sub authenticate {
      ## Straight out of the Eagle Book
    my $r = shift;

    return OK if $r->sub_request;

    my ($res,$password) = $r->get_basic_auth_pw;
    return $res if $res != OK;

    my $username = $r->connection->user;
    unless ($username && $pass) {
           $r->note_basic_auth_failure;
           $r->log_reason("Did not provide username");
           return AUTH_REQUIRED;
    }

    ## Now that you have the $username and $password you can
    ## include your code to open your AuthUserFile to check the password
and username
    ## I suggest using Apache::Htpasswd, it provides all the
methods/functions that you need to
    ## accomplish this part of the task...

    $r->log_reason("WELCOME $user");
    return OK;

}

#############################################################################

I've made some minor changes (but the changes all seem to work). The specific error I'm getting now is relating to the line:

    return OK if $r->sub_request;

... in the authenticate subroutine. The error which appears in the apache error logs is:

    [Tue Dec 19 17:32:04 2000] [error] Can't locate object method "sub_request" via package "Apache" at /usr/lib/perl5/5.6.0/i386-linux/raxware/AssignRealm.pm line 85.

As I say, I'm new to mod_perl and object-oriented perl, so maybe this is simple to solve, but I can't find any online reference to the same error, or any reference to the purpose of the method 'sub_request'.


Basically I was hoping someone could point me in the right direction for what to try next. If there is something available already which does what I want (I want to avoid cookie tracking due to the problems of cookie support, and URI tracking for security reasons - also, as HTTP has an authentication system, I may as well try to use it) that would be great. Alternatively, if someone could suggest a good online tutorial or manual for the mod_perl system or suggest a possible solution to the above error, that would also be great. Lastly, if anyone has tried anything similar (or hasn't) and has any pointers or suggestions for alternative methods, they would be much appreciated.

Any advice would be gratefully received.

Cheers,

Andy.
-- 
Beauty is in the eye of the beholder... Oh, no - it's just an eyelash.

Re: HTTP authentication based sessioning with logout ability

Posted by George Sanderson <ge...@xorgate.com>.
At 06:28 PM 12/19/00 +0000, you wrote:
>Hi there.
>
>I've been trying to write a system to perform authentication using the
www-authenticate (http authenatication) method. However, I need a client
visiting the page and having been authenticated to be able to logout and
have their browser forget the information (or at least be able to force the
browser to re-authenticate within the same browser session).
> 
There are two phases of Apache user authorization, namely, authentication
and authorization.  I think that you need to set a flag when the user
logs-out to force authorization to reject requests and force a new login
(which would then clear the flag on success).   The flag could also be tied
to a timer such that if no request was received after a defined time span,
the flag could be set for that user.  This approach would not require a
cookie.  I have never done this, but it should work.




Re: HTTP authentication based sessioning with logout ability

Posted by Rob Tanner <rt...@cheshire.onlinemac.com>.
I would think that non-persistent cookies would be the ticket.  Certainly dynamic realms would accomplish what you want, but really all your doing is using the realm 
like a cookie.

Cookies have a number of advantages.  For one thing, they're reasonably straight forward to manage.  Secondly, you can encrypt a timestamp on a cookie.  And that's important because WEB users are notoriously bad at remembering to logout.  The value of the timestamp is that it can become an idle timeout mechanism, so even if a user goes away and then comes back later, he or she has been logged out just based on inactivity.

-- Rob


--On Tuesday, December 19, 2000 06:28:16 PM +0000 apache@dairylogic.co.uk wrote:

> Hi there.
>
> I've been trying to write a system to perform authentication using the
> www-authenticate (http authenatication) method. However, I need a client visiting
> the page and having been authenticated to be able to logout and have their
> browser forget the information (or at least be able to force the browser to
> re-authenticate within the same browser session).
>
> As most browsers cache login details (sensibly - you don't want to enter your
> login details for each page you visit) the best system I can think of is to use
> dynamic realms. This would mean that when someone first visits the site, they
> will be given a random/sequential realm. When they then click on a logout button,
> the old realm is discarded, and if the browser tries to authenticate with the
> same realm it is refused (or alternatively the server just starts sending a
> different realm and the browser re-authenticates on the new realm).
> Significantly, the system needs to be accessible by several people
> simultaneously. The purpose is actually to allow someone accessing the site to
> log in, be served dynamic content on the basis of username (which I'm already
> doing), but have the option to log out and then back in as a different user.
>
> I've been looking at different ways to do this, but haven't had any sucess as of
> yet. My first attempt was to use the module mod_auth_external to deal with
> authentication using a perl script (which would allow me to arbitrarily refuse
> login details even if they are correct, on the basis of other details such as
> realm). This is my preferable method (mainly because I understand it), but it
> seems that there's no way to integrate the realm into the auth_external system.
> This means that although I could refuse a username and password, I can't change
> the realm dynamically, and so I can't force the browser to re-authenticate (and
> without the realm information being passed to the script, I don't know if a
> visitor has re-authenticated with the same username or if their browser has
> simply sent the cached copy of the details).
>
> After searching around for methods of dynamically assigning an authname, I
> stumbled across mod_perl. I've never in my life even looked at mod_perl (and I
> don't really understand object-oriented perl, I'm sorry to say - I came from a
> BASIC background - in more ways than one apparently). I also found an example
> script for assigning dynamic realms, but haven't been able to get it to work.
>
> I have only been trying for a day, and I know it's bad of me to resort to a
> mailing list after such a short space of time, but I've trawled the Web for as
> much information as I can find but with no success.
>
> The example mod_perl script I found was as follows:
>
> <From http://www.davin.ottawa.on.ca/archive/modperl/2000-09/msg00839.phtml>
>
> #############################################################################
>
> Here's a simple handler that will set the AuthType and AuthName
> dynamically and handle the authentication for you. This handler will
> prompt you for a password when you try to acess /manual with the
> AuthName, "The Manual" and prompt with the AuthName "The Icons" when you
> try to access /icons. These urls are part of Apaches basic installation
> (that's if you did not remove the manual from your htdocs directory).
> The authentication phase will let you in just as long you supply a
> username and password. You can of course code such that it you can
> authenicate against a .htpassword file, using Apache::Htpasswd.
>
> Anyhow, this should show you that you can indeed change the AuthName
> on-the-fly and also handle
> authentication without having to include AuthName,AuthType,AuthUserFile
> explicitly in your httpd.conf.
>
> Note: the authentication subroutine acted flaky, sometimes it worked and
> other times it didn't. But the realms did change for the each uri.
>
> i hope this helps you....have fun ;)
>
>
> Setting it up:
>
> In your httpd.conf ( in a global area):
>
> PerlHeaderParserHandler Apache::SetRealm;
>
>
> =code
>
> package Apache::SetRealm;
>
> use Apache;
> use Apache::Constants qw(:common);
> sub handler {
>     my $r   = shift;
>
>     ## Make Apache aware the we want to also handle the Authentication
> phase using a custom
>     ## handler, in this case the subroutine authenticate()
>           $r->push_handlers(PerlAuthenHandler => \&authenticate);
>     my $uri = $r->uri;
>
>    ## only handle uri that are defined as protected, in this case the
> only protected
>    ## uri's are /icons and /manuals
>     return OK unless is_protected($r);
>     my $realm = get_realm($r);
>
>     ## Construct the Header Field containing the type of authenticate
> (Basic) and our
>    ## realmname return by get_realm()
>     my $authheader = 'Basic realm="'.$realm.'"';
>
>     $r->header_out("WWW-Authenticate" ,$authheader);
>
>     ## Return 401 to browser and prompt for login
>     $r->status(AUTH_REQUIRED);
>     $r->send_http_header("text/html");
>     return AUTH_REQUIRED;
> }
>
> sub get_realm {
>      ## Get the AuthName for a specific uri. You can probably read these
> off of a file that
>      ## contains a list of uri's and realmNames
>       my $r = shift;
>       return "The Icons"  if ($r->uri =~ /\/icons/);
>       return "The Manual" if ($r->uri =~ /\/manual/);
> }
>
> sub is_protected {
>       ## Check the $uri requested matches our set of "Restricted"
> locations
>      ## 1 = isProtected, 0 = NotProtected
>      ## You can probably have these protected areas in a seperate file,
> the eagle book
>      ## has some excellent ideas on how to acomplish this
>       my $r = shift;
>       my @protected = ('\/manual','\/icons');
>
>       for (@protected) { return 1 if ($r->uri =~ /$_/); }
>       return 0;
> }
>
> sub authenticate {
>       ## Straight out of the Eagle Book
>     my $r = shift;
>
>     return OK if $r->sub_request;
>
>     my ($res,$password) = $r->get_basic_auth_pw;
>     return $res if $res != OK;
>
>     my $username = $r->connection->user;
>     unless ($username && $pass) {
>            $r->note_basic_auth_failure;
>            $r->log_reason("Did not provide username");
>            return AUTH_REQUIRED;
>     }
>
>     ## Now that you have the $username and $password you can
>     ## include your code to open your AuthUserFile to check the password
> and username
>     ## I suggest using Apache::Htpasswd, it provides all the
> methods/functions that you need to
>     ## accomplish this part of the task...
>
>     $r->log_reason("WELCOME $user");
>     return OK;
>
> }
>
> #############################################################################
>
> I've made some minor changes (but the changes all seem to work). The specific
> error I'm getting now is relating to the line:
>
>     return OK if $r->sub_request;
>
> ... in the authenticate subroutine. The error which appears in the apache error
> logs is:
>
>     [Tue Dec 19 17:32:04 2000] [error] Can't locate object method "sub_request"
>     via package "Apache" at
>     /usr/lib/perl5/5.6.0/i386-linux/raxware/AssignRealm.pm line 85.
>
> As I say, I'm new to mod_perl and object-oriented perl, so maybe this is simple
> to solve, but I can't find any online reference to the same error, or any
> reference to the purpose of the method 'sub_request'.
>
>
> Basically I was hoping someone could point me in the right direction for what to
> try next. If there is something available already which does what I want (I want
> to avoid cookie tracking due to the problems of cookie support, and URI tracking
> for security reasons - also, as HTTP has an authentication system, I may as well
> try to use it) that would be great. Alternatively, if someone could suggest a
> good online tutorial or manual for the mod_perl system or suggest a possible
> solution to the above error, that would also be great. Lastly, if anyone has
> tried anything similar (or hasn't) and has any pointers or suggestions for
> alternative methods, they would be much appreciated.
>
> Any advice would be gratefully received.
>
> Cheers,
>
> Andy.
> --
> Beauty is in the eye of the beholder... Oh, no - it's just an eyelash.




       _ _ _ _           _    _ _ _ _ _
      /\_\_\_\_\        /\_\ /\_\_\_\_\_\
     /\/_/_/_/_/       /\/_/ \/_/_/_/_/_/  QUIDQUID LATINE DICTUM SIT,
    /\/_/__\/_/ __    /\/_/    /\/_/          PROFUNDUM VIDITUR
   /\/_/_/_/_/ /\_\  /\/_/    /\/_/
  /\/_/ \/_/  /\/_/_/\/_/    /\/_/         (Whatever is said in Latin
  \/_/  \/_/  \/_/_/_/_/     \/_/              appears profound)

  Rob Tanner
  McMinnville, Oregon
  rtanner@cheshire.onlinemac.com

Re: HTTP authentication based sessioning with logout ability

Posted by Darren Duncan <da...@DarrenDuncan.net>.
I have also been doing problem solving related to session handling and I
will briefly share my ideas for a solution.  What I am about to say is
just the logic or protocol behind my solution without getting into
implementation details.  I don't know if it'll help you, but here goes:

Essentially I had a server-side data store that tracked 4 pieces of
information on a client session for authentication purposes:
1. session code or login name (primary key)
2. the "realm"/cookie that the client got on the last log in
3. the date and time of their last log in or request
4. the IP address (or something) of the client machine when last logged in

The above information is checked each time the client makes a request.  If
any is not acceptible then they are prompted for their user id and
password again.  "acceptible" means that the realm and IP are the same as
before, and that less than a certain amount of time passed since they were
prompted for a password.  If users log out then the "realm" is reset to
nil so that they would have to be prompted on a log-in later.

HTTP authentication can be used to gather the login name and password, or
an html form could be used (greater compatability).  It doesn't
really matter.

The back-end data store also remembered the cumulative effect of whatever
users did during the session, so it doesn't all need to be passed back and
forth by the browser.  So if the web browser crashes or they move to
another computer or their session times out, all they have to do is
answer the new prompt for a username/password and they can continue right
where they left off.  This also means that their short-term workflow is
remembered, so they have the same screen they left with.  The actual
commitment of their changes is only done at certain times, such as when
they request to save changes.  Meanwhile, the actual back-end data isn't
left in a volatile state.

I think that my solution has advantages of convenience, security, data
integrity, compatability and so forth.  Also, web browsers have very
little that they need to remember.  The catch is that users need to have
login ids and passwords, and that their activity is tracked by the server
(at least short term).  But my solution was designed for users who were
registered and approved to edit the database, not anonymous individuals.
Although, this methodology could still be adapted for anonymous uses...

FYI: My requirements were to facilitate a web-accessible resource that
could be edited by multiple registered people at once, and as such, each person
would have their own login name and password.  Fairly standard so far,
right?  But in addition to that, it needed to let them do their work at a
public station or office where the same user could be sitting at several
different computers in one day, and several people could use the same
computer.  Additionally, an editing task could be either simple or quite
involved, meaning that the user may have to abandon their session and
continue where they left off later.  I needed precautions against the
browser crashing or it being left open after the user leaves for others to
see.  Finally, the edited information would be hierarchical, often
requiring multiple screens, as well as going up a path and then returning,
with what they did up the path being remembered.  The same user may even
want to edit several unrelated pieces of information at once, doing first
one, then stopping and doing something else, and then returning to what
they were doing before.

Now, I don't know if any of this has helped you or not, but it certainly
has helped me.

Good days,

// Darren Duncan




Re: HTTP authentication based sessioning with logout ability

Posted by "G.W. Haywood" <ge...@www.jubileegroup.co.uk>.
Hi there,

On Tue, 19 Dec 2000 apache@dairylogic.co.uk wrote:

[Reams and reams of stuff snipped, without apology]

> Basically I was hoping someone could point me in the right direction
> for what to try next.

http://perl.apache.org/guide

[more reams snipped]

> I know it's bad of me to resort to a mailing list after such a short
> space of time,

Yup.

> but I've trawled the Web for as much information as I can find but
with no success.

[final snip]

Try trawling some more on perl.apache.org and maybe CPAN... 

73,
Ged.