Session Management with Mason

This Perl-based web helper and MySQL work together to let you quickly build a user registration system for your web site.
Apache::Storable and Mason

Each time a user's browser sends an HTTP request to the web server, it sends whatever cookies have been stored by that domain. So if a cookie was set by cnn.com, my browser will return only that cookie—which is, after all, simply a name-value pair—when I visit http://www.cnn.com/ again.

The cookie version of Apache::Storable takes advantage of this by storing a unique identifier in a cookie. This unique identifier corresponds to the id column in the sessions table. This allows us to retrieve any data that have been stored in a_session. Because a_session is defined to be infinitely long, the amount of data we can store is limited only by our database and our file system.

Data stored in table sessions by Apache::Session is available to programs via the global %session hash. %session is created anew for each incoming HTTP request, and refers to only the data stored in a_session. Storing something in %session places it in the a_session column, and retrieving something from %session gets the value from a_session. Assuming that the variables $first_name, $last_name and $email contain the appropriate pieces of information, we could store them reliably with the following lines of Perl:

$session{first_name} = $first_name;
$session{last_name} = $last_name;
$session{email} = $email;

Since each user (actually, each session) is stored in a separate row of the database, we do not need to worry about users clashing with each other.

In order for sessions to work, we must make a connection between the Apache::Session::DBI module and the corresponding sessions table on disk. This connection must take into account three different possibilities: (a) that the user sends us a valid ID cookie, (b) that the user sends us an invalid ID cookie, and (c) that the user sends us no ID cookie at all.

The first case is the easiest; the program merely needs to re-establish the connection between %session and the appropriate row in sessions, using Perl's “tie” mechanism. In the second case, the program must create a new session if it could not re-establish a previous one. And if the user sends no cookie at all, then we must create a new row in sessions, attach a unique ID to it and send that unique ID to the user's browser in the form of a cookie.

When working with Mason, we put all this in our start-up file. This file, which the Mason documentation calls handler.pl (but which I prefer to call mason.pl), defines all of Mason's main behaviors and allows us to define global variables that other elements of the system will require. Defining %session in mason.pl also ensures that it is available in all Mason components. See Listing 1 for a simple example of mason.pl for a site that wants to include sessions. (Much of Listing 1 comes straight from the Mason documentation.)

Listing 1

The most important part of this file is a call to Perl's eval command. eval comes in two forms, one of which takes a code block as an argument, and forms as a primitive form of error-checking. Inside our code block, we attempt to use Perl's tie command to connect the hash %HTML::Mason::Commands::session to the Apache::Session::DBI module. Tying these two together means that the default storage and retrieval mechanism associated with hashes no longer applies for %session—when we retrieve or modify its value, one or more methods in Apache::Session::DBI will take over:

eval {
    tie %HTML::Mason::Commands::session, 'Apache::Session::DBI',
        ($cookies{'AF_SID'} ? $cookies{'AF_SID'}->value() : undef),
        {
         DataSource => $dbsource,
         UserName => $dbuser,
         Password => $dbpass
        };
};

If this eval is unsuccessful, the variable $@ will contain the error message. Here, we test to see if the object exists in the data store. If so, then we assign the user a new session:

if ( $@ )
{
    if ( $@ =~ m#^Object does not exist in the data store# )
    {
        tie %HTML::Mason::Commands::session,
'Apache::Session::DBI',
            undef,
            {
             DataSource => $dbsource,
             UserName => $dbuser,
             Password => $dbpass
            };
        undef $cookies{'AF_SID'};
       }
}
Finally, if the user does not pass us any identifying AF_SID cookie at all, we create a new one and tell mod_perl to send it along with the rest of the outgoing headers:
if ( !$cookies{'AF_SID'} )
{
    my $cookie =
       new CGI::Cookie(-name => 'AF_SID',
                       -value =>
                       $HTML::Mason::Commands::session{_session_id},
                       -path => '/',);
    $r->header_out('Set-Cookie', => $cookie);
}
Once these are in place, any Mason component can store and retrieve information in %session. Apache::Session's use of the Storable module means that references and complex data structures (such as arrays of arrays, and hashes of hashes) can be stored in %session without us having to worry about losing data.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix