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 )