Apache2-Controller

 view release on metacpan or  search on metacpan

Build.PL  view on Meta::CPAN


my @requires = qw(
    Apache2::CmdParms
    Apache2::Connection
    Apache2::Const
    Apache2::Cookie
    Apache2::Directive
    Apache2::Module
    Apache2::Request
    Apache2::RequestIO
    Apache2::RequestRec
    Apache2::RequestUtil
    Apache::Session
    Apache::Session::File
    DateTime
    Digest::SHA

Build.PL  view on Meta::CPAN

my @build_requires = qw(
    Apache::TestMM
    Apache::TestRequest
    Apache::TestRunPerl
    Apache::TestUtil
    Net::OpenID::Server
    HTTP::Server::Simple::CGI
    Math::BigInt::GMP
    URI::Escape
    LWP
    HTTP::Cookies
);

my @recommends = qw(
    LWPx::ParanoidAgent
    IPC::Open3
);

use Module::Build;

my $build_pkg = eval { require Apache::TestMB }

Changes  view on Meta::CPAN

            template was used, so Apache doesn't try to append its own 
            html error messages to the finished html output.

            Session factored tying and will now generate a new cookie
            and session if the session store object referenced by the old 
            cookie is no longer present.


1.000.111   2010-12-21

            bad cookie eval only if directive A2C_Skip_Bogus_Cookies.


1.000.101   2010-12-21

            mkdir explicitly uses $_ for perl < 5.10.  Fixes RT# 60240.

            Errors from Apache2::Cookie::Jar->new() skipped if the
            APR::Request::Error code is NOTOKEN.  Bad cookie, buggy 
            client.  Fixes RT# 61744.


1.000.100   2009-02-02

            Fixed MANIFEST. RT# 42979.
            https://rt.cpan.org/Ticket/Display.html?id=42979

            Switched to Module::Build to better control prereqs,

MANIFEST  view on Meta::CPAN

lib/Apache2/Controller/Log/DetectAbortedConnection.pm
lib/Apache2/Controller/Log/SessionSave.pm
lib/Apache2/Controller/Methods.pm
lib/Apache2/Controller/NonResponseBase.pm
lib/Apache2/Controller/NonResponseRequest.pm
lib/Apache2/Controller/PerChildInit.pm
lib/Apache2/Controller/Refcard.pm
lib/Apache2/Controller/Render/Template.pm
lib/Apache2/Controller/SQL/MySQL.pm
lib/Apache2/Controller/Session.pm
lib/Apache2/Controller/Session/Cookie.pm
lib/Apache2/Controller/X.pm
t/00-load.t
t/TEST.PL
t/basic.t
t/conf/dispatch/simple.yaml
t/conf/extra.last.conf.in
t/conf/modperl_extra.pl
t/dbi_connector.t
t/lib/Apache2/Controller/Test/Funk.pm
t/lib/Apache2/Controller/Test/Mockr.pm

META.json  view on Meta::CPAN

   },
   "name" : "Apache2-Controller",
   "prereqs" : {
      "build" : {
         "requires" : {
            "Apache::Test" : "1.12",
            "Apache::TestMM" : "0",
            "Apache::TestRequest" : "0",
            "Apache::TestRunPerl" : "0",
            "Apache::TestUtil" : "0",
            "HTTP::Cookies" : "0",
            "HTTP::Server::Simple::CGI" : "0",
            "LWP" : "0",
            "Math::BigInt::GMP" : "0",
            "Net::OpenID::Server" : "0",
            "URI::Escape" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "Module::Build" : "0.42"

META.json  view on Meta::CPAN

      },
      "runtime" : {
         "recommends" : {
            "IPC::Open3" : "0",
            "LWPx::ParanoidAgent" : "0"
         },
         "requires" : {
            "Apache2::CmdParms" : "0",
            "Apache2::Connection" : "0",
            "Apache2::Const" : "0",
            "Apache2::Cookie" : "0",
            "Apache2::Directive" : "0",
            "Apache2::Module" : "0",
            "Apache2::Request" : "0",
            "Apache2::RequestIO" : "0",
            "Apache2::RequestRec" : "0",
            "Apache2::RequestUtil" : "0",
            "Apache::Session" : "0",
            "Apache::Session::File" : "0",
            "DateTime" : "0",
            "Digest::SHA" : "0",

META.json  view on Meta::CPAN

         "version" : "v1.1.1"
      },
      "Apache2::Controller::SQL::MySQL" : {
         "file" : "lib/Apache2/Controller/SQL/MySQL.pm",
         "version" : "v1.1.1"
      },
      "Apache2::Controller::Session" : {
         "file" : "lib/Apache2/Controller/Session.pm",
         "version" : "v1.1.1"
      },
      "Apache2::Controller::Session::Cookie" : {
         "file" : "lib/Apache2/Controller/Session/Cookie.pm",
         "version" : "v1.1.1"
      },
      "Apache2::Controller::X" : {
         "file" : "lib/Apache2/Controller/X.pm",
         "version" : "v1.1.1"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "license" : [

META.yml  view on Meta::CPAN

---
abstract: 'fast MVC-style Apache2 handler apps'
author:
  - 'Mark Hedges <hedges@formdata.biz>'
build_requires:
  Apache::Test: '1.12'
  Apache::TestMM: '0'
  Apache::TestRequest: '0'
  Apache::TestRunPerl: '0'
  Apache::TestUtil: '0'
  HTTP::Cookies: '0'
  HTTP::Server::Simple::CGI: '0'
  LWP: '0'
  Math::BigInt::GMP: '0'
  Net::OpenID::Server: '0'
  URI::Escape: '0'
configure_requires:
  Module::Build: '0.42'
dynamic_config: 1
generated_by: 'Module::Build version 0.4205, CPAN::Meta::Converter version 2.141520'
license: perl

META.yml  view on Meta::CPAN

    version: v1.1.1
  Apache2::Controller::Render::Template:
    file: lib/Apache2/Controller/Render/Template.pm
    version: v1.1.1
  Apache2::Controller::SQL::MySQL:
    file: lib/Apache2/Controller/SQL/MySQL.pm
    version: v1.1.1
  Apache2::Controller::Session:
    file: lib/Apache2/Controller/Session.pm
    version: v1.1.1
  Apache2::Controller::Session::Cookie:
    file: lib/Apache2/Controller/Session/Cookie.pm
    version: v1.1.1
  Apache2::Controller::X:
    file: lib/Apache2/Controller/X.pm
    version: v1.1.1
recommends:
  IPC::Open3: '0'
  LWPx::ParanoidAgent: '0'
requires:
  Apache2::CmdParms: '0'
  Apache2::Connection: '0'
  Apache2::Const: '0'
  Apache2::Cookie: '0'
  Apache2::Directive: '0'
  Apache2::Module: '0'
  Apache2::Request: '0'
  Apache2::RequestIO: '0'
  Apache2::RequestRec: '0'
  Apache2::RequestUtil: '0'
  Apache::Session: '0'
  Apache::Session::File: '0'
  DateTime: '0'
  Digest::SHA: '0'

lib/Apache2/Controller.pm  view on Meta::CPAN

Add handlers in your config file with your own modules which 
C<use base> to inherit from these classes as you need them:

=head2 PerlHeaderParserHandler Apache2::Controller::Session

C<< $r->pnotes->{a2c}{session} >> automatically loaded from and 
stored to an L<Apache::Session> tied hash.  Pushes a PerlLogHandler
to save the session after the main controller returns OK.

See L<Apache2::Controller::Session>
and L<Apache2::Controller::Session::Cookie>.

=head2 PerlAuthenHandler Apache2::Controller::Authen::OpenID

Implements OpenID logins and redirects to your specified login 
controller by changing the dispatch selection on the fly.

See L<Apache2::Controller::Authen::OpenID>.

As for Access and Authz phases of AAA, you should
probably roll your own.  This framework isn't going

lib/Apache2/Controller/Auth/OpenID.pm  view on Meta::CPAN


     # if you do not want to preserve GET/POST params 
     # across redirects to the OpenID server, use this flag:
     # A2C_Auth_OpenID_NoPreserveParams

     # if you do not overload get_uname() (see below), then
     # PerlHeaderParserHandlers must be invoked in order
     # to set up the dbi handle before checking auth
     # with the default method.  In this example,
     # MyApp::DBI::Connector is an Apache2::Controller::DBI::Connector
     # and MyApp::Session is an Apache2::Controller::Session::Cookie...
     # see those modules for more info.

     PerlInitHandler            MyApp::Dispatch 
     PerlHeaderParserHandler    MyApp::DBI::Connector
     PerlHeaderParserHandler    MyApp::Session
     PerlHeaderParserHandler    Apache2::Controller::Auth::OpenID
 </Location>

=head1 DESCRIPTION

lib/Apache2/Controller/Auth/OpenID.pm  view on Meta::CPAN

This is NOT an AuthenPerlHandler.  This is an implementation
of a simple cookie-based mechanism that shows the browser
a login page, where your controller should present and process an
HTML form for logging in.  

If you want an authentication handler that uses browser-based auth
(the pop-up dialog implemented by HTTP auth protocol) use 
L<Apache::Authen::OpenID>, which is not a part of Apache2::Controller
but should work for you anyway.

Natively this depends on L<Apache2::Controller::Session::Cookie>
and L<Apache2::Controller::DBI::Connector> being configured
correctly, but you could always subclass this and overload the
methods below to get information from other sources.

If no claimed ID is detected, the user is shown the login
page.  If an error occured, you'll find the L<Net::OpenID::Consumer>
error details in the session under C<< {a2c}{openid}{errtext} >>
and C<< {a2c}{openid}{errcode} >>.

=head2 REDIRECTION OR REDISPATCH?

lib/Apache2/Controller/Const.pm  view on Meta::CPAN


=cut

Readonly our $DEFAULT_CONSUMER_SECRET => q|-qf_AD4#~a{~3)84cCvd+$6R89+,[l|;

=head2 $DEFAULT_SESSION_SECRET

Some hardcoded garbage characters used to salt the sha hash of time
for the session key secret if one isn't specified or generated.

See L<Apache2::Controller::Session::Cookie> and
L<Apache2::Controller::Directives/A2C_Session_Secret>.

=cut

Readonly our $DEFAULT_SESSION_SECRET => q|Je52oN~$VSE.8PNs-e$5tRzB<=l.IC|;

=head1 SEE ALSO

Apache2::Controller

lib/Apache2/Controller/Directives.pm  view on Meta::CPAN

            A2C_Session_Secret
        },
    },
    {
        name            => 'A2C_Session_Always_Save',
        req_override    => Apache2::Const::OR_ALL,
        args_how        => Apache2::Const::NO_ARGS,
        errmsg          => 'example: A2C_Session_Always_Save',
    },
    {
        name            => 'A2C_Session_Cookie_Opts',
        func            => __PACKAGE__.'::A2C_Session_Cookie_Opts',
        req_override    => Apache2::Const::OR_ALL,
        args_how        => Apache2::Const::ITERATE2,
        errmsg          => q{
            # specify Apache2::Cookie options for session cookie.
            # example:
            A2C_Session_Cookie_Opts   name       myapp_sessionid
            A2C_Session_Cookie_Opts   expires    +3M
        },
    },

    # A2C:Methods
    {
        name            => 'A2C_Skip_Bogus_Cookies',
        req_override    => Apache2::Const::OR_ALL,
        args_how        => Apache2::Const::NO_ARGS,
        errmsg          => 'example: A2C_Skip_Bogus_Cookies',
    },

    # A2C:DBI::Connector
    {
        name            => 'A2C_DBI_DSN',
        req_override    => Apache2::Const::OR_ALL,
        args_how        => Apache2::Const::TAKE1,
        errmsg          => 'example: A2C_DBI_DSN DBI:mysql:database=foo',
    },
    {

lib/Apache2/Controller/Directives.pm  view on Meta::CPAN

C<< $r->pnotes->{a2c}{session}{a2c_timestamp} >> so that
L<Apache::Session> will always save.

=cut

sub A2C_Session_Always_Save {
    my ($self, $parms) = @_;
    $self->{A2C_Session_Always_Save} = 1;
}

=head2 A2C_Session_Cookie_Opts

 A2C_Session_Cookie_Opts name    myapp_sessionid
 A2C_Session_Cookie_Opts expires +3M

Multiple arguments.  
L<Apache2::Controller::Session::Cookie>,
L<Apache2::Cookie>

=cut

sub A2C_Session_Cookie_Opts {
    my ($self, $parms, $key, $val) = @_;
    $self->hash_assign('A2C_Session_Cookie_Opts', $key, $val);
    return;
}

=head1 Apache2::Controller::Methods

Misc. directives that apply to most A2C objects that inherit
L<Apache2::Controller::Methods>.

=head2 A2C_Skip_Bogus_Cookies 

 A2C_Skip_Bogus_Cookies

Takes no arguments.  If present, cookie jar will be constructed
using C<< eval { } >> that skips NOTOKEN errors.  
See L<Apache2::Controller::Methods/get_cookie_jar>.

=cut

sub A2C_Skip_Bogus_Cookies {
    my ($self, $parms) = @_;
    $self->{A2C_Skip_Bogus_Cookies} = 1;
}

=head1 Apache2::Controller::DBI::Connector

See L<Apache2::Controller::DBI::Connector>.

=head2 A2C_DBI_DSN 

 A2C_DBI_DSN        DBI:mysql:database=foobar;host=localhost

lib/Apache2/Controller/Methods.pm  view on Meta::CPAN

=head1 METHODS

=cut

use strict;
use warnings FATAL => 'all';
use English '-no_match_vars';

use Apache2::Module ();
use Apache2::Controller::X;
use Apache2::Cookie;
use APR::Error ();
use APR::Request::Error ();
use YAML::Syck;
use Log::Log4perl qw( :easy );

=head2 get_directives

 my $directives_hashref = $self->get_directives();

Returns the L<Apache2::Controller::Directives> config hash for this request,

lib/Apache2/Controller/Methods.pm  view on Meta::CPAN

        "directive $directive = "
        .(defined $directive_value ? "'$directive_value'" : '[undef]')
    };
    return $directive_value;
}

=head2 get_cookie_jar

 my $jar = $self->get_cookie_jar();

Gets the L<Apache2::Cookie::Jar> object.

Does NOT cache the jar in any way, as this is the business 
of C<Apache2::Cookie>, and input headers could possibly change
via filters, and it would create a circular reference to C<< $r >>
if you stuck it in pnotes.  It always creates a new Jar object,
which acts as a utility object to parse the source information
that remains in C<< $r >>, if I understand this correctly.

If the directive << A2C_Skip_Bogus_Cookies >> is set, fetches
jar in eval and returns C<< $EVAL_ERROR->jar >> if the error
is an L<APR::Request::Error> and the code is C<< APR::Request::Error::NOTOKEN >>,
indicating a cookie with a value like '1' sent by a defective client.
Any other L<APR::Error> will be re-thrown as per that doc, 
otherwise A2C will throw an L<Apache2::Controller::X> with the error.
(See L<http://comments.gmane.org/gmane.comp.apache.apreq/4477> - 
closes RT #61744, thanks Arkadius Litwinczuk.)  Skipping these
errors is optional since they might be important for debugging 
clients that send invalid headers.

See L<Apache2::Cookie>, L<Apache2::Controller::Directives>.

=cut

sub get_cookie_jar {
    my $self = shift;
    return $self->get_directive('A2C_Skip_Bogus_Cookies')
        ? $self->_get_cookie_jar_eval(@_)
        : $self->_get_cookie_jar_normal(@_)
        ;
}

sub _get_cookie_jar_normal {
    my ($self) = @_;
    my $r = $self->{r};
    my $jar;
    eval { $jar = Apache2::Cookie::Jar->new($r) };
    if (my $err = $EVAL_ERROR) {
        my $ref = ref $err;
        DEBUG "error creating cookie jar (reftype '$ref'): '$err'";
        die $err if $ref; # rethrow blessed APR::Error errors
        a2cx "unknown error creating cookie jar: '$err'";
    }
    DEBUG sub {
        my $cookie = $r->headers_in->{Cookie};
        $cookie = $cookie ? qq{$cookie} : '[no raw cookie string]';
        eval { my @cookies = $jar->cookies() };
        a2cx "error getting cookie from jar that worked: '$EVAL_ERROR'"
            if $EVAL_ERROR;
        return 
            "raw cookie header: $cookie\n"
            ."cookie names in jar:\n"
            .join('', map qq{ - $_\n}, $jar->cookies() )
            ;
    };
    return $jar;
}

sub _get_cookie_jar_eval {
    my ($self) = @_;
    my $r = $self->{r};
    my $jar;
    eval { $jar = Apache2::Cookie::Jar->new($r) };
    if (my $err = $EVAL_ERROR) {
        my $ref = ref $err;
        my $is_apr_error = length($ref) >= 5 && substr($ref,0,5) eq 'APR::';
        DEBUG "caught error from jar of ref '$ref'";
        if ($is_apr_error) {
            if ($err == APR::Request::Error::NOTOKEN) {
                my $code = int($err);
                my $errstr = APR::Error::strerror($code);
                DEBUG sub { 
                    my $ip = $r->connection->remote_ip 

lib/Apache2/Controller/Methods.pm  view on Meta::CPAN

            else {
                DEBUG "rethrowing other APR::Error: '$err'";
                die $err;
            }
        }
        else {
            a2cx "unknown error (reftype '$ref') getting cookie jar: '$err'";
        }
    }
    DEBUG sub {
        my $cookie = $r->headers_in->{Cookie};
        $cookie = $cookie ? qq{$cookie} : '[no raw cookie string]';
        my @cookie_names;
        eval { @cookie_names = map qq{$_}, $jar->cookies };
        return "eval error reading cookie names: $EVAL_ERROR" if $EVAL_ERROR;
        return 
            "raw cookie header: $cookie\n"
            ."cookie names in jar:\n"
            .join('', map "  - $_\n", @cookie_names)
            ;
    };

lib/Apache2/Controller/Methods.pm  view on Meta::CPAN

L<Apache2::Controller>

L<Apache2::Controller::Session>

L<Apache2::Request>

L<Apache2::Module>

L<Apache2::Directives>

L<Apache2::Cookie>

=head1 AUTHOR

Mark Hedges, C<hedges +(a t)- formdata.biz>

=head1 COPYRIGHT AND LICENSE

Copyright 2008-2010 Mark Hedges.  CPAN: markle

This library is free software; you can redistribute it and/or modify

lib/Apache2/Controller/Session.pm  view on Meta::CPAN


=cut

use version;
our $VERSION = version->new('1.001.001');

=head1 SYNOPSIS

Set your A2C session subclass as a C<PerlHeaderParserHandler>.

This example assumes use of L<Apache2::Controller::Session::Cookie>.

 # get configuration directives:
 PerlLoadModule Apache2::Controller::Directives

 # cookies will get path => /somewhere
 <Location /somewhere>
     SetHandler              modperl

     # see Apache2::Controller::Dispatch for dispatch subclass info
     PerlInitHandler         MyApp::Dispatch

     # see Apache2::Controller::DBI::Connector for database directives

     A2C_Session_Cookie_Opts name  myapp_sessid
     A2C_Session_Class         Apache::Session::MySQL
     A2C_Session_Secret        jfa803m8cma083ak803kjf9-32

     PerlHeaderParserHandler  Apache2::Controller::DBI::Connector  MyApp::Session
 </Location>

In controllers, tied session hash is C<< $r->pnotes->{a2c}{session} >>.

In this example above, you implement C<get_options()> 
in your session subclass to return the options hashref to

lib/Apache2/Controller/Session.pm  view on Meta::CPAN

If you do not implement get_options(), it will try to create
directories to use Apache::Session::File
using C<< /tmp/a2c_sessions/<request hostname>/ >>
and C<< /var/lock/a2c_sessions/<request hostname> >>

=head1 DESCRIPTION

This is a module to make an L<Apache::Session> store available
to methods in your controllers.  It is not just a session id -
if you just need a tracking mechanism or a way to store data
in cookies, you should roll your own handler with L<Apache2::Cookie>.

Your session module uses an Apache2::Controller::Session tracker module 
as a base and you specify your L<Apache::Session> options either as
config variables or by implementing a method C<<getoptions()>>.

Instead of having a bunch of different options for all the different
L<Apache::Session> types, it's easier for me to make you provide
a method C<session_options()> in your subclass that will return a 
has of the appropriate options for your chosen session store.

lib/Apache2/Controller/Session.pm  view on Meta::CPAN

See
L<Apache2::Controller::DBI::Connector|Apache2::Controller::DBI::Connector>
for directives to set database connection in pnotes->{a2c}{dbh}.

Here's a code example for Location /somewhere above:

 package MyApp::Session;
 use strict;
 use warnings FATAL => 'all';

 use base qw( Apache2::Controller::Session::Cookie );

 use English '-no_match_vars';
 use Apache2::Controller::X;

 sub get_options {
     my ($self) = @_; 

     my $r = $self->{r};
     eval {
         $r->pnotes->{a2c}{dbh} ||= DBI->connect(

lib/Apache2/Controller/Session.pm  view on Meta::CPAN

But if you are potentially accessing the session contents without
setting it every time, you should just set a top-level timestamp
manually to indicate to L<Apache::Session> that you want 
things saved at the end of every request, but this may
slow you down on a busy site, so it is not the default.
See L<Apache2::Controller::Directives/A2C_Session_Always_Save>
and L<Apache::Session/BEHAVIOR>.

=head1 IMPLEMENTING TRACKER SUBCLASSES

See L<Apache2::Controller::Session::Cookie> for how to implement
a custom tracker subclass.  This implements C<$sid = get_session_id()> 
which gets a session id from a cookie, and C<set_session_id($sid)> 
which sets the session id in the cookie.

Perhaps some custom tracker subclass would implement
C<get_session_id()> to get the session_id out of the request 
query params, and C<set_session_id()> would push a C<PerlOutputFilterHandler>
to post-process all other handler output and append the session id param
onto any url links that refer to our site.  That would be cool...
release your own plug-in.

lib/Apache2/Controller/Session.pm  view on Meta::CPAN

use Apache2::Controller::Const qw( $DEFAULT_SESSION_SECRET );

=head2 process

The C<process()> method
attaches or creates a session, and pushes a PerlLogHandler
closure to save the session after the end of the request.

It sets the session id cookie
with an expiration that you set in your subclass as C<our $expiration = ...>
in a format that is passed to Apache2::Cookie.  (i.e. '3M', '2D', etc.)
Don't set that if you want them to expire at the end of the
browser session.

=cut

my %used;   # i feel used!

sub process {
    my ($self) = @_;
    my $r = $self->{r};

lib/Apache2/Controller/Session.pm  view on Meta::CPAN


Return the string which is the signature of the session id
plus the secret.

Override this in a subclass if you want to use something other
than SHA224.  See L<Digest::SHA/sha224_base64>.

The secret is the value associated with the directive A2C_Session_Secret,
or the default if that directive was not used.

See L<Apache2::Controller::Session::Cookie>,
L<Apache2::Controller::Directives/A2C_Session_Secret>,
L<Apache2::Controller::Const/$DEFAULT_SESSION_SECRET>.

=cut

sub signature {
    my ($self, $sid) = @_;
    a2cx "no sid param" if !defined $sid;

    my $secret = $self->{secret} 

lib/Apache2/Controller/Session.pm  view on Meta::CPAN

=over 4

=item A2C_Session_Class

=item A2C_Session_Opts

=back

=head1 SEE ALSO

L<Apache2::Controller::Session::Cookie>

L<Apache2::Controller::Dispatch>

L<Apache2::Controller>

L<Apache::Session>

=head1 THANKS

Thanks to David Ihern for edumacating me about the

lib/Apache2/Controller/Session/Cookie.pm  view on Meta::CPAN

package Apache2::Controller::Session::Cookie;

=head1 NAME

Apache2::Controller::Session::Cookie - track a sessionid with a cookie in A2C

=head1 VERSION

Version 1.001.001

=cut

use version;
our $VERSION = version->new('1.001.001');

=head1 SYNOPSIS

See L<Apache2::Controller::Session> for detailed setup example.

 package MyApp::Session;
 use base qw( Apache2::Controller::Session::Cookie );
 sub get_options {
     # ...
 }
 1;

=head1 DESCRIPTION

This module implements C<get_session_id> and C<set_session_id>
to get and set the session id from
a cookie.  

=head1 DIRECTIVES

=over 4 

=item A2C_Session_Cookie_Opts

=back

L<Apache2::Controller::Directives>

L<Apache2::Cookie>

=head1 METHODS

These methods must by implemented by any 
L<Apache2::Controller::Session> subclass.

=cut

use strict;
use warnings FATAL => 'all';

lib/Apache2/Controller/Session/Cookie.pm  view on Meta::CPAN


=head2 get_session_id

 my $sid = $self->get_session_id();

Get the session id from the cookie and verifies it.

Sets C<< $r->pnotes->{a2c}{session_id} >> to be the session id string.

See L<Apache2::Controller::Methods/get_cookie_jar>
and L<Apache2::Controller::Directives/A2C_Skip_Bogus_Cookies>.

If the cookie is not present or invalid, returns undef.

Warns the debug log if sig validation fails and returns undef.

=cut

sub get_session_id {
    my ($self) = @_;

    my %copts = %{ $self->get_directive('A2C_Session_Cookie_Opts') || { } }; 
    $copts{name} ||= $DEFAULT_COOKIE_NAME;
    my $cookie_name = $copts{name};
    
    my $jar = $self->get_cookie_jar();  # result might be undef
    my ($sid, $valid_sig, $cookie) = ();
    my $sig = qq{};

    if (defined $jar) {
        DEBUG "looking for cookie name '$cookie_name'";
        $cookie = $jar->cookies($cookie_name);

lib/Apache2/Controller/Session/Cookie.pm  view on Meta::CPAN

    if (defined $sid) {
        # if the session_id does not pass signature, return nothing
        $valid_sig = $self->signature($sid);

        if ($valid_sig ne $sig) {
            WARN "signature validation failed";
            return;
        }
    }

    # save sig and Apache2::Cookie object for this handler stage
    # (do not need to recompute the signature since we will use this one)
    $self->{session_valid_sig} = $valid_sig;
    
    return $sid;
}

=head2 set_session_id

 $self->set_session_id($sid);

lib/Apache2/Controller/Session/Cookie.pm  view on Meta::CPAN


=cut

sub set_session_id {
    my ($self, $session_id) = @_;
    DEBUG("Setting session_id '$session_id'");
    my $r = $self->{r};

    my $directives = $self->get_directives();

    my %opts = %{ $self->get_directive('A2C_Session_Cookie_Opts') || { } }; 
    $opts{name} ||= $DEFAULT_COOKIE_NAME;

    DEBUG(sub {"Creating session cookie with opts:\n".Dump(\%opts)});
    my $name = delete $opts{name};

    my $cookie = Apache2::Cookie->new( $r,
        -name           => $name,
        -value          => [ 
            $session_id, 
            ( $self->{session_valid_sig} || $self->signature($session_id) )
        ],
    );

    $cookie->$_($opts{$_}) for keys %opts;

    DEBUG("baking cookie '$cookie'");

lib/Apache2/Controller/Session/Cookie.pm  view on Meta::CPAN

}

=head1 SEE ALSO

L<Apache2::Controller::Session>

L<Apache2::Controller::Directives/Apache2::Controller::Session>

L<Apache2::Controller>

L<Apache2::Cookie>

=head1 AUTHOR

Mark Hedges, C<< <hedges at formdata.biz> >>

=head1 COPYRIGHT & LICENSE

Copyright 2008-2010 Mark Hedges, all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

This software is provided as-is, with no warranty 
and no guarantee of fitness
for any particular purpose.

=cut


1; # End of Apache2::Controller::Session::Cookie

t/conf/extra.last.conf.in  view on Meta::CPAN

# this file will be Include-d by @ServerRoot@/httpd.conf

# @ServerRoot@ = t directory

# where Apache2::Controller and the test application libs can be found
PerlSwitches -I@ServerRoot@/lib

PerlLoadModule Apache2::Request
PerlLoadModule Apache2::RequestRec
PerlLoadModule Apache2::RequestUtil
PerlLoadModule Apache2::Cookie
PerlLoadModule Apache2::RequestIO
PerlLoadModule Apache2::Module

PerlLoadModule Apache2::Controller::Directives
#PerlLoadModule Apache2::Controller::X
A2C_Render_Template_Path @ServerRoot@/templates/primary

# preload the module
<Location '/simple'>
    SetHandler modperl

t/conf/extra.last.conf.in  view on Meta::CPAN

<Location '/render/multipath'>
    A2C_Render_Template_Path @ServerRoot@/templates/primary @ServerRoot@/templates/secondary
</Location>

PerlLoadModule TestApp::Session::Session
<Location '/session'>
    SetHandler modperl
    PerlInitHandler TestApp::Session::Dispatch

    # in theory my testapp get_options should detect system-appropriate tempdirs
    A2C_Session_Cookie_Opts     name    testapp_sessid
    PerlHeaderParserHandler     TestApp::Session::Session
</Location>

# pre-load the connector to generate temporary database
PerlLoadModule TestApp::DBI::Connector
<Location '/dbi_connector'>
    # i cannot use the directives for setup, because i have to get a tempfile.
    # so i use a subclass

    SetHandler              modperl

t/conf/extra.last.conf.in  view on Meta::CPAN


PerlLoadModule Apache2::Controller::Auth::OpenID
PerlLoadModule TestApp::OpenID::Dispatch::Unprotected
PerlLoadModule TestApp::OpenID::Dispatch::Protected

<Location '/openid/unprotected'>
    SetHandler                  modperl
    PerlInitHandler             TestApp::OpenID::Dispatch::Unprotected

    PerlHeaderParserHandler     TestApp::DBI::Connector
    A2C_Session_Cookie_Opts     name    testapp_openid_sessid
    A2C_Session_Cookie_Opts     path    /openid
    PerlHeaderParserHandler     TestApp::Session::Session
</Location>

<Location '/openid/protected'>
    SetHandler                  modperl
    PerlInitHandler             TestApp::OpenID::Dispatch::Protected

    PerlHeaderParserHandler     TestApp::DBI::Connector
    A2C_Session_Cookie_Opts     name    testapp_openid_sessid
    A2C_Session_Cookie_Opts     path    /openid
    PerlHeaderParserHandler     TestApp::Session::Session

    # it turns out to be too weird to get LWPx::ParanoidAgent to work
    # so for our purposes we just use a regular LWP::UserAgent
    A2C_Auth_OpenID_LWP_Class   LWP::UserAgent
    A2C_Auth_OpenID_LWP_Opts    timeout 5

    # generate a server-wide constant random string for consumer secret?
    A2C_Auth_OpenID_Consumer_Secret

t/lib/TestApp/Session/Session.pm  view on Meta::CPAN

package TestApp::Session::Session;
use strict;
use warnings FATAL => 'all';
use English '-no_match_vars';
use File::Spec;
use Log::Log4perl qw( :easy );
use File::Temp qw( tempdir );

use base qw( Apache2::Controller::Session::Cookie );

my $tmpdir = tempdir( CLEANUP => 1 );

do {
    #DEBUG("Creating temp directory $_");
    mkdir $_ || die "Cannot create $_: $OS_ERROR\n";
} for grep !-d, 
    $tmpdir, 
    map File::Spec->catfile($tmpdir, $_), 
    qw( lock sess );

t/session.t  view on Meta::CPAN

my @CHARS = ('A'..'Z', 'a'..'z', 0 .. 9);
my %TD = (
    foo     => {
        boz     => [qw( noz schnoz )]
    },
    bar     => 'biz',
    floobie => join('', map $CHARS[int(rand @CHARS)], 1 .. 50),
);
my $testdata_dump = Dump(\%TD);

use HTTP::Cookies;
my $jar = HTTP::Cookies->new();

plan tests => 12, need_lwp;
my $ua = Apache::TestRequest::user_agent(
    cookie_jar              => $jar, 
    requests_redirectable   => 0,
);
Apache::TestRequest::lwp_debug(2);

use TestApp::Session::Controller;

t/session.t  view on Meta::CPAN

$response_testdata = Dump($session->{testdata});
#diag($response_testdata);


ok t_cmp($response_testdata, $testdata_dump, "Read data after error unchanged.");

my $old_sess_id = q{};
$jar->scan(sub { 
    diag("lame:\n".Dump(\@_));
    $old_sess_id ||= $_[2];
}); # See HTTP::Cookie

diag("session id was '$old_sess_id'");
diag("set raw cookie val to 1 in headers_out (invalid cookie freeze/thaw bug)");
my ($cookie_domain) = keys %{$jar->{COOKIES}}; # ('highlander.therecanbeonly1.com')
diag("cookie domain is '$cookie_domain'");

my $full_url = Apache::TestRequest::module2url('', { path => "$url/read" });
diag("full_url: '$full_url'");

$response = $ua->get($full_url);

t/session.t  view on Meta::CPAN

$jar->scan(sub { $doublecheck_sess_id ||= $_[2] });
diag('double-check');
ok t_cmp($old_sess_id, $doublecheck_sess_id,
    'double-check sess id is the same across requests',
);

diag("SPOCK: '$ua'");
$jar->clear();
diag("KIRK: ".Dump($jar));

$response = $ua->get($full_url, 'Set-Cookie3' => qq{1; path="$cookie_path"; domain=$cookie_domain; discard; version=0});

diag("response code:\n".$response->code);

diag("as_string:\n".$response->as_string);

diag("UHURA: ".Dump($jar));

my $new_sess_id = q{};
$jar->scan(sub { $new_sess_id ||= $_[2] });



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