Apache-AxKit-Plugin-Session

 view release on metacpan or  search on metacpan

lib/Apache/AxKit/Plugin/Session.pm  view on Meta::CPAN

}

sub restore_params ($) {
    my ($self) = @_;
    $self->debug(3,"--------- restore_params(".join(',',@_).")");
    my $r = Apache->request();
    my $session = $r->pnotes('SESSION') || return $self->orig_restore_params();
    return $self->orig_restore_params() unless $$session{'auth_params'};

    my @in = @{$$session{'auth_params'}};
    my $out = new Apache::Table($r);
    while (@in) {
        $out->add($in[0],$in[1]);
        shift @in; shift @in;
    }
    $r->pnotes('INPUT',$out);
    delete $$session{'auth_params'};
}


sub _cleanup_session ($$) {
    my ($self, $session) = @_;
    $self->debug(3,"--------- _cleanup_session(".join(',',@_).")");
    untie %{$session};
    undef %{$session};
}

sub _get_session_from_store($$;$) {
    my ($self, $r, $session_id) = @_;
    $self->debug(3,"--------- _get_session_from_store(".join(',',@_).")");
    my $auth_name = $r->auth_name || 'AxKitSession';
    my @now = localtime;
    my $session = {};
    my $dir = $r->dir_config($auth_name.'Dir') || '/tmp/sessions';
    my $absdir = $dir;
    $absdir = $r->document_root.'/'.$dir if substr($dir,0,1) ne '/';
    my $args = {
            Directory => $absdir,
            DataSource => $dir,
            FileName => $absdir.'/sessions.db',
            LockDirectory => $absdir.'/locks',
            DirLevels => 3,
            CounterFile => sprintf("$absdir/counters/%04d-%02d-%02d", $now[5]+1900,$now[4]+1,$now[3]),
            $r->dir_config->get($auth_name.'ManagerArgs'),
    };
    eval {
        eval "require ".($r->dir_config($auth_name.'Manager')||'Apache::Session::File') or die $@;
        tie %{$session}, $r->dir_config($auth_name.'Manager')||'Apache::Session::File', $session_id, $args;
    };
    die "Session creation failed. Depending on which session module you use, make sure that directories $absdir, $absdir/locks or $absdir/counters, or database $dir exist and are writable. The error message was: $@" if $@ && !defined $session_id;
    return $session;
}

