Basic Authentication PHP Help

Authentication, like everything else, can be done Simply or with tremendous complexity. Also, like nearly everything else, it’s best to start with the basics and add complexity as needed. For a simple application, you don’t need thumbprint readers and lasers scanning a user’s face. (Granted, it might be fun, but it’s not necessary. James Bond almost certainly isn’t going to fill out your create_User.html form.)

Using HTTP Headers for Basic Authentication

Basic authetication also known as HTTP authentication, is a means of supplying a user name and password in a web application through HTTP headers. You’ve already worked with headers a bit. Remember this bit of code from scripts/app_config.php.

function handle_error($user_error_message, $system_error_message)
header(” Location: ” . get_web_path(SITE_ROOT)
“scripts/show_error. php” .
“?error_message={$user_error_message}”
“&system_error_message={$system_error_message}”);

This handle_error function is using an HTTP header-the Location header-to send a redirect to the browser. You’ve also used the Content-type and Content-length headers in displaying an image in show_image.php.

header(‘Content-type: ‘ . $image[‘mime_type’]);
header(‘Content-length: ‘ . $image[‘fi.le_size’]);

With basic authentication, there are a couple of other HTTP headers you can send. The first doesn’t have a key value such as Content-type or Location. You simply send this:

HTTP/1.1 401 Unauthorized

When a browser receives this header, it knows that a requested page requires authentication to-be displayed. 401 is a special status code, along with lots of others, that informs the browser about the request. 200 is the code used to indicate “Everything is OK,” for example, and 404 is the HTTP error code for “Not Found.”

It’s one thing to tell the browser that access to a page is restricted, but at some point you’ll want to make that page unrestricted. The answer is to send a second header:

WWW-Authenticate: Basic realm=”The Social Site”

This header WM-i-Authenticate alerts the browser that authentication needs to happen. Specifically, the browser should pop up a dialog box and ask for some credentials.

You specify what type of authentication to require; in this example, it’s Basic. Then, you identify a realm to which that authentication should be applied. In this case, it’s “The Social Site”. As long as different pages use this same realm, authentication to one of those pages applies to other pages in that same realm.

Basic Authentication Is…Well, Basic
It’s time to apply authentication to your own application. Open your sow_user.php script.

Enter these two header lines near the top of the script

<?php
require_once’ ../scripts/app_config.php’;
require_once’ ../scripts/database_connection.php’;
require_once’ ../scripts/view.php’;

header(‘HTTP/1.1 401 Unauthorized’);
header(‘WWW-Authenticate: Basic realm=”The Social Site”‘);
// Build the SELECT statement
$select users =
“SELECT user_id, first_name, last_name, email ” .
” FROM users”;
// Remaining PHP
?>

Navigate over to show_users.php. You should see a nice pop-up window asking you to log in, like Figure 12-1.Well, it’s not that nice, but it does the trick. Basic authentication, pure and simple.

FIGURE 12-1

FIGURE 12-1

The Worst Authentication Ever

With the addition of the two headers on page 388, there’s still a gaping hole in your security. Navigate to show_user.php if you’re not there already, and leave both the Name and Password fields blank. Then, simply click Cancel. Figure 12-2 shows the result.

FIGURE 12-2

FIGURE 12-2

As if that’s not enough, enter anv user name and password and then click Log In. There you go: Figure 12-2 again. In fact, spend some time trying to get anything other than the normal show_user,php page. You won’t be able to.

Pretty poor security, isn’t it? Canceling should take you on to the supposedly secure page. What you need to do is get the user name and password, check them against acceptable values, and show the page. In every other case, the user should not see show_user.php.

Getting Your User’s Credentials

To check the user name and password against any values, you need to make some changes to your script. Your current code doesn’t extract those values, let alone compare them against any other values. There’s clearly some work to do here.

