Php/Apache Authentication
— print (last updated: Sep 12, 2009) print

Select font size:
Download the PhpAuth.zip archive. Install it, like others, as a Php project with existing sources. This is an AJAX-based project which requires the installation of Dojo.

Apache Rewrite Module

You will need to activate the Apache Rewrite module.
    Windows   Linux (Ubuntu)    

Windows

Edit the Apache configuration file, httpd.conf (from the Apache menu). Look for the line:
#LoadModule rewrite_module modules/mod_rewrite.so
Uncomment it by removing the initial "#" character. Then restart Apache (from the menu).

Authentication

The notion of authentication, in its simplest form, usually means forcing a web user to enter some "secret" information in order to be able to activate certain web functions. The secret information can be a single password or a user name and password.

The Apache web server itself supports a number of authentication mechanisms, the most common being the so called Basic Authentication. Basic Authentication forces a user/password entry and checks this against information stored in a variety of ways such as a a file, a MySQL table, etc. One problem with Basic Authentication is the lack of control by the application, e.g., an authenticated client session cannot be invalidated by the application.

Session-based authentication

Let's say that we want to employ a session-based authentication. In its simplest form we somehow set some special session variable:
$_SESSION['_VALID_'] = 1
Each script requiring authenticated access must somehow: In order to avoid adding code to effect these features for every script requiring authentication, we use Apache's rewrite features to forward such scripts through a single controller script, controller.php. The easiest way to achieve what we want is to write an Apache-specific .htaccess file:

.htaccess
RewriteEngine on RewriteBase /default/PhpAuth RewriteRule ^_.*$ controller.php [PT,L]
The implication of using this .htaccess file is that all web-based URLs in this application beginning with "_" will be forwarded to controller.php. The job of controller.php is:
  1. determine the protected document corresponding to the intended activation
  2. if the session has already been validated, forward to the protected document
  3. if the session has not been validated, invoke HTML code with a form which requests password entry for validation.
Using a "_" prefix to determine whether authentication is required is very contrived. Web frameworks using Apache provide non-contrived ways to send most URLs through some front controller and distribute their behavior to other controllers which generate the desired output by combining their output with "view scripts."

Controller and validator


controller.php
<?php define( "BASE", "/default/PhpAuth/" ); $url = parse_url($_SERVER['REQUEST_URI']); $path = $url['path']; $path = substr($path, strlen(BASE)); // strip off BASE prefix #$show = 1; // uncomment this for debugging if ($show) { echo "FRONT CONTROLLER<br />target url: $path" ; exit(); } session_start(); if ( $_SESSION['_VALID_'] ) { if (! is_file($path) ) { header("HTTP/1.0 404 Not Found"); echo "<h1>Object not found</h1>"; } else require_once $path; // forward to intended script exit(); } ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Read</title> <script type="text/javascript" src="/dojolib/dojo/dojo.js" djConfig="parseOnLoad:true"></script> <script> function checkValid() { dojo.xhrPost( { url: "validate.php", form: 'validate', load: function() { location.reload() }, error: function(response,ioArgs) { if (ioArgs.xhr.status == 420) { // expected error dojo.byId('resp').innerHTML = ioArgs.xhr.responseText } else { alert(response); } } } ) } </script> </head> <body> <h2>Validate Access</h2> <form id="validate"> <!-- autocomplete="off" makes it so that the browser cannot remember the password --> <input type="password" autocomplete="off" name="pwd" /> <button onclick="checkValid();return false">Validate</button> <b id="resp" style="color:red"></b> </form> </body> </html>

validate.php
<?php session_start(); $param = array_merge( $_GET, $_POST ); $pwd = $param['pwd']; $thePassword = "foobar"; if ($param['pwd'] == $thePassword) { # pathetic security! $_SESSION['_VALID_'] = 1; exit(); } if ($param['pwd'] == 'INVALID') { unset($_SESSION['_VALID_']); exit(); } header("HTTP/1.0 420 Invalid Password"); die("Invalid password!");
Our validation merely checks that the entered password equals the known password. As we remark in the comment, this is pretty pathetic. A significant improvement would be matching the entered password against some cryptographic content so as to avoid revealing the actual password anywhere. On the other hand, the validation does take place entirely on the server side and so we ensure that the browser client is unable to read the known password.

Remaining scripts

The additional scripts used in this project are:
index.php:                  presents the features: read, create, logout
read.php:                   non-protected read script
handlers/readHandler.php:   non-protected read activation script
_create.php:                protected create script
_handlers/createHander.php: protected create activation script
Both read.php and _create.php present a simple HTML form which performs an AJAX-activation of the respective "handler" script. The "handler" script simply indicates through its output that it is being activated.

Below we illustrate the index.php file as well as the files used for the "read" feature. Those for the "create" feature are similar.

index.php
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="/dojolib/dojo/dojo.js" djConfig="parseOnLoad:true"></script> <script> function invalidate() { dojo.xhrGet( { url: "validate.php", content: { pwd: "INVALID" }, error: function(response) { alert(response); } } ) } </script> <title></title> </head> <body> <a href="read.php">Read</a> <br /><br /> <a href="_create.php">Create</a> <br /><br /> <a href="javascript:invalidate()">Logout</a> </body> </html>

read.php
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Read</title> <script type="text/javascript" src="/dojolib/dojo/dojo.js" djConfig="parseOnLoad:true"></script> <script> function button_handle() { dojo.xhrGet( { url: "handlers/readHandler.php", load: function(response) { dojo.byId('result').innerHTML = response } } ) } </script> </head> <body> <h2>Read</h2> <button onclick="button_handle()">DO IT</button> <p id="result"><p> </body> </html>

handlers/readHandler.php
<?php echo "READ HANDLER ACTIVATED";


© Robert M. Kline