Apache-AuthCookieDBIRadius

 view release on metacpan or  search on metacpan

AuthCookie.pm  view on Meta::CPAN

package Apache::AuthCookie;

use strict;

use Carp;
use CGI::Util ();
use mod_perl qw(1.07 StackedHandlers MethodHandlers Authen Authz);
use Apache::Constants qw(:common M_GET M_POST FORBIDDEN REDIRECT);
use vars qw($VERSION);

# $Id: AuthCookie.pm,v 2.16 2001/06/01 15:50:27 mschout Exp $
$VERSION = '3.00';

sub recognize_user ($$) {
  my ($self, $r) = @_;
  my $debug = $r->dir_config("AuthCookieDebug") || 0;
  my ($auth_type, $auth_name) = ($r->auth_type, $r->auth_name);
  return unless $auth_type && $auth_name;
  return unless $r->header_in('Cookie');

  my ($cookie) = $r->header_in('Cookie') =~ /${auth_type}_${auth_name}=([^;]+)/;
  $r->log_error("cookie ${auth_type}_${auth_name} is $cookie") if $debug >= 2;
  return unless $cookie;

  if (my ($user) = $auth_type->authen_ses_key($r, $cookie)) {
    $r->log_error("user is $user") if $debug >= 2;
    $r->connection->user($user);
  }
  return OK;
}


sub login ($$) {
  my ($self, $r) = @_;
  my $debug = $r->dir_config("AuthCookieDebug") || 0;

  my ($auth_type, $auth_name) = ($r->auth_type, $r->auth_name);
  my %args = $r->method eq 'POST' ? $r->content : $r->args;
  unless (exists $args{'destination'}) {
    $r->log_error("No key 'destination' found in posted data");
    return SERVER_ERROR;
  }
  
  # Get the credentials from the data posted by the client
  my @credentials;

AuthCookie.pm  view on Meta::CPAN

  unless ($r->dir_config("${auth_name}Cache")) {
    $r->no_cache(1);
    $r->err_header_out("Pragma" => "no-cache");
  }
  $r->header_out("Location" => $args{'destination'});
  return REDIRECT;
}

sub logout($$) {
  my ($self,$r) = @_;
  my $debug = $r->dir_config("AuthCookieDebug") || 0;
  
  my ($auth_type, $auth_name) = ($r->auth_type, $r->auth_name);
  
  # Send the Set-Cookie header to expire the auth cookie.
  my $str = $self->cookie_string( request => $r,
											 key     => "$auth_type\_$auth_name",
								          value 	=> '',
											 expires => 'Mon, 21-May-1971 00:00:00 GMT' );
  $r->err_headers_out->add("Set-Cookie" => "$str");
  $r->log_error("set_cookie " . $r->err_header_out("Set-Cookie")) if $debug >= 2;
  unless ($r->dir_config("${auth_name}Cache")) {
    $r->no_cache(1);
    $r->err_header_out("Pragma" => "no-cache");
  }

  #my %args = $r->args;
  #if (exists $args{'redirect'}) {
  #  $r->err_header_out("Location" => $args{'redirect'});
  #  return REDIRECT;
  #} else {
  #  $r->status(200);
  #  return OK;
  #}
}

sub authenticate ($$) {
  my ($auth_type, $r) = @_;
  my ($authen_script, $auth_user);
  my $debug = $r->dir_config("AuthCookieDebug") || 0;
  
  $r->log_error("auth_type " . $auth_type) if ($debug >= 3);
  return OK unless $r->is_initial_req; # Only authenticate the first internal request
  
  if ($r->auth_type ne $auth_type) {
    # This location requires authentication because we are being called,
    # but we don't handle this AuthType.
    $r->log_error("AuthType mismatch: $auth_type =/= ".$r->auth_type) if $debug >= 3;
    return DECLINED;
  }

  # Ok, the AuthType is $auth_type which we handle, what's the authentication
  # realm's name?
  my $auth_name = $r->auth_name;
  $r->log_error("auth_name " . $auth_name) if $debug >= 2;
  unless ($auth_name) {
    $r->log_reason("AuthName not set, AuthType=$auth_type", $r->uri);
    return SERVER_ERROR;
  }

  # Get the Cookie header. If there is a session key for this realm, strip
  # off everything but the value of the cookie.
  my ($ses_key_cookie) = ($r->header_in("Cookie") || "") =~ /$auth_type\_$auth_name=([^;]+)/;
  $ses_key_cookie = "" unless defined($ses_key_cookie);

  $r->log_error("ses_key_cookie " . $ses_key_cookie) if ($debug >= 1);
  $r->log_error("uri " . $r->uri) if ($debug >= 2);

  if ($ses_key_cookie) {
    if ($auth_user = $auth_type->authen_ses_key($r, $ses_key_cookie)) {
      # We have a valid session key, so we return with an OK value.
      # Tell the rest of Apache what the authentication method and
      # user is.

AuthCookie.pm  view on Meta::CPAN

      # There was a session key set, but it's invalid for some reason. So,
      # remove it from the client now so when the credential data is posted
      # we act just like it's a new session starting.
      
      my $str = $auth_type->cookie_string(
		  request => $r,
		  key     => "$auth_type\_$auth_name",
		  value   => '',
		  expires => 'Mon, 21-May-1971 00:00:00 GMT'
		);
      $r->err_headers_out->add("Set-Cookie" => "$str");
      $r->log_error("set_cookie " . $r->err_header_out("Set-Cookie")) if $debug >= 2;
		#$r->subprocess_env('AuthCookieReason', 'Bad Cookie');

		# Instead of 'Bad Cookie', lets return something more useful.
		# $ses_key_cookie has a unique value if ERROR, but undef if ! ERROR.
      $r->subprocess_env('AuthCookieReason', $ses_key_cookie) if $ses_key_cookie =~ /ERROR/;
		$r->subprocess_env('AuthCookieReason', 'ERROR! Your session has expired, or your login does not have the proper access level for this webpage.') if $ses_key_cookie !~ /ERROR/;
    }
  } else {
	 #$r->subprocess_env('AuthCookieReason', 'no_cookie');

	 # Instead of 'no_cookie, let's return something more useful.
    $r->subprocess_env('AuthCookieReason', 'Please enter your user name and password.');
  }

  # They aren't authenticated, and they tried to get a protected
  # document.  Send them the authen form.
  return $auth_type->login_form;
}
  

sub login_form {  
  my $r = Apache->request or die "no request";

AuthCookie.pm  view on Meta::CPAN

    return SERVER_ERROR;
  }
  #$r->log_error("Redirecting to $authen_script");
  $r->custom_response(FORBIDDEN, $authen_script);
  
  return FORBIDDEN;
}

sub authorize ($$) {
  my ($auth_type, $r) = @_;
  my $debug = $r->dir_config("AuthCookieDebug") || 0;
  
  return OK unless $r->is_initial_req; #only the first internal request
  
  if ($r->auth_type ne $auth_type) {
    $r->log_error($auth_type . " auth type is " .
		  $r->auth_type) if ($debug >= 3);
    return DECLINED;
  }
  
  my $reqs_arr = $r->requires or return DECLINED;

AuthCookie.pm  view on Meta::CPAN

    $r->log_error("$auth_type->$requirement returned $ret_val") if $debug >= 3;
    next if $ret_val == OK;

    # Nothing succeeded, deny access to this user.
    $forbidden = 1;
    last;
  }
   #return $forbidden ? FORBIDDEN : OK;

   # Was returning generic Apache FORBIDDEN here.  We want to return to login.pl with error message.
   $r->subprocess_env('AuthCookieReason', 'ERROR! Your login does not have the proper permission for this webpage.') if $forbidden;
 	$r->log_error("AuthCookie, ERROR! Login not in list for this directory using require user ...") if $forbidden;
   return $auth_type->login_form if $forbidden;

   return OK;
}

sub send_cookie {
  my ($self, $ses_key) = @_;
  my $r = Apache->request();

  my ($auth_type, $auth_name) = ($r->auth_type, $r->auth_name);
  my $cookie = $self->cookie_string( request => $r, 
											    key     => "$auth_type\_$auth_name", 
												 value   => $ses_key );
  $r->err_header_out("Set-Cookie" => $cookie);
}

sub cookie_string {
  my $self = shift;

  # if passed 3 args, we have old-style call.
  if (scalar(@_) == 3) {
    carp "deprecated old style call to ".__PACKAGE__."::cookie_string()";
    my ($r, $key, $value) = @_;
    return $self->cookie_string(request=>$r, key=>$key, value=>$value);

AuthCookie.pm  view on Meta::CPAN


  $string .= '; secure' if $r->dir_config("${auth_name}Secure");

  return $string;
}

sub key {
  my $self = shift;
  my $r = Apache->request;

  my $allcook = ($r->header_in("Cookie") || "");
  my ($type, $name) = ($r->auth_type, $r->auth_name);
  return ($allcook =~ /(?:^|\s)${type}_$name=([^;]*)/)[0];
}

1;

__END__

=head1 NAME

Apache::AuthCookie - Perl Authentication and Authorization via cookies

=head1 SYNOPSIS

Make sure your mod_perl is at least 1.24, with StackedHandlers,
MethodHandlers, Authen, and Authz compiled in.

 # In httpd.conf or .htaccess:
 PerlModule Sample::AuthCookieHandler
 PerlSetVar WhatEverPath /
 PerlSetVar WhatEverLoginScript /login.pl
 
 # The following line is optional - it allows you to set the domain
 # scope of your cookie.  Default is the current domain.
 PerlSetVar WhatEverDomain .yourdomain.com

 # Use this to only send over a secure connection
 PerlSetVar WhatEverSecure 1

 # Usually documents are uncached - turn off here
 PerlSetVar WhatEverCache 1

 # Use this to make your cookies persistent (+2 hours here)
 PerlSetVar WhatEverExpires +2h

 # These documents require user to be logged in.
 <Location /protected>
  AuthType Sample::AuthCookieHandler
  AuthName WhatEver
  PerlAuthenHandler Sample::AuthCookieHandler->authenticate
  PerlAuthzHandler Sample::AuthCookieHandler->authorize
  require valid-user
 </Location>

 # These documents don't require logging in, but allow it.
 <FilesMatch "\.ok$">
  AuthType Sample::AuthCookieHandler
  AuthName WhatEver
  PerlFixupHandler Sample::AuthCookieHandler->recognize_user
 </FilesMatch>

 # This is the action of the login.pl script above.
 <Files LOGIN>
  AuthType Sample::AuthCookieHandler
  AuthName WhatEver
  SetHandler perl-script
  PerlHandler Sample::AuthCookieHandler->login
 </Files>

=head1 DESCRIPTION

B<Apache::AuthCookie> allows you to intercept a user's first
unauthenticated access to a protected document. The user will be
presented with a custom form where they can enter authentication
credentials. The credentials are posted to the server where AuthCookie
verifies them and returns a session key.

The session key is returned to the user's browser as a cookie. As a
cookie, the browser will pass the session key on every subsequent
accesses. AuthCookie will verify the session key and re-authenticate
the user.

All you have to do is write a custom module that inherits from
AuthCookie.  Your module is a class which implements two methods:

=over 4

=item C<authen_cred()>

Verify the user-supplied credentials and return a session key.  The
session key can be any string - often you'll use some string
containing username, timeout info, and any other information you need
to determine access to documents, and append a one-way hash of those
values together with some secret key.

=item C<authen_ses_key()>

Verify the session key (previously generated by C<authen_cred()>,
possibly during a previous request) and return the user ID.  This user
ID will be fed to C<$r-E<gt>connection-E<gt>user()> to set Apache's
idea of who's logged in.

=back

By using AuthCookie versus Apache's built-in AuthBasic you can design
your own authentication system.  There are several benefits.

=over 4

=item 1.

The client doesn't *have* to pass the user credentials on every
subsequent access.  If you're using passwords, this means that the
password can be sent on the first request only, and subsequent
requests don't need to send this (potentially sensitive) information.

AuthCookie.pm  view on Meta::CPAN

=item 2.

When you determine that the client should stop using the
credentials/session key, the server can tell the client to delete the
cookie.  Letting users "log out" is a notoriously impossible-to-solve
problem of AuthBasic.

=item 3.

AuthBasic dialog boxes are ugly.  You can design your own HTML login
forms when you use AuthCookie.

=item 4.

You can specify the domain of a cookie using PerlSetVar commands.  For
instance, if your AuthName is C<WhatEver>, you can put the command 

 PerlSetVar WhatEverDomain .yourhost.com

into your server setup file and your access cookies will span all
hosts ending in C<.yourhost.com>.

=back

This is the flow of the authentication handler, less the details of the
redirects. Two REDIRECT's are used to keep the client from displaying
the user's credentials in the Location field. They don't really change
AuthCookie's model, but they do add another round-trip request to the
client.

=for html
<PRE>

 (-----------------------)     +---------------------------------+
 ( Request a protected   )     | AuthCookie sets custom error    |
 ( page, but user hasn't )---->| document and returns            |
 ( authenticated (no     )     | FORBIDDEN. Apache abandons      |      
 ( session key cookie)   )     | current request and creates sub |      
 (-----------------------)     | request for the error document. |<-+
                               | Error document is a script that |  |
                               | generates a form where the user |  |
                 return        | enters authentication           |  |
          ^------------------->| credentials (login & password). |  |
         / \      False        +---------------------------------+  |
        /   \                                   |                   |
       /     \                                  |                   |
      /       \                                 V                   |
     /         \               +---------------------------------+  |
    /   Pass    \              | User's client submits this form |  |
   /   user's    \             | to the LOGIN URL, which calls   |  |
   | credentials |<------------| AuthCookie->login().            |  |
   \     to      /             +---------------------------------+  |
    \authen_cred/                                                   |
     \ function/                                                    |
      \       /                                                     |
       \     /                                                      |
        \   /            +------------------------------------+     |
         \ /   return    | Authen cred returns a session      |  +--+
          V------------->| key which is opaque to AuthCookie.*|  |
                True     +------------------------------------+  |
                                              |                  |
               +--------------------+         |      +---------------+
               |                    |         |      | If we had a   |
               V                    |         V      | cookie, add   |
  +----------------------------+  r |         ^      | a Set-Cookie  |
  | If we didn't have a session|  e |T       / \     | header to     |
  | key cookie, add a          |  t |r      /   \    | override the  |
  | Set-Cookie header with this|  u |u     /     \   | invalid cookie|
  | session key. Client then   |  r |e    /       \  +---------------+
  | returns session key with   |  n |    /  pass   \               ^    
  | sucsesive requests         |    |   /  session  \              |    
  +----------------------------+    |  /   key to    \    return   |
               |                    +-| authen_ses_key|------------+
               V                       \             /     False
  +-----------------------------------+ \           /
  | Tell Apache to set Expires header,|  \         /
  | set user to user ID returned by   |   \       /
  | authen_ses_key, set authentication|    \     /
  | to our type (e.g. AuthCookie).    |     \   /
  +-----------------------------------+      \ /
                                              V
         (---------------------)              ^
         ( Request a protected )              |
         ( page, user has a    )--------------+
         ( session key cookie  )
         (---------------------)


 *  The session key that the client gets can be anything you want.  For

AuthCookie.pm  view on Meta::CPAN


    The only requirement is that the authen_ses_key function that you
    create must be able to determine if this session_key is valid and
    map it back to the originally authenticated user ID.

=for html
</PRE>

=head1 METHODS

C<Apache::AuthCookie> has several methods you should know about.  Here
is the documentation for each. =)

=over 4

=item * authenticate()

This method is one you'll use in a server config file (httpd.conf,
.htaccess, ...) as a PerlAuthenHandler.  If the user provided a
session key in a cookie, the C<authen_ses_key()> method will get
called to check whether the key is valid.  If not, or if there is no

AuthCookie.pm  view on Meta::CPAN


Currently users must satisfy ALL of the C<require> directives.  I have
heard that other Apache modules let the user satisfy ANY of the
C<require> directives.  I don't know which is correct, I haven't found
any Apache docs on the matter.  If you need one behavior or the other,
be careful.  I may change it if I discover that ANY is correct.

=item * authen_cred()

You must define this method yourself in your subclass of
C<Apache::AuthCookie>.  Its job is to create the session key that will
be preserved in the user's cookie.  The arguments passed to it are:

 sub authen_cred ($$\@) {
   my $self = shift;  # Package name (same as AuthName directive)
   my $r    = shift;  # Apache request object
   my @cred = @_;     # Credentials from login form

   ...blah blah blah, create a session key...
   return $session_key;
 }

AuthCookie.pm  view on Meta::CPAN

look at it later and determine the user's username.  You are
responsible for implementing your own session key format.  A typical
format is to make a string that contains the username, an expiration
time, whatever else you need, and an MD5 hash of all that data
together with a secret key.  The hash will ensure that the user
doesn't tamper with the session key.  More info in the Eagle book.

=item * authen_ses_key()

You must define this method yourself in your subclass of
Apache::AuthCookie.  Its job is to look at a session key and determine
whether it is valid.  If so, it returns the username of the
authenticated user.

 sub authen_ses_key ($$$) {
   my ($self, $r, $session_key) = @_;
   ...blah blah blah, check whether $session_key is valid...
   return $ok ? $username : undef;
 }

=item * login()

AuthCookie.pm  view on Meta::CPAN


Third, you must change your login forms (see L<THE LOGIN SCRIPT>
below) to indicate how requests should be redirected after a
successful login.

Fourth, you might want to take advantage of the new C<logout()>
method, though you certainly don't have to.

=head1 EXAMPLE

For an example of how to use Apache::AuthCookie, you may want to check
out the test suite, which runs AuthCookie through a few of its paces.
The documents are located in t/eg/, and you may want to peruse
t/real.t to see the generated httpd.conf file (at the bottom of
real.t) and check out what requests it's making of the server (at the
top of real.t).

=head1 THE LOGIN SCRIPT

You will need to create a login script (called login.pl above) that
generates an HTML form for the user to fill out.  You might generate
the page using an Apache::Registry script, or an HTML::Mason

AuthCookie.pm  view on Meta::CPAN


=item 2.

The various user input fields (username, passwords, etc.) must be
named 'credential_0', 'credential_1', etc. on the form.  These will
get passed to your authen_cred() method.

=item 3.

You must define a form field called 'destination' that tells
AuthCookie where to redirect the request after successfully logging
in.  Typically this value is obtained from C<$r-E<gt>prev-E<gt>uri>.
See the login.pl script in t/eg/.

=back

In addition, you might want your login page to be able to tell the
difference between a user that sent an incorrect auth cookie, and a
user that sent no auth cookie at all.  These typically correspond,
respectively, to users who logged in incorrectly or aren't allowed to
access the given page, and users who are trying to log in for the
first time.  To help you differentiate between the two, B<AuthCookie>
will set C<$r-E<gt>subprocess_env('AuthCookieReason')> to either
C<bad_cookie> or C<no_cookie>.  You can examine this value in your
login form by examining
C<$r-E<gt>prev-E<gt>subprocess_env('AuthCookieReason')> (because it's
a sub-request).

Of course, if you want to give more specific information about why
access failed when a cookie is present, your C<authen_ses_key()>
method can set arbitrary entries in C<$r-E<gt>subprocess_env>.

=head1 THE LOGOUT SCRIPT

If you want to let users log themselves out (something that can't be
done using Basic Auth), you need to create a logout script.  For an
example, see t/eg/logout.pl.  Logout scripts may want to take
advantage of AuthCookie's C<logout()> method, which will set the
proper cookie headers in order to clear the user's cookie.  This
usually looks like C<$r-E<gt>auth_type-E<gt>logout($r);>.

Note that if you don't necessarily trust your users, you can't count
on cookie deletion for logging out.  You'll have to expire some
server-side login information too.  AuthCookie doesn't do this for
you, you have to handle it yourself.

=head1 ABOUT SESSION KEYS

Unlike the sample AuthCookieHandler, you have you verify the user's
login and password in C<authen_cred()>, then you do something
like:

    my $date = localtime;
    my $ses_key = MD5->hexhash(join(';', $date, $PID, $PAC));

save C<$ses_key> along with the user's login, and return C<$ses_key>.

Now C<authen_ses_key()> looks up the C<$ses_key> passed to it and
returns the saved login.  I use Oracle to store the session key and

AuthCookie.pm  view on Meta::CPAN


It might be nice if the logout method could accept some parameters
that could make it easy to redirect the user to another URI, or
whatever.  I'd have to think about the options needed before I
implement anything, though.

=back

=head1 CVS REVISION

$Id: AuthCookie.pm,v 2.16 2001/06/01 15:50:27 mschout Exp $

=head1 AUTHOR

Michael Schout <mschout@gkg.net>

Originally written by Eric Bartley <bartley@purdue.edu>

versions 2.x were written by Ken Williams <ken@forum.swarthmore.edu>

=head1 SEE ALSO

AuthCookieDBIRadius.pm  view on Meta::CPAN

#===============================================================================
#
# Apache::AuthCookieDBIRadius
#
# An AuthCookie module backed by a DBI database, then to a Radius server.
#
# Copyright (C) 1999 SF Interactive, Inc.  All rights reserved.
#
# Author:  Charles Day <chaday@s1te.com>
# Original Author:  Jacob Davies <jacob@sfinteractive.com> <jacob@well.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# 
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# $Id: AuthCookieDBIRadius.pm,v 1.19 2001/11/14 12:07:01 barracode Exp $
#
#===============================================================================