sub _get_session($$;$) {
    my ($self, $r, $session_id) = @_;
    my $auth_name = $r->auth_name || 'AxKitSession';
    $self->debug(3,"--------- _get_session(".join(',',@_).")");
    my $dir = $r->dir_config($auth_name.'Dir') || '/tmp/sessions';
    my $expire = ($r->dir_config($auth_name.'Expire') || 30) / 5 + 1; #/
    my $check = $r->dir_config($auth_name.'IPCheck');
    my $remote = ($check == 1?($r->header_in('X-Forwarded-For') || $r->connection->remote_ip):
        $check == 2?($r->connection->remote_ip =~ m/(.*)\./):
        $check == 3?($r->connection->remote_ip):
        '');
    my $guest = $r->dir_config($auth_name.'Guest') || 'guest';

    my $mr = $r;
    # find existing session - a bit more complicated than usual since the request could be in
    # different stages of authentication
    if (1 || $session_id) {
        if ($mr->main && (!$mr->pnotes('SESSION') || $mr->pnotes('SESSION')->{'_session_id'} ne $session_id)) {
            $mr = $mr->main;
            #$self->debug(5,"main: ".$mr->main.", sid=".($mr->pnotes('SESSION')||{})->{'_session_id'});
        }
        #$self->debug(5,"prev: ".$mr->prev.", sid=".($mr->pnotes('SESSION')||{})->{'_session_id'});
        while ($mr->prev && (!$mr->pnotes('SESSION') || $mr->pnotes('SESSION')->{'_session_id'} ne $session_id)) {
            $mr = $mr->prev;
            #$self->debug(5,"prev: ".$mr->prev.", sid=".($mr->pnotes('SESSION')||{})->{'_session_id'});
            if ($mr->main && (!$mr->pnotes('SESSION') || $mr->pnotes('SESSION')->{'_session_id'} ne $session_id)) {
                $mr = $mr->main;
                #$self->debug(5,"main: ".$mr->main.", sid=".($mr->pnotes('SESSION')||{})->{'_session_id'});
            }
        }
        $mr ||= $r;
    }

    my $session = {};

    # retrieve session from a previous internal request
    $session = $mr->pnotes('SESSION') if $mr->pnotes('SESSION'); # and $session_id;
    $self->debug(5,"checkpoint beta, session={".join(',',keys %$session)."}");
    # create/retrieve session, providing parameters for several common session managers
    if (!keys %$session) {
        $session = $self->_get_session_from_store($r,$session_id);
        $r->register_cleanup(sub { _cleanup_session($self, $session) });
        if ($@ && $guest) {
            $self->debug(3, "sid $session_id invalid: $@");
            return (undef, 'bad_session_provided');
        }
    }
    $self->debug(5,"checkpoint charlie, sid=".$$session{'_session_id'}.", keys = ".join(",",keys %$session));

    $$session{'auth_access_user'} = $guest unless exists $$session{'auth_access_user'};
    $$session{'auth_first_access'} = time() unless exists $$session{'auth_first_access'};
    $$session{'auth_expire'} = $expire unless exists $$session{'auth_expire'};

    $expire = $$session{'auth_expire'};
    $self->debug(4,'UID = '.$$session{'auth_access_user'});
    # check if remote host changed or session expired; guest sessions never expire
    if (exists $$session{'auth_remote_ip'} && $remote ne $$session{'auth_remote_ip'}) {
        $self->debug(3, "ip mispatch");
        return (undef, 'ip_mismatch') if ($$session{'auth_access_user'} && $$session{'auth_access_user'} ne $guest);
    } elsif ($$session{'auth_access_user'} && $$session{'auth_access_user'} ne $guest && exists $$session{'auth_last_access'} && int(time()/300) > $$session{'auth_last_access'}+$expire) {
        $self->debug(3, "session expired");
        %$session = ();
        eval { tied(%$session)->delete };
        return (undef, 'session_expired');
    } elsif (!exists $$session{'auth_remote_ip'}) {
        $$session{'auth_remote_ip'} = $remote;
    }

lib/Apache/AxKit/Plugin/Session.pm  view on Meta::CPAN

C<login.xsp> must call <auth:login>, see L<AxKit::XSP::Auth>.

B<Advanced protection:>

Allow access to user JohnDoe and to user JaneDoe:

        require user JohnDoe JaneDoe

Allow access to members of group internal and mambers of group admin:

        require group internal admin

Allow access to members with level 42 or higher:

        require level 42

Allow access to all users except guest:

        require not user guest

Allow access to all users who are in group powerusers AND
 either longtimeusers or verylongtimeusers (compare "group" above):

	require combined group powerusers group "longtimeusers verylongtimeusers"

Allow access if (group == longtimeusers AND (group == powerusers OR level >= 10))

        require combined group longtimeusers alternate "group powerusers level 10"

You can have as many "require" lines as you want. Access is granted if at least one
rule matches.

=head2 Advanced options

How long is a session valid when idle? (minutes, must be multiple of 5)

    PerlSetVar AxKitSessionExpire 30

Which session module should be used?

    PerlSetVar AxKitSessionManager Apache::Session::File

Where should session files (data and locks) go?

    PerlSetVar AxKitSessionDir /tmp/sessions

Do you want global data? ($r->pnotes('GLOBALS') and AxKit::XSP::Globals)

    PerlSetVar AxKitSessionGlobal Tie::SymlinkTree,/tmp/globals

How's the "guest" user called?

    PerlSetVar AxKitSessionGuest guest

Want to check the IP address for sessions?

    PerlSetVar AxKitSessionIPCheck 1

Beware that IP checking is dangerous: Some people have different IP addresses
for each request, AOL customers for example. There are several values for you
to choose: 0 = no check; 1 = use numeric IP address or X-Forwarded-For, if present;
2 = use numeric IP address with last part stripped (/24 subnet); 3 = use
numeric IP address

=head2 Cookie options

Look at L<Apache::Cookie>. You'll quickly get the idea:

    PerlSetVar AxKitSessionPath /
    PerlSetVar AxKitSessionExpires +1d
    PerlSetVar AxKitSessionDomain some.domain
    PerlSetVar AxKitSessionSecure 1

Path can only be set to "/" if using URL sessions. Do not set "AxKitSessionExpires",
since the default value is best: it keeps the cookies until the user closes his
browser.

Disable cookies: (force URL-encoded sessions)

    PerlSetVar AxKitSessionNoCookie 1

=head2 Internal options

DANGER! Do not fiddle with these unless you know what you are doing.

Want a different redirector location? (default is '/redirect')

    <Perl>$Apache::AxKit::Plugin::Session::redirect_location = "/redir";</Perl>

Debugging:

    PerlSetVar AxDebugSession 5

Prefix to session ID in URLs:

    PerlSetVar SessionPrefix Session-


=head1 DESCRIPTION

WARNING: This version is for AxKit 1.7 and above!

This module is an authentication and authorization handler for Apache, designed specifically
to work with Apache::AxKit. It should be generic enough to work without it as well, only
much of its comfort lies in a separate XSP taglib which is distributed alongside this module.
It combines authentication and authorization in Apache::AuthCookieURL style with session management
via one of the Apache::Session modules. It should even work with Apache::Session::Counted. See those
manpages for more information, but be sure to note the differences in configuration!

In addition to Apache::AuthCookieURL, you get:

=over 4

=item * session data in $r->pnotes('SESSION')

=item * global application data in $r->pnotes('GLOBAL')

=item * sessions without the need to login (guest account)

=item * automatic expiration of sessions after 30 minutes (with
    automatic degradation to guest account, if any)

lib/Apache/AxKit/Plugin/Session.pm  view on Meta::CPAN


Sets the session expire timeout in minutes. The value must be a multiple of 5.

Example: PerlSetVar AxKitSessionExpire 30

Note that the session expire timeout (AxKitSessionExpire) is different from the cookie expire
timeout (AxKitSessionExpires).  You should not set the cookie expire timeout unless you have
a good reason to do so. 

=item * AxKitSessionManager

Specifies the module to use for session handling. Directly supported are File,
DB_File, Counted, and all DB server modules if connecting anonymously. For all
other configurations (including Flex), you need AxKitSessionManagerArgs, too.

Example: PerlSetVar AxKitSessionManager Apache::Session::Counted

=item * AxKitSessionManagerArgs

List of additional session manager parameters in the form: Name Value. Use
with PerlAddVar.

Example: PerlAddVar AxKitSessionManagerArgs User foo

=item * AxKitSessionDir

The location where all session files go, including lockfiles. If you are using
a database server as session backend, this is the server specific db/table string.

Example: PerlSetVar AxKitSessionDir /home/sites/site42/data/session

=item * AxKitSessionGuest

The user name to be recognized as guest account. Setting this to a false
value (the default) disables automatic guest login. If logins are used at
all, this is the only way to get session management for unknown users. If
no logins are used, this MUST be set to some value.

Example: PerlSetVar AxKitSessionGuest guest

=item * AxKitSessionGlobal

Often you want to share a few values across all sessions. That's what
$r->pnotes('GLOBALS') is for: It works just like the session hash, but it is
shared among all sessions. In previous versions, globals were always available,
but since many users didn't care and there were grave problems in the old
implementation, behaviour has changed: You get a fake GLOBALS hash unless you
specify the sotrage method to use using this setting. It takes a comma-separated
list of "tie" parameters, starting with the name of the module to use. Do not use
spaces, and you should use a module that works with a minimum of locking, like
L<Tie::SymlinkTree>. Otherwise, you could get server lockups or bad performance
(which is what you often got in previous versions as well).

Example: PerlSetVar AxKitSessionGlobal Tie::SymlinkTree,/tmp/globals

=item * AxKitSessionIPCheck

The level of IP matching in sessions. A session id is only valid when the
connection is coming from the same remote address. This setting lets you
adjust what will be checked: 0 = nothing, 1 = numeric IP address or
HTTP X-Forwarded-For header, if present, 2 = numeric IP address with last
part stripped off, 3 = whole numeric IP address.

Example: PerlSetVar AxKitSessionIPCheck 3

=back

=head2 Programming interface

By subclassing, you can modify the authorization scheme to your hearts desires. You can store
directory and file permissions in an RDBMS and you can invent new permission types.

To store and retrieve permissions somewhere else than in httpd.conf, override 'get_permissions'
and 'set_permissions'. 'get_permissions' should return a list of arrayrefs, each one
containing a (type,argument-string) pair (e.g., the equivalent of a 'require group foo bar'
would be ['group','foo bar']). Access is granted if one of these requirements are met.
'set_permissions' should store such a list somewhere, if dynamic modification of permissions
is wanted. For more details, read the source.

For a new permission type 'foo', provide 3 subs: 'foo', 'pack_requirements_foo' and
'unpack_requirements_foo'. sub 'foo' should return OK or FORBIDDEN depending on the parameters
and the session variable 'auth_access_foo'. The other two subs can be aliased to
'default_(un)pack_requirements' if your 'require foo' parses like a 'require group'. Read the
source for more information.

=head1 WARNING

URL munging has security issues.  Session keys can get written to access logs, cached by
browsers, leak outside your site, and can be broken if your pages use absolute links to other
pages on-site (but there is HTTP Referer: header tracking for this case). Keep this in mind.

The redirect handler tries to catch the case of external redirects by changing them into
self-refreshing pages, thus removing a possibly sensitive http referrer header. This
won't work from mod_perl, so use Apache::AuthCookieURL's fixup_redirect instead. If you are
adding hyperlinks to your page, change http://www.foo.com to /redirect?url=http://www.foo.com

=head1 REQUIRED

Apache::Session, AxKit 1.7, mod_perl 1.2x

=head1 AUTHOR

Jörg Walter E<lt>jwalt@cpan.orgE<gt>.

=head1 VERSION

1.00

=head1 SEE ALSO

L<Apache::AuthCookie>, L<Apache::AuthCookieURL>, L<Apache::Session>,
L<Apache::Session::File>, L<Apache::Session::Counted>, L<AxKit::XSP::Session>,
L<AxKit::XSP::Auth>, L<AxKit::XSP::Globals>, L<Tie::SymlinkTree>

=cut





( run in 2.409 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )