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.

Reply via email to