package Apache::AuthCookieDBIRadius;

use strict;
use 5.004;
use vars qw( $VERSION );

# $Id: AuthCookieDBIRadius.pm,v 1.19 2001/11/14 12:07:01 barracode Exp $
$VERSION = '1.19';

use Apache::AuthCookie;
use vars qw( @ISA );
@ISA = qw( Apache::AuthCookie );

use Apache;
use Apache::DBI;
use Apache::Constants;
use Apache::File;
use Digest::MD5 qw( md5_hex );
use Date::Calc qw( Today_and_Now Add_Delta_DHMS );
# Also uses Crypt::CBC if you're using encrypted cookies.

# Added IPC::ShareLite.

AuthCookieDBIRadius.pm  view on Meta::CPAN

# P R I V A T E   F U N C T I O N S
#===============================================================================

#-------------------------------------------------------------------------------
# _log_not_set -- Log that a particular authentication variable was not set.

sub _log_not_set($$)
{
	my( $r, $variable ) = @_;
	my $auth_name = $r->auth_name;
	$r->log_error( "Apache::AuthCookieDBIRadius: $variable not set for auth realm
$auth_name", $r->uri );
}

#-------------------------------------------------------------------------------
# _dir_config_var -- Get a particular authentication variable.

sub _dir_config_var($$)
{
	my( $r, $variable ) = @_;
	my $auth_name = $r->auth_name;

AuthCookieDBIRadius.pm  view on Meta::CPAN

	$c{ DBI_encryptiontype } = _dir_config_var( $r, 'DBI_EncryptionType' ) || 'none';

	# If we used encryption we need to pull in Crypt::CBC.
	if ( $c{ DBI_encryptiontype } ne 'none' ) 
	{
		require Crypt::CBC;
	}

	#<WhatEverDBI_SessionLifetime>
	#How long tickets are good for after being issued.  Note that presently
	#Apache::AuthCookie does not set a client-side expire time, which means that
	#most clients will only keep the cookie until the user quits the browser.
	#However, if you wish to force people to log in again sooner than that, set
	#this value.  This can be 'forever' or a life time specified as:
	#DD-hh-mm-ss -- Days, hours, minute and seconds to live.
	#This is not required and defaults to '00-12-00-00' or 12 hours.
	$c{ DBI_sessionlifetime } = _dir_config_var( $r, 'DBI_SessionLifetime' ) || '00-12-00-00';

	# Custom variables from httpd.conf.
	$c{ DBI_a }    			  = _dir_config_var( $r, 'DBI_a' ) || 'off';
	$c{ DBI_b }     			  = _dir_config_var( $r, 'DBI_b' ) || 'off';

AuthCookieDBIRadius.pm  view on Meta::CPAN

sub authen_cred($$\@)
{
	my( $self, $r, @credentials ) = @_;

	my $auth_name = $r->auth_name;

	# Username goes in credential_0
	my $user = $credentials[ 0 ];
	unless ( $user =~ /^.+$/ ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: no username supplied for auth realm $auth_name", $r->uri );
	   return 'ERROR! No Username Supplied';
		#return 'bad';
	}
	# Password goes in credential_1
	my $password = $credentials[ 1 ];

	# create $temp for error messages.
	my $temp = $password;
    
	unless ( $password =~ /^.+$/ ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: no password supplied for auth realm $auth_name", $r->uri );
	   return 'ERROR! No Password Supplied';
		#return 'bad';
	}

	# get the configuration information.
	my %c = _dbi_config_vars $r;

  	# Lock out after 5 failed consecutive attempts. Unlock when the next IP comes in.
   my $attempts = 1;
   my @split = ();
   my $share = new IPC::ShareLite(  -key     => 'AuthCookie',
                                    -create  => 'yes',
                                    -destroy => 'no',
                                    -size    => 25 );

   # Retrieve value from memory.
   my $result = $share->fetch;
   if ($result =~ $ENV{REMOTE_ADDR})
   {
      @split = split(/\:/,$result);
      $attempts = $split[1]+1;
      if ($split[1] > 5)
      {
         $r->log_reason( "Apache::AuthCookieDBIRadius: Security Error!  Too many attempts to auth realm $auth_name", $r->uri );
         return "ERROR! Security error.  Too many attempts.";
      }
   }
   # Store new value.
   $result = $share->store("$ENV{REMOTE_ADDR}:$attempts");

	# Look up user in database.
	my $dbh = DBI->connect( $c{ DBI_DSN },
	                        $c{ DBI_user }, $c{ DBI_password } );
	unless ( defined $dbh ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: couldn't connect to $c{ DBI_DSN } for auth realm $auth_name", $r->uri );
		return 'ERROR! Internal Server Error (111).  Please contact us immediately so we can fix this problem.';
		#return 'bad';
	}
	my $cmd = "SELECT $c{DBI_passwordfield},activeuser,a,b,c,d,e,f,g FROM $c{DBI_userstable} WHERE $c{DBI_userfield} = @{[ $dbh->quote($user) ]}";

	$result = $dbh->prepare($cmd);
	$result->execute;

	my @row = $result->fetchrow_array;

	# debug line.
	#$r->log_reason( "Apache::AuthCookieDBIRadius:  results from database query: row = @row for user $user for auth realm $auth_name", $r->uri );

	my $crypted_password = $row[0];
	my $activeuser = $row[1];
	my $a = $row[2];
	my $b = $row[3];
	my $c = $row[4];
	my $d = $row[5];
	my $e = $row[6];
	my $f = $row[7];
	my $g = $row[8];

	#unless ( defined $crypted_password ) 
	if ( !$crypted_password )
	{
		## Not in DBI database, let's try Radius.
		#$r->log_reason( "Apache::AuthCookieDBIRadius: couldn't select password from $c{DBI_DSN}, $c{DBI_userstable}, $c{DBI_userfield} for user $user for auth realm $auth_name, lets try Radius", $r->uri );
		#
      ## Create the radius connection.
      #my $radius = Authen::Radius->new(
      #         Host => "$c{ DBI_Radius_host }:$c{ DBI_Radius_port }",
      #         Secret => $c{ DBI_Radius_secret },
      #         TimeOut => $c{ DBI_Radius_timeout });
		#
      ## Error if we can't connect.
      #if (!defined $radius)
      #{
      #   $r->log_reason("Apache::AuthCookieDBIRadius: failed to connect to Radius host $c{ DBI_Radius_host }, Radius port $c{ DBI_Radius_port }", $r->uri );
		#	return 'ERROR! Internal Server Error (222).  Please contact us immediately so we can fix this problem.';
      #   #return 'bad';
      #}
      ## Do the actual check.
      #if ($radius->check_pwd($user,$password))
      #{
		#	# Passed.
      #   $r->log_reason("Apache::AuthCookieDBIRadius: User $user in Radius and password matches", $r->uri);
		#
		#	# Must be an employee, give them everything.
		#	$activeuser = 'y';
		#	$a = 'y';
		#	$b = 'y';
		#	$c = 'y';
		#	$d = 'y';
		#	$e = 'y';
		#	$f = 'y';
		#  $g = 'y';
      #}
      #else
      #{
			# Radius failed, return to login page.
         $r->log_reason("Apache::AuthCookieDBIRadius Radius authentication failed for user $user and password $password", $r->uri);
			return 'ERROR! Authentication Failure.';
         #return 'bad';
      #}
	}

	else
	{
		# Return unless the passwords match.
		if ( lc $c{ DBI_crypttype } eq 'none' ) 
		{
			unless ( $password eq $crypted_password ) 
			{
				$r->log_reason( "Apache::AuthCookieDBIRadius: plaintext passwords didn't match for user $user, password = $password, crypted_password = $crypted_password for auth realm $auth_name", $r->uri );
				return 'ERROR! Password did not match.';
				#return 'bad';
			}
		} 
		elsif ( lc $c{ DBI_crypttype } eq 'crypt' ) 
		{
			my $salt = substr $crypted_password, 0, 2;
			unless ( crypt( $password, $salt ) eq $crypted_password ) 
			{
				$r->log_reason( "Apache::AuthCookieDBIRadius: crypted passwords didn't match for user $user, password supplied = $temp for auth realm $auth_name", $r->uri );
				return 'ERROR! Password did not match.';
				#return 'bad';
			}
		} 
		elsif ( lc $c{ DBI_crypttype } eq 'md5' ) 
		{
			unless ( md5_hex( $password ) eq $crypted_password ) 
			{
				$r->log_reason( "Apache::AuthCookieDBIRadius: MD5 passwords didn't match for user $user for auth realm $auth_name", $r->uri );
				return 'ERROR! Password did not match.';
				#return 'bad';
			}
		}
	}

	# Create the expire time for the ticket.
	my $expire_time;
	# expire time in a zillion years if it's forever.
	if ( lc $c{ DBI_sessionlifetime } eq 'forever' ) {

AuthCookieDBIRadius.pm  view on Meta::CPAN


	#my $public_part = "$enc_user:$current_time:$expire_time";
   my $public_part = "$enc_user:$current_time:$expire_time:$activeuser:$a:$b:$c:$d:$e:$f:$g";

	# Now we calculate the hash of this and the secret key and then
	# calculate the hash of *that* and the secret key again.
	my $secret_key = $SECRET_KEYS{ $auth_name };

	unless ( defined $secret_key ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: didn't have the secret key for auth realm $auth_name", $r->uri );
		return 'ERROR! Internal Server Error (333).  Please contact us immediately so we can fix this problem.';
		#return 'bad';
	}
	my $hash = md5_hex( join ':', $secret_key, md5_hex(
		join ':', $public_part, $secret_key
	) );

	# Now we add this hash to the end of the public part.
	my $session_key = "$public_part:$hash";

AuthCookieDBIRadius.pm  view on Meta::CPAN

		}->encrypt_hex( $session_key );
	}

	# update log_field field.
   if ($c{ DBI_log_field })
   {
	   my $cmd = "UPDATE $c{DBI_userstable} SET $c{DBI_log_field} = 'NOW' WHERE $c{DBI_userfield} = \'$user\';";

      unless ($dbh->do($cmd))
      {
         $r->log_reason("Apache::AuthCookieDBIRadius: can not update $c{DBI_log_field}: $DBI::errstr: cmd=$cmd", $r->uri);
         $dbh->disconnect;
         return SERVER_ERROR;
      }
      $dbh->disconnect;
   }

	return $encrypted_session_key;
}


AuthCookieDBIRadius.pm  view on Meta::CPAN


	my $auth_name = $r->auth_name;

	# Get the configuration information.
	my %c = _dbi_config_vars $r;

	# Get the secret key.
	my $secret_key = $SECRET_KEYS{ $auth_name };

	unless ( defined $secret_key ) {
		$r->log_reason( "Apache::AuthCookieDBIRadius: didn't the secret key from for auth realm $auth_name", $r->uri );
		return undef;
	}
	
	# Decrypt the session key.
	my $session_key;
	if ( $c{ DBI_encryptiontype } eq 'none' ) 
	{
		$session_key = $encrypted_session_key;
	} 
	else 
	{
		# Check that this looks like an encrypted hex-encoded string.
		unless ( $encrypted_session_key =~ /^[0-9a-fA-F]+$/ ) 
		{
			$r->log_reason( "Apache::AuthCookieDBIRadius: encrypted session key $encrypted_session_key doesn't look like it's properly hex-encoded for auth realm $auth_name", $r->uri );
			return undef;
		}

		# Get the cipher from the cache, or create a new one if the
		# cached cipher hasn't been created, & decrypt the session key.
		my $cipher;
		if ( lc $c{ DBI_encryptiontype } eq 'des' ) {
			$cipher = $CIPHERS{ "des:$auth_name" }
			   ||= Crypt::CBC->new( $secret_key, 'DES' );
		} elsif ( lc $c{ DBI_encryptiontype } eq 'idea' ) {
			$cipher = $CIPHERS{ "idea:$auth_name" }
			   ||= Crypt::CBC->new( $secret_key, 'IDEA' );
		} elsif ( lc $c{ DBI_encryptiontype } eq 'blowfish' ) {
			$cipher = $CIPHERS{ "blowfish:$auth_name" }
			   ||= Crypt::CBC->new( $secret_key, 'Blowfish' );
		} elsif ( lc $c{ DBI_encryptiontype } eq 'blowfish_pp' ) {
			$cipher = $CIPHERS{ "blowfish_pp:$auth_name" }
			   ||= Crypt::CBC->new( $secret_key, 'Blowfish_PP' );
		} else {
			$r->log_reason( "Apache::AuthCookieDBIRadius: unknown encryption type $c{ DBI_encryptiontype } for auth realm $auth_name", $r->uri );
			return undef;
		}
		$session_key = $cipher->decrypt_hex( $encrypted_session_key );
	}
	
	# Break up the session key.
   my( $enc_user,$issue_time,$expire_time,$activeuser,$a,$b,$c,$d,$e,$f,$g,$supplied_hash )
	   = split /:/, $session_key;
	# Let's check that we got passed sensible values in the cookie.
	unless ( $enc_user =~ /^[a-zA-Z0-9_\%]+$/ ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: bad percent-encoded user $enc_user recovered from session ticket for auth_realm $auth_name", $r->uri );
		return undef;
	}

	# decode the user
	my $user = _percent_decode $enc_user;
	unless ( $issue_time =~ /^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$/ ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: bad issue time $issue_time recovered from ticket for user $user for auth_realm $auth_name", $r->uri );
		return undef;
	}
	unless ( $expire_time =~ /^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$/ ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: bad expire time $expire_time recovered from ticket for user $user for auth_realm $auth_name", $r->uri );
		return undef;
	}
	unless ( $supplied_hash =~ /^[0-9a-fA-F]{32}$/ ) 
	{
		$r->log_reason( "Apache::AuthCookieDBIRadius: bad hash $supplied_hash recovered from ticket for user $user for auth_realm $auth_name", $r->uri );
		return undef;
	}

	# Calculate the hash of the user, issue time, expire_time and
	# the secret key and then the hash of that and the secret key again.
	my $hash = md5_hex( join ':', $secret_key, md5_hex(
      join ':', $enc_user,$issue_time,$expire_time,$activeuser,$a,$b,$c,$d,$e,$f,$g,$secret_key
	) );

	# Compare it to the hash they gave us.
	unless ( $hash eq $supplied_hash ) {
		$r->log_reason( "Apache::AuthCookieDBIRadius: hash in cookie did not match calculated hash of contents for user $user for auth realm $auth_name", $r->uri );
		return undef;
	}

	# Check that their session hasn't timed out.
	if ( _now_year_month_day_hour_minute_second gt $expire_time ) 
	{
		$r->log_reason( "Apache:AuthCookieDBIRadius: expire time $expire_time has passed for user $user for auth realm $auth_name", $r->uri );
		return undef;
	}

	# If we're being paranoid about timing-out long-lived sessions,
	# check that the issue time + the current (server-set) session lifetime
	# hasn't passed too (in case we issued long-lived session tickets
	# in the past that we want to get rid of). *** DEBUG ***
	# if ( lc $c{ DBI_AlwaysUseCurrentSessionLifetime } eq 'on' ) {

	# check the directory to see if user has correct permissions here.
 	$auth_name = $r->auth_name;

   # Get the configuration information.
   %c = _dbi_config_vars $r;

   # a
   if ($c{DBI_a} eq "on" && $a ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_a = on but a <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }
   # b
   if ($c{DBI_b} eq "on" && $b ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_b = on but b <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }
   # c
   if ($c{DBI_c} eq "on" && $c ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_c = on but c <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }
   # d
   if ($c{DBI_d} eq "on" && $d ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_d = on but d <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }
   # e
   if ($c{DBI_e} eq "on" && $e ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_e = on but e <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }
   # f
   if ($c{DBI_f} eq "on" && $f ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_f = on but f <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }
   # g
   if ($c{DBI_g} eq "on" && $g ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_g = on but g <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }
  	# activeuser
   if ($c{DBI_activeuser} eq "on" && $activeuser ne 'y')
   {
      $r->log_reason( "Apache::AuthCookieDBIRadius: DBI_activeuser = on but activeuser <> y for user $user for auth realm $auth_name", $r->uri);
      return undef;
   }

	# They must be okay, so return the user.
	$r->subprocess_env('TICKET', $user);

	return $user;
}

