Apache-AuthCookieDBI
view release on metacpan or search on metacpan
AuthCookieDBI.pm view on Meta::CPAN
# Optional, to share tickets between servers.
PerlSetVar WhatEverDomain .domain.com
# These must be set
PerlSetVar WhatEverDBI_DSN "DBI:mysql:database=test"
PerlSetVar WhatEverDBI_SecretKey "489e5eaad8b3208f9ad8792ef4afca73598ae666b0206a9c92ac877e73ce835c"
# These are optional, the module sets sensible defaults.
PerlSetVar WhatEverDBI_User "nobody"
PerlSetVar WhatEverDBI_Password "password"
PerlSetVar WhatEverDBI_UsersTable "users"
PerlSetVar WhatEverDBI_UserField "user"
PerlSetVar WhatEverDBI_PasswordField "password"
PerlSetVar WhatEverDBI_CryptType "none"
PerlSetVar WhatEverDBI_GroupsTable "groups"
PerlSetVar WhatEverDBI_GroupField "grp"
PerlSetVar WhatEverDBI_GroupUserField "user"
PerlSetVar WhatEverDBI_EncryptionType "none"
PerlSetVar WhatEverDBI_SessionLifetime 00-24-00-00
# Protected by AuthCookieDBI.
<Directory /www/domain.com/authcookiedbi>
AuthType Apache::AuthCookieDBI
AuthCookieDBI.pm view on Meta::CPAN
AuthType Apache::AuthCookieDBI
AuthName WhatEver
SetHandler perl-script
PerlHandler Apache::AuthCookieDBI->login
</Files>
=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
in the database; the password in the database can be plaintext, or a crypt()
or md5_hex() checksum of the password. If this succeeds, the user is issued
a ticket. This ticket contains the username, an issue time, an expire time,
and an MD5 checksum of those and a secret key for the server. It can
optionally be encrypted before returning it to the client in the cookie;
encryption is only useful for preventing the client from seeing the expire
time. If you wish to protect passwords in transport, use an SSL-encrypted
connection. The ticket is given in a cookie that the browser stores.
After a login the user is redirected to the location they originally wished
to view (or to a fixed page if the login "script" was really a static file).
On this access and any subsequent attempt to access a protected document, the
browser returns the ticket to the server. The server unencrypts it if
encrypted tickets are enabled, then extracts the username, issue time, expire
time and checksum. A new checksum is calculated of the username, issue time,
expire time and the secret key again; if it agrees with the checksum that
AuthCookieDBI.pm view on Meta::CPAN
The user to log into the database as. This is not required and
defaults to undef.
=cut
$c{DBI_user} = _dir_config_var( $r, 'DBI_User' )
|| undef;
=item C<WhatEverDBI_Password>
The password to use to access the database. This is not required
and defaults to undef.
=cut
$c{DBI_password} = _dir_config_var( $r, 'DBI_Password' )
|| undef;
=item C<WhatEverDBI_UsersTable>
The table that user names and passwords are stored in. This is not
required and defaults to 'users'.
=cut
$c{DBI_userstable} = _dir_config_var( $r, 'DBI_UsersTable' )
|| 'users';
=item C<WhatEverDBI_UserField>
The field in the above table that has the user name. This is not
required and defaults to 'user'.
=cut
$c{DBI_userfield} = _dir_config_var( $r, 'DBI_UserField' )
|| 'user';
=item C<WhatEverDBI_PasswordField>
The field in the above table that has the password. This is not
required and defaults to 'password'.
=cut
$c{DBI_passwordfield} = _dir_config_var( $r, 'DBI_PasswordField' )
|| 'password';
=item C<WhatEverDBI_CryptType>
What kind of hashing is used on the password field in the database. This can
be 'none', 'crypt', or 'md5'. This is not required and defaults to 'none'.
=cut
$c{DBI_crypttype} = _dir_config_var( $r, 'DBI_CryptType' )
|| 'none';
=item C<WhatEverDBI_GroupsTable>
The table that has the user / group information. This is not required and
AuthCookieDBI.pm view on Meta::CPAN
{
_log_not_set $r, 'DBI_SecretKeyFile or DBI_SecretKey';
return;
}
=item C<WhatEverDBI_EncryptionType>
What kind of encryption to use to prevent the user from looking at the fields
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'.
=cut
$c{DBI_encryptiontype} = _dir_config_var( $r, 'DBI_EncryptionType' )
|| 'none';
# If we used encryption we need to pull in Crypt::CBC.
AuthCookieDBI.pm view on Meta::CPAN
return;
}
#-------------------------------------------------------------------------------
# Take the credentials for a user and check that they match; if so, return
# a new session key for this user that can be stored in the cookie.
# If there is a problem, return a bogus session key.
sub authen_cred {
my ( $self, $r, @credentials ) = @_;
my ( $user, $password, @extra_credentials ) = @credentials;
my $auth_name = $r->auth_name;
( $user, $password ) = _defined_or_empty( $user, $password );
if ( !length $user ) {
$r->log_reason(
"Apache::AuthCookieDBI: no username supplied for auth realm $auth_name",
$r->uri
);
return;
}
if ( !length $password ) {
$r->log_reason(
"Apache::AuthCookieDBI: no password supplied for auth realm $auth_name",
$r->uri
);
return;
}
# get the configuration information.
my %c = _dbi_config_vars $r;
# get the crypted password from the users database for this user.
my $dbh = DBI->connect( $c{DBI_DSN}, $c{DBI_user}, $c{DBI_password} );
unless ( defined $dbh ) {
$r->log_reason(
"Apache::AuthCookieDBI: couldn't connect to $c{ DBI_DSN } for auth realm $auth_name",
$r->uri
);
return;
}
my $sth = $dbh->prepare( <<"EOS" );
SELECT $c{ DBI_passwordfield }
FROM $c{ DBI_userstable }
WHERE $c{ DBI_userfield } = ?
EOS
$sth->execute($user);
my ($crypted_password) = $sth->fetchrow_array;
unless ( defined $crypted_password ) {
$r->log_reason(
"Apache::AuthCookieDBI: couldn't select password from $c{ DBI_DSN }, $c{ DBI_userstable }, $c{ DBI_userfield } for user $user for auth realm $auth_name",
$r->uri
);
return;
}
# now return unless the passwords match.
if ( lc $c{DBI_crypttype} eq 'none' ) {
unless ( $password eq $crypted_password ) {
$r->log_reason(
"Apache::AuthCookieDBI: plaintext passwords didn't match for user $user for auth realm $auth_name",
$r->uri
);
return;
}
}
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::AuthCookieDBI: crypted passwords didn't match for user $user for auth realm $auth_name",
$r->uri
);
return;
}
}
elsif ( lc $c{DBI_crypttype} eq 'md5' ) {
unless ( md5_hex($password) eq $crypted_password ) {
$r->log_reason(
"Apache::AuthCookieDBI: MD5 passwords didn't match for user $user for auth realm $auth_name",
$r->uri
);
return;
}
}
# Create the expire time for the ticket.
my $expire_time;
# expire time in a zillion years if it's forever.
AuthCookieDBI.pm view on Meta::CPAN
my ( $self, $r, @groups ) = @_;
my $auth_name = $r->auth_name;
# 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::AuthCookieDBI: couldn't connect to $c{ DBI_DSN } for auth realm $auth_name",
$r->uri
);
return;
}
# Now loop through all the groups to see if we're a member of any:
my $sth = $dbh->prepare( <<"EOS" );
AuthCookieDBI.pm view on Meta::CPAN
1;
__END__
=back
=head1 DATABASE SCHEMAS
For this module to work, the database tables must be laid out at least somewhat
according to the following rules: the user field must be a primary key
so there is only one row per user; the password field must be NOT NULL. If
you're using MD5 passwords the password field must be 32 characters long to
allow enough space for the output of md5_hex(). If you're using crypt()
passwords you need to allow 13 characters.
An minimal CREATE TABLE statement might look like:
CREATE TABLE users (
user VARCHAR(16) PRIMARY KEY,
password VARCHAR(32) NOT NULL
)
For the groups table, the access table is actually going to be a join table
between the users table and a table in which there is one row per group
if you have more per-group data to store; if all you care about is group
membership though, you only need this one table. The only constraints on
this table are that the user and group fields be NOT NULL.
A minimal CREATE TABLE statement might look like:
Apache::AuthCookieDBI is a module that subclasses Apache::AuthCookie and is
designed to be directly used for authentication in a mod_perl server.
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.
generic_reg_auth_scheme.txt view on Meta::CPAN
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'
PerlSetVar AuthNameDBI_PasswordField fieldname # default 'password'
PerlSetVar AuthNameDBI_CryptType [ none, crypt, MD5 ] # default 'none'
PerlSetVar AuthNameDBI_GroupsTable tablename # default 'groups'
PerlSetVar AuthNameDBI_GroupField fieldname # default 'group'
PerlSetVar AuthNameDBI_GroupUserField fieldname # default 'user'
# 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
# $Id: schema.sql,v 1.1.1.1 2003/10/10 20:13:33 jacob Exp $
#
# Schema for creating the database tables for an authentication system.
CREATE TABLE users (
user CHAR(16) PRIMARY KEY,
password CHAR(24)
);
CREATE TABLE groups (
group CHAR(16),
user CHAR(16)
);
techspec.txt view on Meta::CPAN
$Id: techspec.txt,v 1.1.1.1 2003/10/10 20:13:33 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
tampered with since in order to generate the checksum you must have the secret
( run in 1.011 second using v1.01-cache-2.11-cpan-49f99fa48dc )