[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dgAIS] new version also supports POST cgi (take 2)

From: david nicol
Subject: [dgAIS] new version also supports POST cgi (take 2)
Date: Sat, 06 Jul 2002 21:57:30 -0500

it is very strange that POST form submissions do not appear to
deliver the full measure of cookies, so the session does a
handshake for each form submission.  The attached AIS client module
saves POST data in its session database and writes it into STDIN
later, by opening a pipe and forking.

It is used in the form handler at
package CGI::AIS::Session;

 use strict;

use vars qw{ *SOCK @ISA @EXPORT $VERSION };

require Exporter;

 @ISA = qw(Exporter);
 @EXPORT = qw(Authenticate);

 $VERSION = '0.01';

use Carp;

use Socket qw(:DEFAULT :crlf);
use IO::Handle;
sub miniget($$$$){
        my($HostName, $PortNumber, $Desired, $agent)  = @_;
        $PortNumber ||= 80;
        my $iaddr       = inet_aton($HostName)  || die "Cannot find host named 
        my $paddr       = sockaddr_in($PortNumber,$iaddr);
        my $proto       = getprotobyname('tcp');
        socket(SOCK, PF_INET, SOCK_STREAM, $proto)  || die "socket: $!";
        connect(SOCK, $paddr)    || die "connect: $!";

        print SOCK
                "GET $Desired HTTP/1.1$CRLF",
                # Do we need a Host: header with an "AbsoluteURI?"
                # not needed:
                # but this is trumped by an Apache error message invoking 
RFC2068 sections 9 and 14.23
                "Host: $HostName$CRLF",
                "User-Agent: $agent$CRLF",
                "Connection: close$CRLF",



sub Authenticate{

        my %Param = (agent => 'AISclient', @_);
        my %Result;
        my $AISXML;

        my ($Cookie) = ($ENV{HTTP_COOKIE} =~  /AIS_Session=(\w+)/);
        tie my %Session, $Param{tieargs}->[0],
                or croak "failed to tie @{$Param{tieargs}}";

        # make Cookie imply its validity
        if ($Cookie and ! $Session{$Cookie}){
                $Cookie = undef;


        my $OTUkey;
        my $SessionKey;
        if ($ENV{QUERY_STRING} =~ /AIS_OTUkey=(\w+)/){
           $OTUkey = $1;
                if ($ENV{QUERY_STRING} =~ /AIS_POST_key=(\w+)/){
                        my $PostKey = $1;
                        pipe(POSTREAD,POSTWRITE) or die "Cannot create pipe: 
                        if (fork){
                                # we are in parent
                                close POSTWRITE;
                                open STDIN, "<&POSTREAD";

                                # in child -- write POSTdata to pipe and exit
                                close POSTREAD;
                                print POSTWRITE '&',$Session{$PostKey};
                                close POSTWRITE or die "$$: Error closing 
                                delete $Session{$PostKey};
           my ($method, $host, $port, $path) =
             ($Param{aissri} =~ m#^(\w+)://([^:/]+):?(\d*)(.+)$#)
              or die "Could not get meth,hos,por,pat from <$Param{aissri}>";
           unless ($method eq 'http'){
                croak "aissri parameter must begin 'http://' at this time";

           # my $Response = `lynx -source $Param{aissri}query?$OTUkey$CRLF$CRLF`
           my $Response = miniget $host, $port,
           "$Param{aissri}query?$OTUkey", $Param{agent};

           $SessionKey = join('',time,(map {("A".."Z")[rand 26]}(0..19)));
           print "Set-Cookie: AIS_Session=$SessionKey; 
           ($AISXML) =
                $Response =~ m#<aisresponse>(.+)</aisresponse>#si
                   or die "no <aisresponse> element from 
           $Session{$SessionKey} = $AISXML;

        }elsif (!$Cookie){
                my $PostString = '';
                # if ($ENV{REQUEST_METHOD} eq 'POST' and !eof){
                if ($ENV{REQUEST_METHOD} eq 'POST' ){
                        my $PostKey = join('',time,(map {("A".."Z")[rand 
                        $Session{$PostKey} = join('',(<>));
                        $PostString = "AIS_POST_key=$PostKey&";

                print "Location: 
        }else{ # We have a cookie
                $AISXML = $Session{$Cookie};
                delete  $Session{$Cookie} if $ENV{QUERY_STRING} eq 'AIS_LOGOUT';

        foreach (qw{
                $AISXML =~ m#<$_>(.+)</$_>#si or next;
                $Result{$_} = $1;

        if ( defined($Param{timeout})){
                my $TO = $Param{timeout};
                delete @Session{ grep { time - $_ > $TO } keys %Session };


        #Suppress caching NULL and ERROR
        if( $Result{identity} eq 'NULL' or $Result{identity} eq 'ERROR'){
                print "Set-Cookie: AIS_Session=$CRLF";
                $SessionKey and delete $Session{$SessionKey} ;
        return \%Result;

# Preloaded methods go here.


=head1 NAME

CGI::AIS::Session - Perl extension to manage CGI user sessions with external 
identity authentication via AIS

  use DirDB;    # or any other concurrent-access-safe
                # persistent hash abstraction
  use CGI::AIS::Session;
  my $Session = Authenticate(
             aissri <= '',
             tieargs <= ['DirDB', './data/Sessions'],
             XML <= ['name','age','region','gender'],
             agent <= 'Bollow', # this is the password for the AIS service, if 
             ( $$ % 100 ? () : (timeout <= 4 * 3600)) # four hours
  if($$Session{identity} eq 'NULL'){
        print "Location:\n\n";
  }elsif($Session->{identity} eq 'ERROR'){
        print "Content-type: text/plain\n\n";
        print "There was an error with the authentication layer",
              " of this web service: $Session->{error}\n\n",
              "please contact $ENV{SERVER_ADMIN} to report this.";
  tie my %UserData, 'DirDB', "./data/$$Session{identity}";


Creates and maintains a read-only session abstraction based on data in
a central AIS server.

The session data provided by AIS is read-only.  A second
database keyed on the identity provided by AIS should be
used to store persistent local information such as shopping cart
contents. This may be repaired in future releases, so the 
session object will be more similar to the session objects
used with the Apache::Session modules, but for now, all the
data in the object returned by C<Authenticate> comes from the
central AIS server.

On the first use, the user is redirected to the AIS server
according to the AIS protocol. Then the identity, if any,
is cached
under a session key in the session database as tied to by
the 'tieargs' parameter.

This module will create a http cookie named AIS_Session.

Authenticate will croak on aissri methods other than
http in this version.

Additional expected XML fields can be listed in an XML parameter.

If a 'timeout' paramter is provided,  Sessions older than
the timeout get deleted from the tied sessions hash.

'ERROR' and 'NULL' identities are not cached.

Internally, the possible states of this system are:

no cookie, no OTU

Only the last one results in returning a session object. The
other two cause redirection.

if a query string of AIS_LOGOUT is postpended to any url in the
domain protected by this module, the session will be deleted before
it times out.

=head1 EXPORTS

the Authenticate routine is exported.

=head1 AUTHOR

David Nicol, address@hidden

=head1 SEE ALSO

The Apache::Session family of modules on CPAN


reply via email to

[Prev in Thread] Current Thread [Next in Thread]