#-------------------------------------------------------------------------------

AuthCookieDBIRadius.pm  view on Meta::CPAN


	# Get the configuration information.
	my %c = _dbi_config_vars $r;

	my $user = $r->connection->user;

	# See if we have a row in the groups table for this user/group.
	my $dbh = DBI->connect( $c{ DBI_DSN },
	                        $c{ DBI_user }, $c{ DBI_password } );
	unless ( defined $dbh ) {
		$r->log_reason( "Apache::AuthCookieDBIRadius: couldn't connect to $c{ DBI_DSN } for auth realm $auth_name", $r->uri );
		return undef;
	}

	# Now loop through all the groups to see if we're a member of any:
	my $result = $dbh->prepare( <<"EOS" );
SELECT $c{ DBI_groupuserfield }
FROM $c{ DBI_groupstable }
WHERE $c{ DBI_groupfield } = ?
AND $c{ DBI_groupuserfield } = ?
EOS
	foreach my $group ( @groups ) {
		$result->execute( $group, $user );
		return OK if ( $result->fetchrow_array );
	}
	$r->log_reason( "Apache::AuthCookieDBIRadius: user $user was not a member of any of the required groups @groups for auth realm $auth_name", $r->uri );
	return FORBIDDEN;
}

1;

__END__

=head1 NAME

   Apache::AuthCookieDBIRadius - An AuthCookie module backed by a DBI database, and an optional Radius server.

