Setting Up Basic Authentication On A Drupal Site Without .htaccess

Basic HTTP authentication is a simple authentication mechanism that is used to prevent access to a site or directory on a server. It is by no means the most secure authentication mechanism but it is commonly used on staging sites in order to prevent unwanted access. This is a good way of preventing search engine bots from spidering the staging site, which is undesirable as it can cause staging site pages appearing in search engines results.

The usual route to set this up is to create a .htaccess that sets up the authentication and references a .htpasswd file to create the username and password details. This can mean editing the .htaccess file in order to setup the password correctly. Unfortunately, this creates a .htaccess file that shouldn't be added to the repository as it would mean that the live site would also be password protected when the code is deployed.

The best way around this is to put the authentication mechanism into your Drupal settings.php file. This prevents the authentication mechanism from being passed onto he live site.

The first thing to do here is to set an environment variable in your Apache config. This will be used later in the script in order to detect if a password is needed. This is a good way of making sure that the stating site is the only one that gets effected by the authentication code.

SetEnv SET_PASSWORD "true"

There is one rule that you need to add to the Drupal .htaccess file, but this doesn't cause any unwanted side effects if it happens to be deployed to the live site. This needs to be placed at the end of your .htaccess file in order for the normal Drupal index.php rules to be fired correctly.

RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]

The 'E' flag here sets up an environment variable with the authenticated user details so that we can read it in PHP. The 'L' flag means that if this rule fires no other rewrite rules will be processed.

Now add the following to your settings.php file. This is the full code needed for the password authentication to work. You can change the username and password by altering the variables at the top of the script.

if (php_sapi_name() != 'cli' && getenv('SET_PASSWORD') !== FALSE) {
  $username = 'username';
  $password = 'password';

  // PHP-CGI fix.
  $a = base64_decode(substr($_SERVER["REMOTE_USER"], 6));
  if ((strlen($a) == 0) || (strcasecmp($a, ":") == 0)) {
    header('WWW-Authenticate: Basic realm="Private"');
    header('HTTP/1.0 401 Unauthorized');
  }
  else {
    list($name, $pass) = explode(':', $a);
    $_SERVER['PHP_AUTH_USER'] = $name;
    $_SERVER['PHP_AUTH_PW'] = $pass;
  }

  if (!(isset($_SERVER['PHP_AUTH_USER']) && ($_SERVER['PHP_AUTH_USER'] == $username && $_SERVER['PHP_AUTH_PW'] == $password))) {
    header('WWW-Authenticate: Basic realm="This site is protected"');
    header('HTTP/1.0 401 Unauthorized');
    // Fallback page when the user presses cancel.
    echo '<html><head></head><body><h1>Access denied</h1></body></html>';
    exit;
  }
}

With everything in place you will be met with a login prompt the next time you open up the website.

If you don't want to setup an Apache variable then you can use this alternative syntax to detect the site. The following if statement will mean that the authentication triggers if the site URL is staging.example.com.

if (php_sapi_name() != 'cli' && isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME'] == 'staging.example.com') {
}

The good thing about adding these checks is that even if the code does make it to the live box it won't cause an error. However, if you don't want to add this to the settings.php file then there is an alternative. The Drupal settings.php file can contain some low level configuration for cache settings and things like that so it is sometimes written to the repository to include these settings. If you also add the following lines to your settings.php file then a local file called local.settings.php will be included.

// Override settings in this file
if (file_exists('./'. conf_path() .'/local.settings.php')) {
  include_once './'. conf_path() .'/local.settings.php';
}

With this in place you can place the authentication mechanism into the local.settings.php file and it would never be deployed to the live site.

Comments

IDK if you have this from Acquia or Acquia from you but I love it, thx :-)

Permalink

I'm not quite sure where it came from to be honest. It's been a few years!

These days, I just use the Shield module for Drupal (https://www.drupal.org/project/shield).

Name
Philip Norton
Permalink

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
17 + 1 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.