CGI::Ex::Auth(3) User Contributed Perl Documentation CGI::Ex::Auth(3)NAMECGI::Ex::Auth - Handle logins nicely.
SYNOPSIS
use CGI::Ex::Auth;
### authorize the user
my $auth = CGI::Ex::Auth->get_valid_auth({
get_pass_by_user => \&get_pass_by_user,
});
sub get_pass_by_user {
my $auth = shift;
my $user = shift;
my $pass = some_way_of_getting_password($user);
return $pass;
}
### OR - if you are using a OO based CGI or Application
sub require_authentication {
my $self = shift;
return $self->{'auth'} = CGI::Ex::Auth->get_valid_auth({
get_pass_by_user => sub {
my ($auth, $user) = @_;
return $self->get_pass($user);
},
});
}
sub get_pass {
my ($self, $user) = @_;
return $self->loopup_and_cache_pass($user);
}
DESCRIPTIONCGI::Ex::Auth allows for auto-expiring, safe and easy web based logins.
Auth uses javascript modules that perform MD5 hashing to cram the
password on the client side before passing them through the internet.
For the stored cookie you can choose to use simple cram mechanisms,
secure hash cram tokens, auto expiring logins (not cookie based), and
Crypt::Blowfish protection. You can also choose to keep passwords
plaintext and to use perl's crypt for testing passwords. Or you can
completely replace the cookie parsing/generating and let Auth handle
requesting, setting, and storing the cookie.
A theoretical downside to this module is that it does not use a session
to preserve state so get_pass_by_user has to happen on every request
(any authenticated area has to verify authentication each time - unless
the verify_token method is completely overridden). In theory you
should be checking the password everytime a user makes a request to
make sure the password is still valid. A definite plus is that you
don't need to use a session if you don't want to. It is up to the
interested reader to add caching to the get_pass_by_user method.
In the end, the only truly secure login method is across an https
connection. Any connection across non-https (non-secure) is
susceptible to cookie hijacking or tcp hijacking - though the
possibility of this is normally small and typically requires access to
a machine somewhere in your TCP chain. If in doubt - you should try to
use https - but even then you need to guard the logged in area against
cross-site javascript exploits. A discussion of all security issues is
far beyond the scope of this documentation.
METHODS
"new"
Constructor. Takes a hashref of properties as arguments.
Many of the methods which may be overridden in a subclass, or may
be passed as properties to the new constuctor such as in the
following:
CGI::Ex::Auth->new({
get_pass_by_user => \&my_pass_sub,
key_user => 'my_user',
key_pass => 'my_pass',
login_header => \"<h1>My Login</h1>",
});
The following methods will look for properties of the same name.
Each of these will be described separately.
cgix
cleanup_user
cookie_domain
cookie_secure
cookie_path
cookies
expires_min
form
form_name
get_pass_by_user
js_uri_path
key_cookie
key_expires_min
key_logout
key_pass
key_redirect
key_save
key_time
key_user
key_verify
key_loggedout
bounce_on_logout
login_footer
login_form
login_header
login_script
login_template
handle_success
handle_failure
success_hook
failure_hook
logout_hook
no_cookie_verify
path_info
script_name
secure_hash_keys
template_args
template_include_path
template_obj
text_user
text_pass
text_save
text_submit
hide_save
use_base64
use_blowfish
use_crypt
use_plaintext
use_session_cookie
verify_token
verify_payload
verify_user
"generate_token"
Takes either an auth_data object from a auth_data returned by
verify_token, or a hashref of arguments.
Possible arguments are:
user - the username we are generating the token for
real_pass - the password of the user (if use_plaintext is false
and use_crypt is false, the password can be an md5sum
of the user's password)
use_blowfish - indicates that we should use Crypt::Blowfish to protect
the generated token. The value of this argument is used
as the key. Default is false.
use_base64 - indicates that we should use Base64 encoding to protect
the generated token. Default is true. Will not be
used if use_blowfish is true.
use_plaintext - indicates that we should keep the password in plaintext
use_crypt - also indicates that we should keep the password in plaintext
expires_min - says how many minutes until the generated token expires.
Values <= 0 indicate to not ever expire. Used only on cram
types.
payload - a payload that will be passed to generate_payload and then
will be added to cram type tokens. It cannot contain a /.
prefer_simple_cram
- If the secure_hash_keys method returns keys, and it is a non-plaintext
token, generate_token will create a secure_hash_cram. Set
this value to true to tell it to use a simple_cram. This
is generally only useful in testing.
The following are types of tokens that can be generated by
generate_token. Each type includes pseudocode and a sample of a
generated that token.
plaintext:
user := "paul"
real_pass := "123qwe"
token := join("/", user, real_pass);
use_base64 := 0
token == "paul/123qwe"
use_base64 := 1
token == "cGF1bC8xMjNxd2U="
use_blowfish := "foobarbaz"
token == "6da702975190f0fe98a746f0d6514683"
Notes: This token will be used if either use_plaintext or use_crypt is set.
The real_pass can also be the md5_sum of the password. If real_pass is an md5_sum
of the password but the get_pass_by_user hook returns the crypt'ed password, the
token will not be able to be verified.
simple_cram:
user := "paul"
real_pass := "123qwe"
server_time := 1148512991 # a time in seconds since epoch
expires_min := 6 * 60
payload := "something"
md5_pass := md5_sum(real_pass) # if it isn't already a 32 digit md5 sum
str := join("/", user, server_time, expires_min, payload, md5_pass)
md5_str := md5(sum_str)
token := join("/", user, server_time, expires_min, payload, md5_str)
use_base64 := 0
token == "paul/1148512991/360/something/16d0ba369a4c9781b5981eb89224ce30"
use_base64 := 1
token == "cGF1bC8xMTQ4NTEyOTkxLzM2MC9zb21ldGhpbmcvMTZkMGJhMzY5YTRjOTc4MWI1OTgxZWI4OTIyNGNlMzA="
Notes: use_blowfish is available as well
secure_hash_cram:
user := "paul"
real_pass := "123qwe"
server_time := 1148514034 # a time in seconds since epoch
expires_min := 6 * 60
payload := "something"
secure_hash := ["aaaa", "bbbb", "cccc", "dddd"]
rand1 := 3 # int(rand(length(secure_hash)))
rand2 := 39163 # int(rand(100000))
md5_pass := md5_sum(real_pass) # if it isn't already a 32 digit md5 sum
sh_str1 := join(".", "sh", secure_hash[rand1], rand2)
sh_str2 := join(".", "sh", rand1, rand2)
str := join("/", user, server_time, expires_min, payload, md5_pass, sh_str1)
md5_str := md5(sum_str)
token := join("/", user, server_time, expires_min, payload, md5_str, sh_str2)
use_base64 := 0
token == "paul/1148514034/360/something/06db2914c9fd4e11499e0652bcf67dae/sh.3.39163"
Notes: use_blowfish is available as well. The secure_hash keys need to be set in the
"secure_hash_keys" property of the CGI::Ex::Auth object.
"get_valid_auth"
Performs the core logic. Returns an auth object on successful
login. Returns false on errored login (with the details of the
error stored in $@). If a false value is returned, execution of
the CGI should be halted. get_valid_auth WILL NOT automatically
stop execution.
$auth->get_valid_auth || exit;
Optionally, the class and a list of arguments may be passed. This
will create a new object using the passed arguments, and then run
get_valid_auth.
CGI::Ex::Auth->get_valid_auth({key_user => 'my_user'}) || exit;
"check_valid_auth"
Runs get_valid_auth with login_print and location_bounce set to do
nothing. This allows for obtaining login data without forcing an
html login page to appear.
"login_print"
Called if login errored. Defaults to printing a very basic (but
adequate) page loaded from login_template..
You will want to override it with a template from your own system.
The hook that is called will be passed the step to print (currently
only "get_login_info" and "no_cookies"), and a hash containing the
form variables as well as the following:
"login_hash_common"
Passed to the template swapped during login_print.
%$form, # any keys passed to the login script
error # The text "Login Failed" if a login occurred
login_data # A login data object if they failed authentication.
key_user # $self->key_user, # the username fieldname
key_pass # $self->key_pass, # the password fieldname
key_time # $self->key_time, # the server time field name
key_save # $self->key_save, # the save password checkbox field name
key_redirect # $self->key_redirect, # the redirect fieldname
form_name # $self->form_name, # the name of the form
script_name # $self->script_name, # where the server will post back to
path_info # $self->path_info, # $ENV{PATH_INFO} if any
md5_js_path # $self->js_uri_path ."/CGI/Ex/md5.js", # script for cramming
$self->key_user # $data->{'user'}, # the username (if any)
$self->key_pass # '', # intentional blankout
$self->key_time # $self->server_time, # the server's time
$self->key_expires_min # $self->expires_min # how many minutes crams are valid
text_user # $self->text_user # template text Username:
text_pass # $self->text_pass # template text Password:
text_save # $self->text_save # template text Save Password ?
text_submit # $self->text_submit # template text Login
hide_save # $self->hide_save # 0
"bounce_on_logout"
Default 0. If true, will location bounce to script returned by
logout_redirect passing the key key_logout. If false, will simply
show the login screen.
"key_loggedout"
Key to bounce with in the form during a logout should
bounce_on_logout return true. Default is "loggedout".
"key_logout"
If the form hash contains a true value in this field name, the
current user will be logged out. Default is "cea_logout".
"key_cookie"
The name of the auth cookie. Default is "cea_user".
"key_verify"
A field name used during a bounce to see if cookies exist. Default
is "cea_verify".
"key_user"
The form field name used to pass the username. Default is
"cea_user".
"key_pass"
The form field name used to pass the password. Default is
"cea_pass".
"key_save"
Works in conjunction with key_expires_min. If key_save is true,
then the cookie will be set to be saved for longer than the current
session (If it is a plaintext variety it will be given a 20 year
life rather than being a session cookie. If it is a cram variety,
the expires_min portion of the cram will be set to -1). If it is
set to false, the cookie will be available only for the session (If
it is a plaintext variety, the cookie will be session based and
will be removed on the next loggout. If it is a cram variety then
the cookie will only be good for expires_min minutes.
Default is "cea_save".
"key_expires_min"
The name of the form field that contains how long cram type cookies
will be valid if key_save contains a false value.
Default key name is "cea_expires_min". Default field value is 6 *
60 (six hours).
This value will have no effect when use_plaintext or use_crypt is
set.
A value of -1 means no expiration.
"failed_sleep"
Number of seconds to sleep if the passed tokens are invalid. Does
not apply if validation failed because of expired tokens. Default
value is 0. Setting to 0 disables any sleeping.
"form_name"
The name of the html login form to attach the javascript to.
Default is "cea_form".
"verify_token"
This method verifies the token that was passed either via the form
or via cookies. It will accept plaintext or crammed tokens (A
listing of the available algorithms for creating tokes is listed
below). It also allows for armoring the token with base64
encoding, or using blowfish encryption. A listing of creating
these tokens can be found under generate_token.
"parse_token"
Used by verify_token to remove armor from the passed tokens and
split the token into its parts. Returns true if it was able to
parse the passed token.
"cleanup_user"
Called by verify_token. Default is to do no modification. Allows
for usernames to be lowercased, or canonized in some other way.
Should return the cleaned username.
"verify_user"
Called by verify_token. Single argument is the username. May or
may not be an initial check to see if the username is ok. The
username will already be cleaned at this point. Default return is
true.
"get_pass_by_user"
Called by verify_token. Given the cleaned, verified username,
should return a valid password for the user. It can always return
plaintext. If use_crypt is enabled, it should return the crypted
password. If use_plaintext and use_crypt are not enabled, it may
return the md5 sum of the password.
get_pass_by_user => sub {
my ($auth_obj, $user) = @_;
my $pass = $some_obj->get_pass({user => $user});
return $pass;
}
Alternately, get_pass_by_user may return a hashref of data items
that will be added to the data object if the token is valid. The
hashref must also contain a key named real_pass or password that
contains the password. Note that keys passed back in the hashref
that are already in the data object will override those in the data
object.
get_pass_by_user => sub {
my ($auth_obj, $user) = @_;
my ($pass, $user_id) = $some_obj->get_pass({user => $user});
return {
password => $pass,
user_id => $user_id,
};
}
"verify_password"
Called by verify_token. Passed the password to check as well as
the auth data object. Should return true if the password matches.
Default method can handle md5, crypt, cram, secure_hash_cram, and
plaintext (all of the default types supported by generate_token).
If a property named verify_password exists, it will be used and
called as a coderef rather than using the default method.
"verify_payload"
Called by verify_token. Passed the password to check as well as
the auth data object. Should return true if the payload is valid.
Default method returns true without performing any checks on the
payload. If a property named verify_password exists, it will be
used and called as a coderef rather than using the default method.
"cgix"
Returns a CGI::Ex object.
"form"
A hash of passed form info. Defaults to CGI::Ex::get_form.
"cookies"
The current cookies. Defaults to CGI::Ex::get_cookies.
"login_template"
Should return either a template filename to use for the login
template, or it should return a reference to a string that contains
the template. The contents will be used in login_print and passed
to the template engine.
Default login_template is the values of login_header, login_form,
login_script, and login_script concatenated together.
Values from login_hash_common will be passed to the template
engine, and will also be used to fill in the form.
The basic values are capable of handling most needs so long as
appropriate headers and css styles are used.
"login_header"
Should return a header to use in the default login_template. The
default value will try to PROCESS a file called login_header.tt
that should be located in directory specified by the
template_include_path method.
It should ideally supply css styles that format the login_form as
desired.
"login_footer"
Same as login_header - but for the footer. Will look for
login_footer.tt by default.
"login_form"
An html chunk that contains the necessary form fields to login the
user. The basic chunk has a username text entry, password text
entry, save password checkbox, and submit button, and any hidden
fields necessary for logging in the user.
"login_script"
Contains javascript that will attach to the form from login_form.
This script is capable of taking the login_fields and creating an
md5 cram which prevents the password from being passed plaintext.
"text_user, text_pass, text_save"
The text items shown in the default login template. The default
values are:
text_user "Username:"
text_pass "Password:"
text_save "Save Password ?"
"disable_simple_cram"
Disables simple cram type from being an available type. Default is
false. If set, then one of use_plaintext, use_crypt, or
secure_hash_keys should be set. Setting this option allows for
payloads to be generated by the server only - otherwise a user who
understands the algorithm could generate a valid simple_cram cookie
with a custom payload.
Another option would be to only accept payloads from tokens if
use_blowfish is set and armor was equal to "blowfish."
LICENSE
This module may be distributed under the same terms as Perl itself.
AUTHORS
Paul Seamons <perl at seamons dot com>
perl v5.14.1 2010-02-25 CGI::Ex::Auth(3)