=head1 SYNOPSIS

   # In httpd.conf or .htaccess

	############################################
	#     AuthCookie                           #
	#                                          #
	# PortalDBI_CryptType                      #
	# PortalDBI_GroupsTable                    #
	# PortalDBI_GroupField                     #
	# PortalDBI_GroupUserField                 #
	# PortalDBI_EncryptionType none|crypt|md5  #
	# PortalDBI_a on|off                       #
	# PortalDBI_b on|off                       #
	# PortalDBI_c on|off                       #
	# PortalDBI_d on|off                       #
	# PortalDBI_e on|off                       #
	# PortalDBI_f on|off                       #
	# PortalDBI_g on|off                       #
	# PortalDBI_useracct on|off                #
	# PortalDBI_log_field last_access          #
	# PortalDBI_Radius_host none               #
	# PortalDBI_Radius_port 1645               #
	# PortalDBI_Radius_secret none             #
	# PortalDBI_Radius_timeout 45              #
	# AuthCookieDebug 0,1,2,3                  #
	# PortalDomain .yourdomain.com             #
	#                                          #
	############################################

	# key line must come first
	PerlSetVar PortalDBI_SecretKeyFile /usr/local/apache/conf/site.key

	PerlModule Apache::AuthCookieDBIRadius
	PerlSetVar PortalPath /
	PerlSetVar PortalLoginScript /login.pl
	PerlSetVar AuthCookieDebug 1
	PerlSetVar PortalDBI_DSN 'dbi:Pg:host=localhost port=5432 dbname=mydatabase'
	PerlSetVar PortalDBI_User "database_user"
	PerlSetVar PortalDBI_Password "database_password"
	PerlSetVar PortalDBI_UsersTable "users"
	PerlSetVar PortalDBI_UserField "userid"
	PerlSetVar PortalDBI_PasswordField "password"
	PerlSetVar PortalDBI_SessionLifeTime 00-24-00-00

	<FilesMatch "\.pl">
 	 AuthType Apache::AuthCookieDBIRadius
 	 AuthName Portal
 	 SetHandler perl-script
 	 PerlHandler Apache::Registry
 	 Options +ExecCGI
	</FilesMatch>

	# login.pl
	<Files LOGIN>
 	 AuthType Apache::AuthCookieDBIRadius
 	 AuthName Portal
 	 SetHandler perl-script
 	 PerlHandler Apache::AuthCookieDBIRadius->login
	</Files>

	#######################################
	#                                     #
	# Begin websites                      #
	#                                     #
	#######################################

	# private
	<Directory /home/httpd/html/private>
 	 AuthType Apache::AuthCookieDBIRadius
 	 AuthName Portal
 	 PerlSetVar PortalDBI_b on
 	 PerlAuthenHandler Apache::AuthCookieDBIRadius->authenticate
 	 PerlAuthzHandler Apache::AuthCookieDBIRadius->authorize
 	 require valid-user
	</Directory>

	# calendar
	<Directory /home/httpd/html/calendar>
 	 AuthType Apache::AuthCookieDBIRadius
 	 AuthName Portal
  	 PerlSetVar PortalDBI_a on
 	 PerlAuthenHandler Apache::AuthCookieDBIRadius->authenticate
 	 PerlAuthzHandler Apache::AuthCookieDBIRadius->authorize
 	 require valid-user
	</Directory>


=head1 DESCRIPTION

This module is an authentication handler that uses the basic mechanism provided
by Apache::AuthCookie with a DBI database for ticket-based protection.  It
is based on two tokens being provided, a username and password, which can
be any strings (there are no illegal characters for either).  The username is
used to set the remote user as if Basic Authentication was used.

On an attempt to access a protected location without a valid cookie being
provided, the module prints an HTML login form (produced by a CGI or any
other handler; this can be a static file if you want to always send people
to the same entry page when they log in).  This login form has fields for
username and password.  On submitting it, the username and password are looked
up in the DBI database.  The supplied password is checked against the password

