PHP and HTTP Authentication






PHP and HTTP Authentication

PHP can use authentication from the Apache web server. PHP sends a header request to the browser requesting an authentication dialog on the client's browser. You'll recognize this prompt as a standard browser login prompt. Because the authentication head must come before any other HTML output, this works only with the module-based PHP installation, not the CGI version.

Figure shows how to use HTTP authentication.

Using HTTP authentication with a PHP script

<?php
if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
header('WWW-Authenticate: Basic realm="Member Area"');
header("HTTP/1.0 401 Unauthorized");
echo "Please login with a valid username and password.";
exit;
} else {
echo "You entered a username of: ".$_SERVER['PHP_AUTH_USER']." ";
echo "and a password of: ".$_SERVER['PHP_AUTH_PW'].".";
}
?>

The code from Figure displays a prompt like the one in Figure.

The prompt for authentication to the Member Area realm


If the user clicks Cancel, he'll see Figure.

Clicking Cancel causes a message that the user must log in


That's a fairly simple example. We checked to see if the username and password were set, then displayed them to the user. The realm field provides a way for grouping related pages together for access restrictions. Any PHP page that presents the authentication headers within the same realm as the login page is accessible after a successful login. This spares the user from having to re-authenticate for each PHP page.

Figure validates the username and password retrieved from an authentication prompt. If they don't match, access to all pages in that realm is denied.

Checking the values returned from the authentication prompt

<?php
$username = 'jon_doe';
$password = 'MyNameIsJonDoe';
if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
header('WWW-Authenticate: Basic realm="Member Area"');
header("HTTP/1.0 401 Unauthorized");
echo "You must enter in a username and password combination!";
exit;
}
elseif (strcmp($_SERVER['PHP_AUTH_USER'], $username) !== 0 ||
strcmp($_SERVER['PHP_AUTH_PW'], $password) !== 0) {
header('WWW-Authenticate: Basic realm="Member Area"');
header("HTTP/1.0 401 Unauthorized");
echo "Your username and password combination was incorrect!";
exit;
}
echo("You have successfully logged in!");
?>

Figure checks that the authentication was set. If it wasn't, request a username and password. The elseif clause checks to see whether the strings are equal to each other.

This is different than simply comparing two strings with the equality (==) operator. When comparing input, the == operator can cause unexpected results. Therefore, use the strcmp function. The strcmp function returns 0 only when the two strings are identical. If either the username or password comparison returns a value other than 0, you deny access; otherwise, access is granted. If they don't match, request another authentication prompt from the user by sending authentication headers again. They then must come before any other output.

Storing a Username and Password in a Database

Let's revisit some of the knowledge you picked up back in Chapter 5. We're going to create a new table for users. Instead of comparing a username and password to values that are set in your PHP script, you'll check them against a database table called USERS. As explained in Chapter 5, you'll want to log into the command prompt and create a table using the syntax in Figure.

Creating the users table to store login information

CREATE TABLE `users` (
`user_id` INT NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(100),
`last_name` VARCHAR(100),
`username` VARCHAR(45),
`password` CHAR(32),
PRIMARY KEY (`user_id`));

This code returns:

Query OK, 0 rows affected (0.23 sec)

To add a user, you create an entry in the database for a user with an encrypted password, as shown in Figure.

Creating the entry in the database for a user with an encrypted password

INSERT INTO users (`first_name`, `last_name`, `username`, `password`)
VALUES
('Michele','Davis', 'mdavis', MD5('secret'));

This yields:

Query OK, 1 row affected (0.01 sec)

To check that your row was created and see what the MD5 encoding function returned, you query the users table:

SELECT * FROM users;

Presto:

+---------+------------+-----------+----------+----------------------------------+
| user_id | first_name | last_name | username | password |
+---------+------------+-----------+----------+----------------------------------+
|       1 | Michele    | Davis     | mdavis   | 5ebe2294ecd0e0f08eab7690d2a6ee69 |
+---------+------------+-----------+----------+----------------------------------+
1 row in set (0.00 sec)

Now that you've created the table, let's set up the login script to test a username and password. You encoded the password using MD5 to provide an extra layer of security. The password that created the encoded string cannot be determined from the stored string. This means that even if a malicious user finds out another user's encoded password, she can't use it to log in. However, this method is for testing only, and more secure options will be discussed later in the book.

Figure reuses much of the same code from the example in the previous section, so don't worry about having to rewrite too much! The major difference is that instead of using the strcmp command to check the username and password, you place them into a query and use the database to check for a match.

Don't forget that you still need your database login information in a file called db_login.php, shown in Figure.

The database login details

<?php
$db_host='localhost';
$db_database='test';
$db_username='test';
$db_password='yourpass';
?>

The values from Figure are used in Figure.

Verifying a username and password against the database

<?php
require_once('db_login.php');
require_once('DB.php');
if (!isset($_SERVER['PHP_AUTH_USER']) ||
!isset($_SERVER['PHP_AUTH_PW'])) {
header('WWW-Authenticate: Basic realm="Member Area"');
header("HTTP/1.0 401 Unauthorized");
echo "You must enter in a username and password combination!";
exit;
}
$web_username = $_SERVER['PHP_AUTH_USER'];
$web_password = $_SERVER['PHP_AUTH_PW'];
$connection = DB::connect("mysql://$db_username:$db_password@$db_host/$db_database");
if (DB::isError($connection)){
die ("Could not connect to the database: <br />". DB::errorMessage($connection));
}
$query = "SELECT `user_id`, `username` FROM `users` WHERE
`username`='".$web_username."' AND `password`=MD5('".$web_password."') LIMIT 1";
$result = $connection->query($query);
if (DB::isError($result)){
die("Could not query the database: <br />".$query." ".DB::errorMessage($result));
}
if (!$row = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
header('WWW-Authenticate: Basic realm="Member Area"');
header("HTTP/1.0 401 Unauthorized");
echo "Your username and password combination was incorrect!";
exit;
}
echo("You have successfully logged in as ".$row['username']."!");
?>

You may have to change display_errors = Off in the php.ini file if you get the following error.

Warning:  headers already sent message causing the message box not to display.

This may be a little too much to consume at the moment, but save the script and run it, which displays the screen in Figure. Then try logging in with the username of mdavis and a password of secret.

Prompting for username and password before checking the database


You should see that the script handles the login, shown in Figure, with the database because there is a successful match of data.

A successful match with the database's credentials


If you entered something invalid, you'll see an unauthorized page such as Figure telling you that the username and password are incorrect.

An invalid username and password causes this message to display




 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows