Sophie

Sophie

distrib > Mandriva > 2008.0 > x86_64 > by-pkgid > 5a70b7657dbee2ef80af48a16d37ff12 > files > 2

apache-mod_auth_form-2.05-3mdv2008.0.src.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
	<meta name="Keywords" content="mod_auth_form apache apache2 form-based form based authentication authorization module mysql session group" />
	<meta name="Description" content="Mod_auth_form performs form-based authorization using MySQL, session, and group management." />
	<meta name="Author" content="Aaron Arthurs <ajarthu@uark.edu>" />
	<meta name="Robots" content="all" />
	<title>Apache2 Form-Based Authorization</title>
	<link rel="stylesheet" type="text/css" href="index.css" />
</head>

<body>
	<center>
	   <h1>Apache2 Module 'mod_auth_form'</h1>
	   <h4><i>Current Version: 2.04</i></h4>
	</center>
	<h2>Contents</h2>
	<ul>
		<li><a href="#OVERVIEW">Overview</a></li>
		<li><a href="#REQUIREMENTS">Requirements</a></li>
		<li><a href="#DOWNLOADS">Downloads</a></li>
		<li><a href="#INSTALLATION">Minimum Installation and Configuration</a></li>
		<li><a href="#EXAMPLES">Examples</a></li>
		<ul>
			<li><a href="#EX_SIMPLE">A Simple Restricted Area</a></li>
			<li><a href="#EX_COMPLEX">A Complex Member's Area</a></li>
			<li><a href="#EX_LOGOUT">Logging Out</a></li>
		</ul>
		<li><a href="#REFERENCE">Configuration Reference</a></li>
		<li><a href="#IDEAS">Ideas for Future Releases</a></li>
		<li><a href="#CONTRIBUTE">Contributing</a></li>
		<li><a href="#CONTRIBUTORS">Contributors</a></li>
		<li><a href="#COPYRIGHT">Copyright</a></li>
	</ul>
	<hr />
	<h2><a name="OVERVIEW"></a>Overview</h2>
	<div>
		This module is a form-based authorization module
		based on '<a href="http://www.heuer.org/mod_auth_mysql/">mod_auth_mysql</a>'
		and
		'<a href="http://www.perl-studio.com/mod_auth_sim/">mod_auth_sim</a>'.
		It is used to place access restrictions on a
		per-directory, per-user-request basis using session management.
		The module uses a MySQL database to retrieve users' group
		membership, maintain and validate users' sessions, and
		optionally track user activity.
		<br /><br />
		The mechanics of the module works in the following way. A
		web client (user) requests for a restricted page/directory.
		The module sends back a 'Page Has Moved' error, pointing
		the client to the page containing a login form. Through
		server-side scripting, a session is created in the MySQL
		database and the client (i.e. cookies or query string).
		The session itself consists of a unique, random, and
		temporary ID that is associated with a user. The client
		then makes the same request along with the session ID
		(SID) and the user ID (UID). The module compares and
		validates the two IDs against the IDs stored in the MySQL
		database. If successful, the module sends back the requested
		page; otherwise, the module once again sends back the
		'Page Has Moved' error page. In addition (if specified),
		the module will also validate the user's group membership
		and act accordingly.
		<br /><br />
		<b>Additional Notes:</b>
		<br />
		1) This module does not verify username and passwords (not
		yet). The verification is left up to the web developer via
		server-side scripting. For example, if .htpasswd files
		are used, a Perl script can be written to verify a user's
		input against a .htpasswd file; if the user is verified, the
		same Perl script will create a session in the user's browser
		(cookies or query string) and in a MySQL database.
		<br /><br />
		2) Do not use Apache's basic authentication directives with
		this module (exceptions are 'AuthType Basic' and 'AuthName
		"Name"'). Doing so may cause Apache to use basic authentication
		whenever a user accesses a restricted page. (See
		<a href="http://httpd.apache.org/docs-2.0/mod/mod_auth.html">mod_auth</a>
		and similiar modules).
		<br /><br />
		3) To turn off 'mod_auth_form' for certain directories, add
		the directive "AuthFormAuthoritative Off" to the directory
		container. This is only useful when applying a different
		authentication module (e.g. mod_auth) to a directory under
		mod_auth_form's control (usually sub-directories).
		<br /><br />
		4) This module requires SELECT permission at minimum. For
		'AuthFormSessionTimeout', UPDATE is also required. For
		the tracking table, the module also requires INSERT, DELETE,
		and UPDATE permissions.
		<br /><br />
		5) Enclose MySQL keywords with backticks (`) when using the 'AuthFormMySQL*'
		directives,. For example, "AuthFormMySQLFieldUID SELECT" needs to
		be "AuthFormMySQLFieldUID `SELECT`".
		<br /><br />
		6) Use caution when specifying a fixed number of seconds
		for AuthFormSessionAutoRefresh. This option does not work
		well with inline frames that point to other
		auto-refreshing documents. If you have a restricted page
		with inline frames, you may need to specify
		"AuthFormPageAutoRefresh mypage.html" for each framed
		document.
		<br /><br />
		7) 'AuthFormMySQLTableGID' should refer to a join table
		if each user is to be associated with multiple groups
		(where 'AuthFormMySQLFieldUID' and 'AuthFormMySQLFieldGID'
		are the join table attributes). Although this module allows
		multiple values for the 'AuthFormMySQLFieldGID' field,
		use only one value per record. This multi-value feature
		will be removed in the next major version (3.0).
		<br /><br />
		8) This module may be renamed to mod_authnz_form for the next
		major version (3.0). The next major version (and maybe the
		2.x series) will support authentication via HTTP POST along
		with session management, hence the 'nz' after 'auth'.
		<br />
	</div>
	<hr />
	<h2><a name="REQUIREMENTS"></a>Requirements</h2>
	<ul>
		<li><a href="http://httpd.apache.org">Apache 2.0 Web Server</a></li>
		<li><a href="http://dev.mysql.com/downloads/">MySQL 4.1 or greater</a></li>
		<li>Server-Side Scripting Processor
		<ul>
			<li>Comes with MySQL-Capable API (optionally MySQLi)</li>
			<li><a href="http://www.rubyonrails.org">Ruby on Rails</a> looks promising</li>
			<li>Perhaps <a href="http://www.php.net/downloads.php">PHP 5/4</a></li>
		</ul>
	</ul>
	<h2><a name="DOWNLOADS"></a>Downloads</h2>
	<ul>
		<li>Version 2.04</li>
		<ul>
			<li><a href="download.php?download=v2_04%2Fmod_auth_form-2.04-src.tar.gz">Source Code</a> (<a href="download.php?download=v2_04%2Fmod_auth_form-2.04-src.tar.gz.md5">MD5SUM</a>)</li>
			<li><a href="download.php?download=v2_04%2Fmod_auth_form-2.04-win32.zip">Win32 Binaries</a> (<a href="download.php?download=v2_04%2Fmod_auth_form-2.04-win32.zip.md5">MD5SUM</a>)</li>
			<li>Bugs:</li>
			<ul>
				<li>BUG #7: MySQL SSL directives mismatch the internal data structure (see PATCH #4).</li>
				<li>BUG #8: Query string/cookie values are not decoded (see PATCH #6).</li>
				<li>BUG #9: The apostrophe from the query string/cookie values is not escaped (see PATCH #6).</li>
			</ul>
			<li>Patches:</li>
			<ul>
				<li>PATCH #3: <a href="download.php?download=v2_04/mod_auth_form-2.04-configure_apr_hooks.patch">apr/apr-util RPM include layout</a>: configure looks for apr_hooks.h instead of apr.h</li>
				<li>PATCH #4: <a href="download.php?download=v2_04/mod_auth_form-2.04-mysql_ssl_conf_mismatch_fix.patch">BUGFIX #7</a>: correct the MySQL SSL directive mismatch.</li>
				<li>PATCH #5: <a href="download.php?download=v2_04/mod_auth_form-2.04-mysql_ssl_check.patch">MySQL SSL Support Check</a>: check for mysql_ssl_set during configuration. Disable MySQL SSL support if not present.</li>
				<li>PATCH #6: <a href="download.php?download=v2_04/mod_auth_form-2.04-escape_value_apostrophe.patch">BUGFIX #8 and #9</a>: Decode query string/cookie values and escape the apostrophe if necessary.</li>
			</ul>
			<li>Changes:</li>
			<ul>
				<li>Fixed some Apache 2.2.x compatibility issues</li>
				<li>Added <b>AuthFormMySQLSocket</b></li>
				<li>Added MySQL SSL directives (mimics parameters in mysql_ssl_set)</li>
				<li>Now using libtool versioning</li>
				<li>'make install' no longer:</li>
				<ul>
					<li>Restarts the Apache2 server</li>
					<li>Edits the main configuration file</li>
				</ul>
			</ul>
		</ul>
		<li>Version 2.03</li>
		<ul>
			<li><a href="download.php?download=v2_03%2Fmod_auth_form-2.03-src.tar.gz">Source Code</a> (<a href="download.php?download=v2_03%2Fmod_auth_form-2.03-src.tar.gz.md5">MD5SUM</a>)</li>
			<li><a href="download.php?download=v2_03%2Fmod_auth_form-2.03-win32.zip">Win32 Binaries</a> (<a href="download.php?download=v2_03%2Fmod_auth_form-2.03-win32.zip.md5">MD5SUM</a>)</li>
			<li>Patches:</li>
			<ul>
				<li>PATCH #1: <a href="download.php?download=v2_03%2Fmod_auth_form-2.03-method_to_scheme.patch">ap_http_method to ap_http_scheme</a>: for compatibility with Apache 2.2.x</li>
				<li>PATCH #2: <a href="download.php?download=v2_03%2Fmod_auth_form-2.03-apr_1_fix.patch">APR-1 compatibility fix</a>: for compatibility with Apache 2.2.x</li>
			</ul>
			<li>Changes:</li>
			<ul>
				<li>BUGFIX #5: <b>AuthFormMySQLTableSIDCondition</b> can distinguish similiarly named variables (thanks again Andrei Nazarenko)</li>
				<li>BUGFIX #6: The module returns a Forbidden message if it cannot connect to the specified MySQL server</li>
				<li>Added <b>AuthFormMySQLPort</b></li>
				<li>Added <b>AuthFormSessionDelete</b></li>
				<li>The module is enabled if <b>AuthFormAuthoritative</b> is 'On' and the module's required directives are present</li>
				<li>Set some CGI environment variables</li>
				<li>The 'configure' script is friendlier</li>
			</ul>
		</ul>
		<li>Version 2.02</li>
		<ul>
			<li><a href="download.php?download=v2_02%2Fmod_auth_form-2.02-src.tar.gz">Source Code</a> (<a href="download.php?download=v2_02%2Fmod_auth_form-2.02-src.tar.gz.md5">MD5SUM</a>)</li>
			<li><a href="download.php?download=v2_02%2Fmod_auth_form-2.02-win32.zip">Win32 Binaries</a> (<a href="download.php?download=v2_02%2Fmod_auth_form-2.02-win32.zip.md5">MD5SUM</a>)</li>
			<li>Changes</li>
			<ul>
				<li>BUGFIX #3: Fixed 'AuthFormMySQLFieldGID' to default to 'gid'</li>
				<li>BUGFIX #4: 'AuthFormMySQLFieldGID' no longer needs specifying for the Require line (thanks Andrei Nazarenko)
				<li>Added auto-refresh feature</li>
				<li>Added 'last visited, unauthorized page' feature</li>
				<li>Extract GIDs from all (not just one) records with matching UID</li>
			</ul>
		</ul>
	        <li>Version 2.01</li>
		<ul>
		        <li><a href="download.php?download=v2_01%2Fmod_auth_form-2.01-src.tar.gz">Source Code</a> (<a href="download.php?download=v2_01%2Fmod_auth_form-2.01-src.tar.gz.md5">MD5SUM</a>)</li>
		        <li><a href="download.php?download=v2_01%2Fmod_auth_form-2.01-win32.zip">Win32 Binaries</a> (<a href="download.php?download=v2_01%2Fmod_auth_form-2.01-win32.zip.md5">MD5SUM</a>)</li>
			<li>Changes</li>
			<ul>
			        <li>BUGFIX #1: Fixed unwanted redirects to the login page (thanks Martin Daur)</li>
				<li>BUGFIX #2: Fixed 'lost' spaces in the variable parser</li>
				<li>Added variable parsing to 'AuthFormMySQLTable&lt;GID,Tracking&gt;Condition'</li>
			</ul>
		</ul>		
	        <li>Version 2.0</li>
		<ul>
		        <li><a href="download.php?download=v2_0%2Fmod_auth_form-2.0-src.tar.gz">Source Code</a> (<a href="download.php?download=v2_0%2Fmod_auth_form-2.0-src.tar.gz.md5">MD5SUM</a>)</li>
			<li><a href="download.php?download=v2_0%2Fmod_auth_form-2.0-win32.zip">Win32 Binaries</a> (<a href="download.php?download=v2_0%2Fmod_auth_form-2.0-win32.zip.md5">MD5SUM</a>)</li>
			<li>Changes</li>
			<ul>
			        <li>Removed directives 'AuthFormMySQLFieldSID', 'AuthFormSessionKeyUID', and 'AuthFormSessionKeySID'.</li>			       
				<li>Using 'AuthFormMySQLTableSIDConditon' for session validation.</li>
				<li>Set the priority higher (i.e. override other authentication modules).</li> 
			</ul>
		</ul>
		<li><a href="v1_0">Version 1.0</a></li>
	</ul>
	<hr />
	<h2><a name="INSTALLATION"></a>Minimum Installation and Configuration</h2>
	<div>
		Download the module and copy 'mod_auth_form.so'
		(and 'mod_auth_form.pdb' on win32) to
		the modules directory in the Apache2 distribution. Add
		the following lines to 'httpd.conf'.
		<br /><br />
		<div class="clInfoBox"><pre>
LoadModule auth_form_module modules/mod_auth_form.so

# Directory and/or .htaccess statements
AuthType Basic
AuthName "Realm Name" # This has no effect, but it is required by Apache2.
AuthFormMySQLDB MySQL_Database
AuthFormPageLogin The_Login_Page_URL
Require valid-user</pre>
		</div>
		<br />
		Under MySQL, create the following.
		<ul>
			<li>Database: MySQL_Database</li>
			<ul>
				<li>Table: sessions</li>
				<ul>
					<li>Field: VARCHAR: sid (PRIMARY KEY)</li>
					<li>Field: VARCHAR: uid</li>
				</ul>
			</ul>
		</ul>
		Restart Apache2.
		<br />
	</div>
	<hr />
	<h2><a name="EXAMPLES"></a>Examples</h2>
	<div>
		<b><a name="EX_SIMPLE"></a>Case Study 1: A Simple Restricted Area:</b>
		A website will contain a restricted area that requires a
		valid username and password. The restricted area itself
		is a directory called '/restricted'; the login pages for that
		restricted directory are '/login.html' and its handler '/login.php'.
		 The MySQL server resides on the same computer as the Apache server, and
		the name of the database is 'users'. To implement this restricted
		area, the following must be done:
		<ul>
			<li>httpd.conf</li>
			<div class="clInfoBox"><pre>
LoadModule auth_form_module modules/mod_auth_form.so

&lt;Directory "/absolute/path/to/restricted"&gt;
	AuthType Basic
	AuthName "Restricted"
	# AuthFormMySQLHost	# localhost
	# AuthFormMySQLPort	# Default port (3306)
	# AuthFormMySQLUsername	# Use Apache's username
	# AuthFormMySQLPassword	# Password-less login
	AuthFormMySQLDB users
	AuthFormSessionCookies On
	AuthFormPageLogin /login.html
	Require valid-user
&lt;/Directory&gt;</pre>
			</div>
			<li>MySQL Database: users</li>
			<ul>
				<li>Table: sessions</li>
				<ul>
					<li>Field: VARCHAR (32): sid (PRIMARY KEY)</li>
					<li>Field: VARCHAR (20): uid (FOREIGN KEY)</li>
				</ul>
				<li>Table: passwords</li>
				<ul>
					<li>Field: VARCHAR (20): uid (PRIMARY KEY)</li>
					<li>Field: VARCHAR (32): password (MD5 CRYPTED)</li>
				</ul>
			</ul>
			<li>/login.html</li>
			<div class="clInfoBox"><pre>
&lt;html&gt;
&lt;head&gt;
...
&lt;/head&gt;
&lt;body&gt;
	&lt;form action="/login.php" method="post"&gt;
		&lt;input name="uid" type="text" maxlength="20"&gt;
		&lt;input name="password" type="password" maxlength="20"&gt;
		&lt;input type="submit" value="Login"&gt;
	&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
			</div>
			<li>/login.php</li>
			<div class="clInfoBox"><pre>
&lt;?php
function genID($seed, $length)
{
	$ID = "";
	srand($seed);
	for($i = 0; $i &lt; $length; $i++)
	{
		$chtype = rand(1, 3);
		switch($chtype)
		{
		case 1: // 0-9
			$ID .= chr(rand(48, 57));
			break;
		case 2: // A-Z
			$ID .= chr(rand(65, 90));
			break;
		case 3: // a-z
			$ID .= chr(rand(97, 122));
			break;
		}
	}
	return $ID;
}
function create_session($mysql, $uid, $password)
{
	//
	// Build list of existing SIDs
	//
	$result = $mysql-&gt;query("SELECT sid FROM sessions");
	$num_rows = $result-&gt;num_rows;
	while($num_rows &gt; 0)
	{
		$row = $result-&gt;fetch_assoc();
		$sids[$row["sid"]] = TRUE;
		$num_rows--;
	}
	$result-&gt;close();
	//
	// Generate SID (making sure it is unique)
	//
	$max_attempts = 500000;
	$seed = crc32($password);
	do
	{
		$sid = genID($seed + time(), 32);
		$max_attempts--;
	} while(isset($sids[$sid]) &amp;&amp; $max_attempts &gt; 0);
	if($max_attempts &lt;= 0) // NOT GOOD
	return FALSE;
	//
	// Create the session: set the UID and SID in both the client's cookies and
	// the MySQL session table.
	//
	$mysql-&gt;query("INSERT INTO sessions (sid, uid) VALUES ('$sid', '$uid')");
	setcookie("uid", $uid, time() + 964224000);
	setcookie("sid", $sid, time() + 964224000);
	return TRUE;
}
$uid = $_POST["uid"];
$password = $_POST["password"];
$mysql = new mysqli("localhost", "my_username", "my_password", "users");
$result = $mysql-&gt;query("SELECT password FROM passwords WHERE uid='$uid'");
$row = $result-&gt;fetch_assoc();
$real_password = $row["password"];
$result-&gt;close();
if(md5($password) == $real_password)
{
	create_session($mysql, $uid, $real_password);
	header("Location: /restricted");
}
$mysql-&gt;close();
?&gt;</pre>
			</div>
		</ul>
		<b><a name="EX_COMPLEX"></a>Case Study 2: A Complex Member's Area:</b>
		A website will contain a member's area that requires a valid username and password.
		The member's area itself is a directory called '/members'; furthermore, there are
		two more restricted directories called '/members/paying', which is for paying members
		only (where as '/members' is for any member) and '/members/paying/premium', which is
		for buisness customers and/or premium members. For added security, all sessions will
		expire either from 30 minutes of inactivity or 8 hours from the time of login; also,
		sessions are valid if two SID cookies matches and either the UID cookie or the directory's signature
		matches (in case the UID cookie is rejected). The login pages for the member's area
		are '/member_login.html' and its handler '/member_login.php'. The MySQL server resides
		on a host called 'fake_server.com', and the name of the database is 'members'. Also,
		the MySQL server will keep tracking records of each request made within the member's area.
		<br /><br />
		For additional complexity, another directory called '/administration' will be accessed
		locally by the website maintainers. This directory will use basic authentication from
		'mod_auth' using a password file located at '/absolute/path/to/passwords'.
		<br /><br />
		To implement this member's area, the following must be done:<br />
		<ul>
			<li>httpd.conf</li>
			<div class="clInfoBox"><pre>
LoadModule auth_form_module modules/mod_auth_form.so

&lt;Directory "/absolute/path/to/members"&gt;
	AuthType Basic
	AuthName "Member's Area"
	AuthFormMySQLHost fake_server.com
	AuthFormMySQLUsername my_username
	AuthFormMySQLPassword my_password
	AuthFormMySQLDB members
	AuthFormMySQLTableGID uid_gid
	AuthFormMySQLTableSIDCondition "`sid`=$sid1 AND `sid_dir`=$sid2\
		AND (`uid`=$uid OR `signature`='some_signature_members')"
	AuthFormMySQLTableTracking tracking
	AuthFormMySQLFieldExpiration expiration_date
	AuthFormLastPageKey go_back_to
	AuthFormSessionTimeout 30 #minutes
	AuthFormSessionCookies On
	AuthFormPageLogin /member_login.html
	AuthFormPageExpired /session_expired.html
	Require group 0 1 #non-paying paying
&lt;/Directory&gt;
&lt;Directory "/absolute/path/to/members/paying"&gt;
	AuthFormPageNotAllowed /paying_members_only.html
	AuthFormMySQLTableSIDCondition "`sid`=$sid1 AND `sid_dir`=$sid2\
		AND (`uid`=$uid OR `signature`='some_signature_paying')"
	Require group 1 #paying
&lt;/Directory&gt;
&lt;Directory "/absolute/path/to/members/paying/premium"&gt;
	AuthFormPageNotAllowed /premium_only.html
	Require group 2 #premium
&lt;/Directory&gt;
&lt;Directory "/absolute/path/to/administration"&gt;
	AuthType Basic
	AuthName "Administration"
	AuthUserFile /absolute/path/to/passwords
	
	# Turn off 'mod_auth_form' in this directory,
	# giving control to 'mod_auth'.
	AuthFormAuthoritative Off
	
	Allow from 127.0.0.1  # localhost
	Deny from all
	Order Deny,Allow
	Require valid-user
&lt;/Directory&gt;</pre>
			</div>
			<li>MySQL Database: members</li>
			<ul>
				<li>Table: sessions</li>
				<ul>
					<li>Field: VARCHAR (32): sid (PRIMARY KEY)</li>
					<li>Field: VARCHAR (32): sid_dir</li>
					<li>Field: INT (8) UNSIGNED: uid (FOREIGN KEY)</li>
					<li>Field: VARCHAR (20): signature</li>
					<li>Field: DATETIME: timeout_date</li>
					<li>Field: DATETIME: expiration_date</li>
				</ul>
				<li>Table: creds</li>
				<ul>
					<li>Field: INT (8) UNSIGNED: uid (PRIMARY KEY)</li>
					<li>Field: VARCHAR (20): username (UNIQUE)</li>
					<li>Field: VARCHAR (32): password_md5</li>
					<li>Other fields describing each user...</li>
				</ul>
				<li>Table: groups</li>
				<ul>
					<li>Field: INT (8) UNSIGNED: gid (PRIMARY KEY)</li>
					<li>Field: VARCHAR (20): groupname</li>
					<li>Other fields describing each group...</li>
				</ul>
				<li>Table: uid_gid</li>
				<ul>
					<li>Field: INT (8) UNSIGNED: uid (FOREIGN KEY)</li>
					<li>Field: INT (8) UNSIGNED: gid (FOREIGN KEY)</li>
				</ul>
				<li>Table: tracking</li>
				<ul>
					<li>Field: INT (8) UNSIGNED: uid (FOREIGN KEY)</li>
					<li>Field: VARCHAR (15): client_ip_address</li>
					<li>Field: DATETIME: download_date</li>
					<li>Field: VARCHAR (255); download_path</li>
					<li>Field: INT (8) UNSIGNED: download_size</li>
				</ul>
			</ul>
			<li>/member_login.php</li>
			<div class="clInfoBox"><pre>
&lt;?php
//
// Assume the function 'genID' from the previous case study is defined.
//
function create_session($mysql, $uid, $password)
{
	//
	// Build list of existing SIDs
	//
	$result = $mysql-&gt;query("SELECT sid FROM sessions");
	$num_rows = $result-&gt;num_rows;
	while($num_rows &gt; 0)
	{
		$row = $result-&gt;fetch_assoc();
		$sids[$row["sid"]] = TRUE;
		$num_rows--;
	}
	$result-&gt;close();
	//
	// Generate main SID (making sure it is unique)
	//
	$max_attempts = 500000;
	$seed = crc32($password);
	do
	{
		$sid1 = genID($seed + time(), 32);
		$max_attempts--;
	} while(isset($sids[$sid1]) &amp;&amp; $max_attempts &gt; 0);
	if($max_attempts &lt;= 0) // NOT GOOD
		return FALSE;
	$sid2 = genID(crc32($sid1) + time(), 32);
	//
	// Create the session: set the UID and SID in both the client's cookies and
	// the MySQL session table.
	//
	$mysql-&gt;query("INSERT INTO sessions (sid, sid_dir, uid, signature, timeout_date, expiration_date)
		VALUES ('$sid1', '$sid2', '$uid', 'some_signature_members', DATE_ADD(NOW(), INTERVAL 30 MINUTE),
		DATE_ADD(NOW(), INTERVAL 8 HOUR))");
	setcookie("sid1", $sid1, time() + 964224000);
	setcookie("sid2", $sid2, time() + 964224000);
	setcookie("uid", $uid, time() + 964224000);
	return TRUE;
}
$username = $_POST["username"];
$password = $_POST["password"];
$mysql = new mysqli("fake_server.com", "my_username", "my_password", "members");
$result = $mysql-&gt;query("SELECT uid,password_md5 FROM creds WHERE username='$username'");
$row = $result-&gt;fetch_assoc();
$uid = $row["uid"];
$real_password = $row["password_md5"];
$result-&gt;close();
if(md5($password) == $real_password)
{
	create_session($mysql, $uid, $real_password);
	header("Location: /members");
}
$mysql-&gt;close();
?&gt;</pre>
			</div>
		</ul>
		<b><a name="EX_LOGOUT"></a>Logging Out:</b>
		Besides session expiration, logging out of a session is done simply by deleting the
		session's record from the MySQL database. In addition, the client's cookies can be
		expired if cookies are used. Here is a PHP script for destroying a session, assuming
		the client passes the session cookies.
		<div class="clInfoBox"><pre>
&lt;?php
$uid = $_COOKIE["uid"];
$sid = $_COOKIE["sid"];
$mysql = new mysqli("mysql_host", "my_username", "my_password", "my_database");
$mysql-&gt;query("DELETE FROM sessions WHERE sid='$sid'");
$mysql-&gt;close();
setcookie("uid", $uid, time() - 964224000);
setcookie("sid", $sid, time() - 964224000);
header("Location: login_page");
?&gt;</pre>
		</div>
	</div>
	<hr />
	<h2><a name="REFERENCE"></a>Configuration Reference</h2>
	<h3>The directives listed below have the prefix <big>AuthForm</big>.</h3>
	<div>
		<div class="clConfName">Authoritative</div>
		<div class="clConfSyn">Flag : DEFAULT="On"</div>
		<div class="clConfDesc">
			Turn on 'mod_auth_form'.
		</div>
		<br />
		<div class="clConfName">LastPageKey (version 2.02+)</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The name of the url query string key containing
			the URL that a client unsuccessfully accessed
			(i.e. the URL from which the client was redirected).
		</div>
		<br />
		<div class="clConfName">MySQLDB</div>
		<div class="clConfSyn">String : REQUIRED</div>
		<div class="clConfDesc">
			The MySQL database to connect to.
		</div>
		<br />
		<div class="clConfName">MySQLFieldDownloadDate</div>
		<div class="clConfSyn">String : DEFAULT="download_date"</div>
		<div class="clConfDesc">
			Field under the tracking table that stores
			the time of request.
		</div>
		<br />
		<div class="clConfName">MySQLFieldDownloadPath</div>
		<div class="clConfSyn">String : DEFAULT="download_path"</div>
		<div class="clConfDesc">
			Field under the tracking table that stores
			the path of request.
		</div>
		<br />
		<div class="clConfName">MySQLFieldDownloadSize</div>
		<div class="clConfSyn">String : DEFAULT="download_size"</div>
		<div class="clConfDesc">
			Field under the tracking table that stores
			the size of request.
		</div>
		<br />
		<div class="clConfName">MySQLFieldExpiration</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			Field under the session table that stores
			the time the session will expire regardless
			of user activity. Not specifying this configuration
			disables session expiration (although session inactivity
			timeout can still be enabled). Also,
			<b>AuthFormPageExpired</b> must be configured.
		</div>
		<br />
		<div class="clConfName">MySQLFieldGID</div>
		<div class="clConfSyn">String : DEFAULT="gid"</div>
		<div class="clConfDesc">
			Field under the group table that stores
			the user's space/comma delimited list
			of group IDs. <b><br />NOTE: Having a multi-value
			field violates the conceptual design of relational
			databases. In the next major version (3.0), this
			feature will be removed in favor of a join table.</b>
		</div>
		<br />
		<div class="clConfName">MySQLFieldIPAddress</div>
		<div class="clConfSyn">String : DEFAULT="client_ip_address"</div>
		<div class="clConfDesc">
			Field under the tracking table that stores
			the client's IP address.
		</div>
		<br />
		<div class="clConfName">MySQLFieldTimeout</div>
		<div class="clConfSyn">String : DEFAULT="timeout_date"</div>
		<div class="clConfDesc">
			Field under the session table that stores
			the time the session will expire if the user
			is inactive.
		</div>
		<br />
		<div class="clConfName">MySQLFieldUID</div>
		<div class="clConfSyn">String : DEFAULT="uid"</div>
		<div class="clConfDesc">
			Field under the session, group, and tracking
			tables that stores the user ID.
		</div>
		<br />
		<div class="clConfName">MySQLHost</div>
		<div class="clConfSyn">String : DEFAULT="localhost"</div>
		<div class="clConfDesc">
			The fully-qualified name or IP address of the
			MySQL server.
		</div>
		<br />
		<div class="clConfName">MySQLPassword</div>
		<div class="clConfSyn">String : DEFAULT=&lt;Blank Password&gt;</div>
		<div class="clConfDesc">
			The MySQL user's password.
		</div>
		<br />
		<div class="clConfName">MySQLPort (version 2.03+)</div>
		<div class="clConfSyn">Number : DEFAULT="3306"</div>
		<div class="clConfDesc">
			The MySQL port to connect to.
		</div>
		<br />
		<div class="clConfName">MySQLSSL (version 2.04+)</div>
		<div class="clConfSyn">Flag : DEFAULT="Off"</div>
		<div class="clConfDesc">
			Use SSL connections to MySQL. Please see the
			<b>AuthFormMySQLSSL*</b> directives. Those directives
			mimic the parameters in mysql_ssl_set() from the
			MySQL Client API.
		</div>
		<br />
		<div class="clConfName">MySQLSSLCA (version 2.04+)</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The path to the file listing the trusted certificate
			authorities.
		</div>
		<br />
		<div class="clConfName">MySQLSSLCAPath (version 2.04+)</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The path to the directory containing the PEM-formatted,
			trusted certificate authorities.
		</div>
		<br />
		<div class="clConfName">MySQLSSLCert (version 2.04+)</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The path to the MySQL client certificate.
		</div>
		<br />
		<div class="clConfName">MySQLSSLCipherList (version 2.04+)</div>
		<div class="clConfSyn">String : DEFAULT="!ADH:RC4+RSA:HIGH:MEDIUM:LOW:EXP:+SSLv2:+EXP"</div>
		<div class="clConfDesc">
			The list of SSL ciphers (in 'openssl ciphers' format) to
			allow for SSL connections.
		</div>
		<br />
		<div class="clConfName">MySQLSSLKey (version 2.04+)</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The path to the MySQL client certificate key.
		</div>
		<br />
		<div class="clConfName">MySQLSocket (version 2.04+)</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The path to the MySQL server socket file
			(Unix only).
		</div>
		<br />
		<div class="clConfName">MySQLTableGID</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The table that stores the group memberships.
			<b>AuthFormMySQLFieldGID</b> and
			<b>AuthFormPageNotAllowed</b> must also be configured
			along with the <b>Require</b> directive in
			a directory container (refer the the <a href="http://httpd.apache.org/docs-2.0/">
			Apache2	documentation</a> for more information).
			Also, the table must have a UID and GID field where
			the UID field is the primary key.
		</div>
		<br />
		<div class="clConfName">MySQLTableGIDCondition</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			Condition to add to the WHERE-clause when
			querying the group membership table.
		</div>
		<br />
		<div class="clConfName">MySQLTableSID</div>
		<div class="clConfSyn">String : DEFAULT="sessions"</div>
		<div class="clConfDesc">
			The table that stores session records. At
			minimum, the table should have a SID field and
			a UID field where the SID field is the primary key.
		</div>
		<br />
		<div class="clConfName">MySQLTableSIDCondition</div>
		<div class="clConfSyn">String : DEFAULT="sid=$sid AND uid=$uid"</div>
		<div class="clConfDesc">
			Session validation condition used in the WHERE-clause
			when querying the session table. The variable
			placeholders (denoted as $var) store session values
			passed by the clients and validated by the module.
			With the exception of the placeholders, the syntax
			of the condition is the same as the syntax in
			a MySQL WHERE clause.
		</div>
		<br />
		<div class="clConfName">MySQLTableTracking</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The table that stores request tracking information.
			The table must have a field for UID, client's IP
			address, download date, download path, and download
			size (no primary keys).
		</div>
		<br />
		<div class="clConfName">MySQLTableTrackingCondition</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			Condition to add to the WHERE-clause when
			querying the tracking table.
		</div>
		<br />
		<div class="clConfName">MySQLUsername</div>
		<div class="clConfSyn">String : DEFAULT=&lt;Apache2 Username&gt;</div>
		<div class="clConfDesc">
			The MySQL user used to connect to the MySQL
			server.
		</div>
		<br />
		<div class="clConfName">PageAutoRefresh (version 2.02+)</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The URL to which to auto-refresh.
			Effectively speaking, this directive defaults
			to the current page if session expiration is
			disabled and/or not used (see
			<b>AuthFormSessionAutoRefresh</b>). Otherwise,
			this directive defaults to <b>AuthFormPageExpired</b>.
		</div>
		<br />
		<div class="clConfName">PageExpired</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The URL to the 'session expired' page.
		</div>
		<br />
		<div class="clConfName">PageLogin</div>
		<div class="clConfSyn">String : REQUIRED</div>
		<div class="clConfDesc">
			The URL to the page containing the login form.
		</div>
		<br />
		<div class="clConfName">PageNotAllowed</div>
		<div class="clConfSyn">String : OPTIONAL</div>
		<div class="clConfDesc">
			The URL to the 'invalid group member' page.
		</div>
		<br />
		<div class="clConfName">SessionAutoRefresh (version 2.02+)</div>
		<div class="clConfSyn">Number : DEFAULT=-1</div>
		<div class="clConfDesc">
			How many seconds should the web browser refresh
			to a certain page (if not the current page).
			A value of 0 means disable auto-refreshing.
			A value of -1 (default) means auto-refresh when
			the client's session expires; if session
			expiration is disabled, auto-refreshing will
			effectively be disabled.
			Any value greater than 0 indicates a fixed
			number of seconds to auto-refresh.
			See also <b>AuthFormPageAutoRefresh</b>.
		</div>
		<br />
		<div class="clConfName">SessionCookies</div>
		<div class="clConfSyn">Flag : DEFAULT="Off"</div>
		<div class="clConfDesc">
			Whether to use cookies or the URL query string
			to pass the session keys from the client to the
			module. ('On' means use cookies; 'Off' means
			use the URL query string).
		</div>
		<br />
		<div class="clConfName">SessionDelete (version 2.03+)</div>
		<div class="clConfSyn">Flag : DEFAULT="Off"</div>
		<div class="clConfDesc">
			Whether or not the module should delete expired
			sessions per request.<br />
			<b>NOTE: This feature is not as robust as
			managing expired sessions via
			server-side scripting, especially when
			auto-refreshing is used.</b>
		</div>
		<br />
		<div class="clConfName">SessionTimeout</div>
		<div class="clConfSyn">Number : DEFAULT=0</div>
		<div class="clConfDesc">
			The session inactivity timeout in minutes. A
			value of '0' indicates no timeout. Also,
			<b>AuthFormPageExpired</b> must be configured.
		</div>
		<br />
		<div class="clConfName">TrackingLifetime</div>
		<div class="clConfSyn">Number : DEFAULT=30</div>
		<div class="clConfDesc">
			Maximum number of days to hold a tracking record.
			A value of '0' indicates infinite lifetime.
			(The module goes by the date of download field under
			the tracking table).
		</div>
		<br />
	</div>
	<hr />
	<h2><a name="IDEAS"></a>Ideas for Future Releases</h2>
	<ul>
		<li>Add username/password verification support (e.g. verify against htpasswd files)</li>
		<li>Add support for other SQL servers (e.g. PostgreSQL)</li>
		<li>Add support for LDAP and flat files (XML) as a means for session tracking</li>
		<li>Somehow condense the module's directives</li>
		<li>Centralize database configurations</li>
		<li>Give a full URI from <b>AuthFormSessionLastPageKey</b> when necessary; otherwise, give a relative URI (maybe with a directive)</li>
		<li>Remove the multi-value feature of <b>AuthFormMySQLFieldGID</b> in favor of a join table</li>
		<li>Replace the "Examples" section with a demo-site</li>
	</ul>
	<h2><a name="CONTRIBUTE"></a>Contributing</h2>
	<div>
		Anybody who wants to contribute to this project may send me an email
		at <a href="mailto:ajarthu@uark.edu">ajarthu@uark.edu</a>. Before doing so,
		please read through <a href="#IDEAS">Ideas for Future Releases</a>.
		When sending source code, either attach a snippet of what's not in the
		module's source code or a patch. Along with the source code, please
		include a description in the email message. All source code
		must be in C. Testers are welcome to send their results (e.g.
		how many sessions can this module handle, security holes, etc).
		<br /><br />
		Currently, I'm looking for support in obtaining the username and
		password through HTTP POST and maintaining persistent data in other
		backends besides MySQL. I'm thinking about adding options to the
		'configure' script to specify which backend(s) to compile into the module.
		<br /><br />
		One final note: Let me know if you want me to include your
		name and/or email address under the <a href="#CONTRIBUTORS">contribution list</a>.
	</div>
	<h2><a name="CONTRIBUTORS"></a>Contributors</h2>
	<ul>
		<li>Aaron Arthurs &lt;ajarthu@uark.edu&gt; (maintainer)</li>
		<li>Andrei Nazarenko &lt;a.nazarenko@gmail.com&gt;</li>
		<li>Martin Daur &lt;m.daur@beam.ag&gt;</li>
		<li>Matthew Dickinson &lt;matt@alpha345.com&gt;</li>
	</ul>
	<hr /><a name="COPYRIGHT"></a>
	<div class="clCopyright">
		Copyright 2004-2006 <a href="http://csce.uark.edu/~ajarthu">Aaron Arthurs</a><br /><br />
		Licensed under the Apache Lincense, Version 2.0 (the "License");<br />
		you may not use this file except in compliance with the License.<br />
		You may obtain a copy of the License at<br /><br />
		<div><a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSES-2.0</a><br /><br /></div>
		Unless required by applicable law or agreed to in writing, software<br />
		distributed under the License is distributed on an "AS IS" BASIS,<br />
		WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.<br />
		See the License for the specific language governing permissions and<br />
		limitations under the License.
	</div>
	<hr />
	Last Updated: Sat Jul 22 12:00:05 CDT 2006
	<hr />
</body>
</html>