AuthCookieDBIRadius.pm  view on Meta::CPAN


=head1 APACHE CONFIGURATION DIRECTIVES

All configuration directives for this module are passed in PerlSetVars.  These
PerlSetVars must begin with the AuthName that you are describing, so if your
AuthName is PrivateBankingSystem they will look like:

	PerlSetVar PrivateBankingSystemDBI_DSN "DBI:mysql:database=banking"

See also L<Apache::Authcookie> for the directives required for any kind
of Apache::AuthCookie-based authentication system.

In the following descriptions, replace "WhatEver" with your particular
AuthName.  The available configuration directives are as follows:

=over 4

=item C<WhatEverDBI_DSN>

Specifies the DSN for DBI for the database you wish to connect to retrieve
user information.  This is required and has no default value.

AuthCookieDBIRadius.pm  view on Meta::CPAN

in the ticket we give them.  This is almost completely useless, so don't
switch it on unless you really know you need it.  It does not provide any
protection of the password in transport; use SSL for that.  It can be 'none',
'des', 'idea', 'blowfish', or 'blowfish_pp'.

This is not required and defaults to 'none'.

=item C<WhatEverDBI_SessionLifetime>

How long tickets are good for after being issued.  Note that presently
Apache::AuthCookie does not set a client-side expire time, which means that
most clients will only keep the cookie until the user quits the browser.
However, if you wish to force people to log in again sooner than that, set
this value.  This can be 'forever' or a life time specified as:

	DD-hh-mm-ss -- Days, hours, minute and seconds to live.

This is not required and defaults to '00-24-00-00' or 24 hours.

=back

AuthCookieDBIRadius.pm  view on Meta::CPAN

Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

=head1 AUTHOR

Author: Charles Day <BarracodE@s1te.com>
Original Author: Jacob Davies <jacob@sfinteractive.com> <jacob@well.com>


=head1 SEE ALSO

Apache::AuthCookie(1)
Apache::AuthCookieDBI(1)

=cut

ChangeLog  view on Meta::CPAN

Revision history for Perl extension Apache::AuthCookieDBI.

0.01  Mon Apr  3 10:50:32 2000
	- original version; created by h2xs 1.19

1.18	Tue May 15 11:23:22 2001	 	
	- rewritten from Apache::AuthCookieDBI 1.18

1.19 	Wed Nov 14 12:06:03 2001
	- Updated README
	- Updated perldoc Apache::AuthCookieDBIRadius
	- UNIVERSIAL::AUTOLOAD was complaining about earlier declarations.

MANIFEST  view on Meta::CPAN

AuthCookieDBIRadius.pm
ChangeLog
MANIFEST
README
LICENSE
Makefile.PL
test.pl
generic_reg_auth_scheme.txt
techspec.txt
schema.sql
eg/html/login.html

Makefile.PL  view on Meta::CPAN

use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
    'NAME'	=> 'Apache::AuthCookieDBIRadius',
    'VERSION_FROM' => 'AuthCookieDBIRadius.pm', # finds $VERSION
);

README  view on Meta::CPAN

DESCRIPTION

	Apache::AuthCookieDBIRadius is a module that subclasses Apache::AuthCookie 
	and is designed to be directly used for authentication in a mod_perl 
	server.

	It allows you to authenticate against a DBI database -OR- your trusted NT domains
	via a Radius server using a login webpage via AuthCookie.  

	It is a ticket-issuing system that looks up username/passwords in a DBI
	database using generic SQL and issues MD5-checksummed tickets valid for
	a configurable time period.  Incoming requests with tickets are
	checksummed and expire-time checked.

	Upon failure, it then checks a Radius server for authentication.
	(You do not need to run a Radius server to use this.  Actually, 
	Radius authentication is commented out by default.  Uncomment the
	Radius lines in AuthCookieDBIRadius.pm if you intend to use this method
	along with a DBI database.  Most won't be using this method.  You'll need to 
	get Radius authentication working first before using AuthCookieDBIRadius.
	See Apache-AuthenRadius, Authen::Radius and http://www.funk.com/radius/.)

	Included is a sample httpd.conf and login.pl for your review. 


AUTHCOOKIE

	Also included is a slightly customized AuthCookie.pm based on AuthCookie 3.0.  
	Replace with your existing AuthCookie.pm for added customized error messages:

	# Please enter your username and password (default message).

	# Incorrect Password.

	# Incorrect Username (although some say this isn't a good idea, it can 
	  be easily changed to Incorrect Login for the password and username).

	# ERROR! Your session has expired, or your login does not have the proper 
	  access level for this webpage.

README  view on Meta::CPAN

   # 9 = f
	# 10 = g
   # 10 = key

	Now you can issue content based on the users access level.



DEMO

	AuthCookieDBIRadius is currently in production at http://www.s1te.com/secure/. 



SEE ALSO

	perldoc Apache::AuthCookieDBIRadius
	Apache::AuthCookie
	Apache::AuthCookieDBI

eg/public-pl/login.pl  view on Meta::CPAN


my $t = new Text::TagTemplate;
my $r = Apache->request();

my $destination;
my $authcookiereason;
if ( $r->prev() ) { # we are called as a subrequest.
	$destination = $r->prev()->args()
	             ? $r->prev()->uri() . '?' .  $r->prev->args()
	             : $r->prev()->uri();
	$authcookiereason = $r->prev()->subprocess_env( 'AuthCookieReason' );
} else {
	$destination = $r->args( 'destination' );
	$authcookiereason = $r->args( 'AuthCookieReason' );
}
$t->add_tag( DESTINATION => $destination );

unless ( $authcookiereason eq 'bad_cookie' ) {
	$t->template_file( "../html/login.html" );
} else {
	$t->template_file( "../html/login-failed.html" );
}

$r->send_http_header;

generic_reg_auth_scheme.txt  view on Meta::CPAN


Must be installable and configurable by someone with only basic Perl and
Apache skills. E.g. only slightly more involved than setting up BasicAuth
and writing a simple CGI program.

Jacob>  This could be accomplished by making a little script to install
        the necessary CGI scripts and stuff.

Configuration features:
In global section of virtualhost:
	PerlModule Apache::AuthCookieDBI
	PerlSetVar AuthNamePath /

	# this login script must use another cookie to set the destination
	# and we probably need to hack authcookie to look at the cookie
	# too.  the action should be /LOGIN.  the alternative is to always
	# make the login scripts look at the cookie if they don't get it in
	# the hidden field, which is probably right.
	PerlSetVar AuthNameLoginScript /cgi-bin/ACD/login

	# don't know if this is worth implementing, need to re-authenticate
	# and regenerate the token with every hit (or maybe we can just trust
	# the previous one and just update the expire time and rebuild
	# the MD5 checksum; probably requires hacks to AuthCookie either way).
	PerlSetVar AuthNameCookieExpirePolicy [ renew | time-to-live ]

	# or we could do it on the server side by updating a last-visit
	# table with every hit (ouch).  if we don't have this we use the time
	# in the cookie'd info, if we do have this we use that ticket as a key
	# into this database to see when their last hit was.
	PerlSetVar AuthNameDBI_SessionTable tablename
	# do we need more stuff on the field names and blah blah?

	# this determines how long the cookie is good for (ie how long
	# after the MD5'd date in the cookie (or the last entry in the session
	# database if we use one) we still take it)
 	PerlSetVar AuthNameDBI_SessionLifetime [ forever | time-to-live ]
	# time-to-live is formatted as a time delta:
	# 01-00-00-00-00 - 1 day.
	# 00-01-00-00-00 - 1 hour.
	# 00-00-15-00-00 - 15 minute

	# this is probably set by AuthCookie somewhere.
	PerlSetVar AuthNameCookieName name-of-cookie

	# this is the key we use in the MD5'd checksum.  root should change
	# this every day because it has to be nobody-readable and is therefore
	# not all that secure.
	PerlSetVar AuthNameDBI_SecretKeyfile /path/to/secret/key