Fortunately, because HTTP authentication is defined in a standard way, it’s easy for PHP to interact with users who enter their credentials into a basic authentication pop-up dialog box. In fact, PHP gives you access to both the user name and password entered via two special values in a superglobal variable you’ve used before, $_ SERVER:
• $_SERVER [ ‘PHP _ AUTH _USER’ 1 gives you the entered user name.

• $_ SERVER [ , PHP_AUTH _ PW’ 1 gives you the entered password.

You might expect your flow to proceed something like this:

1. At the beginning of a script, send the HTTP headers that trigger authentication.
2. Once the authentication code is complete, check $_SERVER[, PHP_AUTH _USER’] and $_SERVER[‘PHP_AUTH_PW’] for values and compare those values to some constants or a database.
3. Decide whether to let the us!r see the content your script normally outputs. That makes a lot of sense, but turns out to be wrong. Here’s what really happens:

1. Your script is called.
2. Authentication headers (actually, a header that says a user is unauthorized and should be allowed to sign in) are sent.
3. Once the user enters in a user name and password, the browser recalls your script from the top once again.
Clearly, you need to determine if there are any available credentials betore authentication headers are sent. If there are credentials, check them against allowed values. Finally, if the credentials don’t match or don’t exist, that’s when you send the authentication headers.

Once again, then, isset (page 235) becomes your friend. Start with code like this:

if (!isset($_SERVER[‘PHP_AUTH_USER’]) II
!isset($_SERVER[‘PHP_AUTH_PW’]» {
header(‘HTTP/1.1 401 Unauthorized’);
header( ‘WWW-Authenticate: Basic realm=”The Social Site?”};
}

Yet, all this does is pop up the login box if the user name and password haven’t previously been set. It still allows access to your page through a couple different avenues. So you need to not only pop up a login box, but also ensure that any preset user names and passwords match an allowed set of values.

Cancel Is Not a Valid Means of Authentication

Before you deal with checking user names and passwords, though, there’s something more pressing to deal with. Even worse than accepting any credentials is accepting a click of the Cancel button . This-situation is easy to deal with, albeit not intuitively. Here’s your code right now:

if (!isset($_SERVER[‘PHP_AUTH_USER’]) I I
!isset($_SERVER[‘PHP_AUTH_PW’]» {
header(‘HTTP/1.1 401 Unauthorized’);
header(‘WWW-Authenticate: Basic realm:”The Social Site”‘);

The login dialog box is prompted by the two calls to the header:

header(‘HTTP/1.1 401 Unauthorized’);
header (‘WWW-Authenticate : Basic realm=’The Social Site”‘);

When a user clicks Cancel, your PHP continues to run, directly from after the second header line:

header(‘HTTP/1.1 401 Unauthorized’);
header(‘WWW-Authenticate: Basic realm=The Social Site”‘);
// This line is run if Cancel is clicked

Taking the simplest possible path, you could simply bailout of the script:

if (lisset($_SERVER[‘PHP_AUTH_USER’]) I I
lisset($_SERVER[‘PHP_AUTH_PW’]» {
header(‘HTTP/1.1 401 Unauthorized’);
header(‘WWW~Authenticate: Basic realm-t’The Social Site”‘);
exit(“You need a valid username and password to be here. ”
“Move along, nothing to see.”);

That way, if a user clicks Cancel, the script runs the exit command-which is a lot like die-and bails out with an error message, as shown in Figure 12-3.

FIGURE 12-3

FIGURE 12-3

Getting Your User’s Credentials

Let’s get back to seeing what your user actually supplies to the login dialog box. Remember, the flow here isn’t what you might expect. Once the user has entered a user name and password, your script is basically recalled. It’s almost as though the server is giving you a free while loop, similar to this:

while (username_and_password_are_wrong) {
ask_for_username_and_password_again();
}

Pseudocode: The Code Before You Write Code

Lots of times you’ll find that you need a happy medium before writing full-on working cope-syntactically accurate, debugged, ready to run-and scribbling a list of steps to follow in a notebook. You want to think about the details of how things will work without getting bogged down by minutiae of syntax. As a bonus-pseudocode is language-neutral, so you can write pseudocode and later implement that code in any programming language you choose.

That said, when you write pseudocode, you usually know which language you have in mind and use that syntax. For example, if you’re writing pseudocode that you’ll eventually turn into PHP,you might use an if, a while, an else, and throw in curly braces or angle brackets. That’s why this while (username_and_password_are_wrong) { ask_for_username_and_password_again(); is a great example of pseudocode that will later become PHP.But, in the case below, it’s not helpful to type out all the $_SERVER stuff, because it’s long, full of little commas and apostrophes, and you already know the basic idea. So, whether you’re explaining to a coworker what you’re doing or just planning out your code, this is a perfectly good stand-in:

while (username_and_password_are_wrong) {
In your head, you might be translating that to something like this:
if (($_SERVER[‘PHP_AUTH_USER’] 1= VALID_ USERNAME) II
($_SERVER[‘PHP_AUTH_PW’] 1= VALID PASSWORD)) {
What will you <foonce you make that determination? Something you’re not sure what yet. You know basically what has to happen, but the details are still up in the air. That leaves you with this:

ask_for_username_and_password_again();

It’s clear, it’s understandable, but it’s not bogged down by PHP semantics. It’s pseudocode. It’s great for getting an idea going, or communicating about code. It’s also great for a situation like this in which something tells you the way you’re doing things might need to change. And, if change is coming, the less work you put into a solution that isn’t permanent, the better.

Right now, you have an if statement that confirms whether the user name and password have been set. If not, send the headers, and if Cancel is clicked, bailout.

if (lisset($_SERVER[‘PHP_AUTH_USER’]) I I
lisset($_SERVER[‘PHP_AUTH_PW’])) {
header(‘HTTP/1.1 401 Unauthorized’);
header( ‘WWW-Authenticate: Basic realm=”The Social Site”‘);
exit(“you need a valid username and password to be here. ”
“Move along, nothing to see.”);

In an else part of this script (yet to be written) you could check the user name and password against the acceptable values. If they match, display the output from show_user.php. If not. you want to resend the headers that cause the browser to prompt the user to log in again. Therefore, you want something like this:

Getting Your User's Credentials

Given that, you can actually consolidate things a bit. Whether the user has never attempted to log in, or incorrectly entered her user name or password, the script needs to send HTTP headers to force authentication. It’s only if the user has entered information and it matches the appropriate values that the rest of the page’s action should be taken and the output should be displayed. Thus, what you really want is this:

Getting Your User's Credentials

Go ahead and add this code to your version of show_users.php). Then, go up to the top of show_user.php make sure it’s before your new if statement-and add a few new constants:

Getting Your User's Credentials

Try visiting show_users.php again and typing admin and Super secret for the user name and password, respectively, as shown in Figure 12-4. You should be greeted by the normal show_users.php view (see Figure 12-5). Otherwise, you’ll just get the authentication pop-up over and over.

FIGURE 12-4

FIGURE 12-4

FIGURE 12-5

FIGURE 12-5

Infinity and Beyond

Yes.Absolutely. Alas, at the moment, that’s exactly what you’re providing in show_users.php the opportunity to try, over and over and over, to get a valid user name and password. Truth be told, the sample code and patterns you’ll see all over the Web for using basic authentication look just like what you have in show_users.php. There certainly are ways to get around this, but they’re not as easy as you might hope. Because the browser is making multiple requests to your script, you’d have to figure out a way to pass the number of requests that have been made to your script from your script. If that sounds tricky, it is. There are ways to handle multiple requests, and you’ll learn about them (although for a much better purpose) in the next chapter on sessions. For now, realize that the basic authentication approach is temporary anyway, and all of this code is a starting Point, not an end point.

Posted on January 12, 2016 in Authentication and Authorization

Share the Story

Back to Top