Question

I'm developing a new app and decided to protect cloud staging server with Basic authentication.

I'm using nginx, so the config looks like this:

location / {
  auth_basic "Restricted";
  auth_basic_user_file .htpasswd;
  try_files $uri $uri/ @php_mvc;
}

My MVC app also has an "admin" module, which is protected using HTTP Digest:

$realm = 'Access Restricted.';
$nonce = md5(uniqid());
$opaque = md5(uniqid());
$valid = false;

$headers = System::getallheaders();
if (array_key_exists('Authorization', $headers)) {
    $authHeader = substr($headers['Authorization'],  strlen('Digest'));
    $parsed = array();
    foreach (explode(',', $authHeader) as $pair) {
        if (substr(trim($pair), 0, 4) == ($_u = 'uri=')) {
            $parsed[substr($_u, 0, -1)] = trim(substr($pair, 5), ' "');
        } else {
            $vals = explode('=', $pair);
            $parsed[trim($vals[0])] = trim($vals[1], '" ');
        }
    }

    $A1 = md5(self::DIGEST_USERNAME . ':' . $parsed['realm'] . ':' . self::DIGEST_PASSWORD);
    $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $parsed['uri']);
    $response = md5($A1 . ':' . $parsed['nonce'] . ':' . $A2);

    $valid = ($response == $parsed['response']);
}

if (!$valid) {
    header('HTTP/1.1 401 Unauthorized');
    header('Content-Type: text/html');
    header(sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', $realm, $nonce, $opaque));
    echo 'Access denied.';
    exit();
}

...

function getallheaders()
{
    $headers = null;
    foreach ($_SERVER as $name => $value) {
        if (substr($name, 0, 5) == 'HTTP_') {
            $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
            $headers[$name] = $value;
        } else if ($name == 'CONTENT_TYPE') {
            $headers['Content-Type'] = $value;
        } else if ($name == 'CONTENT_LENGTH') {
            $headers['Content-Length'] = $value;
        }
    }
    return $headers;
}

So, the problem is that PHP-based Digest authentication does not work, since $_SERVER['HTTP_AUTHORIZATION'] by that time is already taken by the result of Basic authentication: $_SERVER['HTTP_AUTHORIZATION'] = "Basic S1aGUzpuZXzzdXRl".

Is there a way to separate results of basic & digest authentications?

Thanks!

Was it helpful?

Solution

No. You either need to use the same Authentication mechanism on server and on backend side (which will not work with every mechanism) or alternatively turn off Authentication on one of these sides.

The latter means that either you turn it off on backend and just trust the user name provided by the server (in this case it's possible to bypass authentication in the internal network) or you turn it off on server side and let the backend do the job.

If you even want to use different usernames/passwords on server and backend (and the user has to enter both of them) the only one option you have is to implement a html/cookie/session based login page in the backend and use http based authentication on server side

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top