In <Directory> or <Location> sections (server config or .htaccess):
	AuthType Apache::AuthCookieDBI
	# set this to whatever, but the PerlSetVar's must match it.
	AuthName AuthName
	PerlAuthenHandler Apache::AuthCookieDBI->authenticate
	PerlAuthzHandler Apache::AuthCookieDBI->authorize
	Require [ valid-user, user username, group groupname ]

	# you must set this.
	PerlSetVar AuthNameDBI_DSN databasename

	# all these are optional.
	PerlSetVar AuthNameDBI_User username # default undef
	PerlSetVar AuthNameDBI_Password password # default undef
	PerlSetVar AuthNameDBI_UsersTable tablename # default 'users'
	PerlSetVar AuthNameDBI_UserField fieldname # default 'user'

generic_reg_auth_scheme.txt  view on Meta::CPAN


	# dunno what this is.
	DefaultTarget  partial or full URL

You also need this to get people to log in (although I'm not exactly sure
why; I guess it's so that login() gets called, but why can't we check for
credentials and log them in at the same point that we redirect them off to
the login form?):

	<Location /LOGIN>
		AuthType Apache::AuthCookieDBI
		AuthName AuthName
		SetHandler perl-script
		PerlHandler Apache::AuthCookieDBI->login
	</Location>

Save TARGET Check requirements Send page that is appropriate.
Possibly clear TARGET.

Group Table
+---------------------+
| group    | username |
+---------------------+
| group_1  | matisse  |

httpd.conf  view on Meta::CPAN

##
## httpd.conf -- Apache HTTP server configuration file
##


############################################
#     AuthCookie                           #
#                                          #
# PortalDBI_CryptType                      #
# PortalDBI_GroupsTable                    #
# PortalDBI_GroupField                     #
# PortalDBI_GroupUserField                 #
# PortalDBI_EncryptionType none|crypt|md5  #
# PortalDBI_a on|off                       #
# PortalDBI_b on|off                       #
# PortalDBI_c on|off                       #
# PortalDBI_d on|off                       #
# PortalDBI_e on|off                       #
# PortalDBI_f on|off                       #
# PortalDBI_g on|off                       #
# PortalDBI_useracct on|off                #
# PortalDBI_log_field last_access          #
# PortalDBI_Radius_host none               #
# PortalDBI_Radius_port 1645               #
# PortalDBI_Radius_secret none             #
# PortalDBI_Radius_timeout 45              #
# AuthCookieDebug 0,1,2,3                  #
# PortalDomain .yourdomain.com             #
#                                          #
############################################

# key line must come first
PerlSetVar PortalDBI_SecretKeyFile /usr/local/apache/conf/site.key

PerlModule Apache::AuthCookieDBIRadius
PerlSetVar PortalPath /
PerlSetVar PortalLoginScript /login.pl
PerlSetVar AuthCookieDebug 1
PerlSetVar PortalDBI_DSN 'dbi:Pg:host=localhost port=5432 dbname=mydatabase'
PerlSetVar PortalDBI_User "database_user"
PerlSetVar PortalDBI_Password "database_password"
PerlSetVar PortalDBI_UsersTable "users"
PerlSetVar PortalDBI_UserField "userid"
PerlSetVar PortalDBI_PasswordField "password"
PerlSetVar PortalDBI_SessionLifeTime 00-24-00-00


<FilesMatch "\.pl">
 AuthType Apache::AuthCookieDBIRadius
 AuthName Portal
 SetHandler perl-script
 PerlHandler Apache::Registry
 Options +ExecCGI
</FilesMatch>

# login.pl
<Files LOGIN>
 AuthType Apache::AuthCookieDBIRadius
 AuthName Portal
 SetHandler perl-script
 PerlHandler Apache::AuthCookieDBIRadius->login
</Files>

#######################################
#                                     #
# Begin websites                      #
#                                     #
#######################################

# private
<Directory /home/httpd/html/private>
 AuthType Apache::AuthCookieDBIRadius
 AuthName Portal
 PerlSetVar PortalDBI_b on
 PerlAuthenHandler Apache::AuthCookieDBIRadius->authenticate
 PerlAuthzHandler Apache::AuthCookieDBIRadius->authorize
 require valid-user
</Directory>

# calendar
<Directory /home/httpd/html/calendar>
 AuthType Apache::AuthCookieDBIRadius
 AuthName Portal
 PerlSetVar PortalDBI_a on
 PerlAuthenHandler Apache::AuthCookieDBIRadius->authenticate
 PerlAuthzHandler Apache::AuthCookieDBIRadius->authorize
 require valid-user
</Directory>

login.pl  view on Meta::CPAN

#!/usr/bin/perl

use strict;
my $r = Apache->request;

$r->status(200);
my $uri = $r->prev->uri;
my $reason = $r->prev->subprocess_env("AuthCookieReason");

# added args so we can redirect correctly.
my $args = $r->prev->args;
$uri = "$uri?$args" if $args;

my $form;

$form = <<HERE;
<HTML>
<HEAD>

techspec.txt  view on Meta::CPAN

$Id: techspec.txt,v 1.2 2000/04/05 19:02:49 jacob Exp $

Apache::AuthCookieDBI Technical Specification

* Description.

This module will allow cookie-based authentication backed by a DBI database,
using usernames and passwords for authentication.

* Authentication.

Authentication is based on a username and password.  These are supplied in
plaintext by the user in a form submission through Apache::AuthCookie.  These
are compared against values in a users table in a DBI database.  The password
field in the database may be plaintext, or hashed with crypt() or md5_hex().

* Tickets.

When a user successfully authenticates, they are issued a cookie with a
session value.  This value consists of a serialized version of
the userid, an issue time, an expiration date, and a two-round MD5 checksum
of the userid and times and a server secret key.  This checksum
ensures that when the ticket is returned we can see that it has not been

test.pl  view on Meta::CPAN

# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl test.pl'

######################### We start with some black magic to print on failure.

# Change 1..1 below to 1..last_test_to_print .
# (It may become useful if the test is moved to ./t subdirectory.)

BEGIN { $| = 1; print "1..1\n"; }
END {print "not ok 1\n" unless $loaded;}
use Apache::AuthCookieDBIRadius;
$loaded = 1;
print "ok 1\n";

######################### End of black magic.

# Insert your test code below (better if it prints "ok 13"
# (correspondingly "not ok 13") depending on the success of chunk 13
# of the test code):



( run in 0.801 second using v1.01-cache-2.11-cpan-e9199f4ba4c )