Apache-AuthCookie
view release on metacpan or search on metacpan
lib/Apache/AuthCookie.pm view on Meta::CPAN
package Apache::AuthCookie;
$Apache::AuthCookie::VERSION = '3.32';
# ABSTRACT: Perl Authentication and Authorization via cookies
use strict;
use Carp;
use mod_perl qw(1.07 StackedHandlers MethodHandlers Authen Authz);
use Apache::Constants qw(:common M_GET FORBIDDEN OK REDIRECT);
use Apache::AuthCookie::Params;
use Apache::AuthCookie::Util qw(is_blank is_local_destination);
use Apache::Util qw(escape_uri);
use Apache::URI;
use Encode ();
sub recognize_user ($$) {
my ($self, $r) = @_;
# only check if user is not already set
return DECLINED unless is_blank($r->connection->user);
my $debug = $r->dir_config("AuthCookieDebug") || 0;
my ($auth_type, $auth_name) = ($r->auth_type, $r->auth_name);
return DECLINED if is_blank($auth_type) or is_blank($auth_name);
return DECLINED if is_blank($r->header_in('Cookie'));
my $cookie_name = $self->cookie_name($r);
my ($cookie) = $r->header_in('Cookie') =~ /$cookie_name=([^;]+)/;
$r->log_error("cookie $cookie_name is $cookie") if $debug >= 2;
return DECLINED unless $cookie;
my ($user, @args) = $auth_type->authen_ses_key($r, $cookie);
if (!is_blank($user) and scalar @args == 0) {
$r->log_error("user is $user") if $debug >= 2;
# if SessionTimeout is on, send new cookie with new Expires.
if (my $expires = $r->dir_config("${auth_name}SessionTimeout")) {
$self->send_cookie($cookie, { expires => $expires });
}
$r->connection->user( $self->_encode($r, $user) );
}
elsif (scalar @args > 0 and $auth_type->can('custom_errors')) {
return $auth_type->custom_errors($r, $user, @args);
}
return is_blank($user) ? DECLINED : OK;
}
sub cookie_name {
my ($self, $r) = @_;
my $auth_type = $r->auth_type;
my $auth_name = $r->auth_name;
my $cookie_name = $r->dir_config("${auth_name}CookieName")
|| "${auth_type}_${auth_name}";
return $cookie_name;
}
sub encoding {
my ($self, $r) = @_;
my $auth_name = $r->auth_name;
return $r->dir_config("${auth_name}Encoding");
}
sub requires_encoding {
my ($self, $r) = @_;
my $auth_name = $r->auth_name;
return $r->dir_config("${auth_name}RequiresEncoding");
}
sub decoded_user {
my ($self, $r) = @_;
my $user = $r->connection->user;
if (is_blank($user)) {
return $user;
}
my $encoding = $self->encoding($r);
if (!is_blank($encoding)) {
$user = Encode::decode($encoding, $user);
}
return $user;
}
lib/Apache/AuthCookie.pm view on Meta::CPAN
}
sub authenticate ($$) {
my ($auth_type, $r) = @_;
my $auth_user;
my $debug = $r->dir_config("AuthCookieDebug") || 0;
$r->log_error("auth_type " . $auth_type) if ($debug >= 3);
unless ($r->is_initial_req) {
if (defined $r->prev) {
# we are in a subrequest. Just copy user from previous request.
# encoding would have been handled in prev req, so do not encode here.
$r->connection->user($r->prev->connection->user);
}
return OK;
}
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 $cookie_name = $auth_type->cookie_name($r);
my ($ses_key_cookie) =
($r->header_in("Cookie") || "") =~ /$cookie_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) {
my ($auth_user, @args) =
$auth_type->authen_ses_key($r, $ses_key_cookie);
if (!is_blank($auth_user) and scalar @args == 0) {
# 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.
$r->connection->auth_type($auth_type);
$r->connection->user( $auth_type->_encode($r, $auth_user) );
$r->log_error("user authenticated as $auth_user") if $debug >= 1;
# if SessionTimeout is on, send cookie with new expires
if (my $expires = $r->dir_config("${auth_name}SessionTimeout")) {
$auth_type->send_cookie($ses_key_cookie,
{ expires => $expires });
}
return OK;
}
elsif (scalar @args > 0 and $auth_type->can('custom_errors')) {
return $auth_type->custom_errors($r, $auth_user, @args);
}
else {
# 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.
$auth_type->remove_cookie;
$r->subprocess_env('AuthCookieReason', 'bad_cookie');
}
}
else {
$r->subprocess_env('AuthCookieReason', 'no_cookie');
}
# 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 $self = shift;
my $r = Apache->request or die "no request";
my $auth_name = $r->auth_name;
$self->_convert_to_get($r) if $r->method eq 'POST';
# There should be a PerlSetVar directive that gives us the URI of
# the script to execute for the login form.
my $authen_script;
unless ($authen_script = $r->dir_config($auth_name . "LoginScript")) {
$r->log_reason("PerlSetVar '${auth_name}LoginScript' not set", $r->uri);
return SERVER_ERROR;
}
#$r->log_error("Redirecting to $authen_script");
my $status = $self->login_form_status($r);
$status = FORBIDDEN unless defined $status;
if ($status == OK) {
# custom_response doesn't work for OK, DONE, or DECLINED in apache 1.x
$r->internal_redirect($authen_script);
}
else {
$r->custom_response($status, $authen_script);
}
return $status;
}
lib/Apache/AuthCookie.pm view on Meta::CPAN
my $auth_name = $r->auth_name;
return $r->dir_config("${auth_name}Path");
}
sub _encode {
my ($self, $r, $value) = @_;
my $encoding = $self->encoding($r);
if (is_blank($encoding)) {
return $value;
}
else {
return Encode::encode($encoding, $value);
}
}
1;
=pod
=encoding UTF-8
=head1 NAME
Apache::AuthCookie - Perl Authentication and Authorization via cookies
=head1 VERSION
version 3.32
=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::Apache::AuthCookieHandler
PerlSetVar WhatEverPath /
PerlSetVar WhatEverLoginScript /login.pl
# use to alter how "require" directives are matched. Can be "Any" or "All".
# If its "Any", then you must only match Any of the "require" directives. If
# its "All", then you must match All of the require directives.
#
# Default: All
PerlSetVar WhatEverSatisfy Any
# 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
# Use this if you want user session cookies to expire if the user
# doesn't request a auth-required or recognize_user page for some
# time period. If set, a new cookie (with updated expire time)
# is set on every request.
PerlSetVar WhatEverSessionTimeout +30m
# to enable the HttpOnly cookie property, use HttpOnly.
# this is an MS extension. See
# http://msdn.microsoft.com/workshop/author/dhtml/httponly_cookies.asp
PerlSetVar WhatEverHttpOnly 1
# Usually documents are uncached - turn off here
PerlSetVar WhatEverCache 1
# Use this to make your cookies persistent (+2 hours here)
PerlSetVar WhatEverExpires +2h
# Use to make AuthCookie send a P3P header with the cookie
# see http://www.w3.org/P3P/ for details about what the value
# of this should be
PerlSetVar WhatEverP3P "CP=\"...\""
# optional: enforce that the destination argument from the login form is
# local to the server
PerlSetVar WhatEverEnforceLocalDestination 1
# optional: specify a default destination for when the destination argument
# of the login form is invalid or unspecified
PerlSetVar WhatEverDefaultDestination /protected/user/
# These documents require user to be logged in.
<Location /protected>
AuthType Sample::Apache::AuthCookieHandler
AuthName WhatEver
PerlAuthenHandler Sample::Apache::AuthCookieHandler->authenticate
PerlAuthzHandler Sample::Apache::AuthCookieHandler->authorize
require valid-user
</Location>
# These documents don't require logging in, but allow it.
<FilesMatch "\.ok$">
AuthType Sample::Apache::AuthCookieHandler
AuthName WhatEver
PerlFixupHandler Sample::Apache::AuthCookieHandler->recognize_user
</FilesMatch>
# This is the action of the login.pl script above.
<Files LOGIN>
AuthType Sample::Apache::AuthCookieHandler
AuthName WhatEver
SetHandler perl-script
PerlHandler Sample::Apache::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
( run in 0.322 second using v1.01-cache-2.11-cpan-1dc43b0fbd2 )