function drupal_valid_test_ua

Same name and namespace in other branches
  1. 7.x includes/bootstrap.inc \drupal_valid_test_ua()
  2. 9 core/includes/bootstrap.inc \drupal_valid_test_ua()
  3. 8.9.x core/includes/bootstrap.inc \drupal_valid_test_ua()
  4. 10 core/includes/bootstrap.inc \drupal_valid_test_ua()

Returns the test prefix if this is an internal request from a test.

Parameters

string $new_prefix: Internal use only. A new prefix to be stored.

Return value

string|false Either the simpletest prefix (the string "simpletest" followed by any number of digits) or FALSE if the user agent does not contain a valid HMAC and timestamp.

15 calls to drupal_valid_test_ua()
CoreServiceProvider::registerTest in core/lib/Drupal/Core/CoreServiceProvider.php
Registers services and event subscribers for a site under test.
DrupalKernel::bootEnvironment in core/lib/Drupal/Core/DrupalKernel.php
Setup a consistent PHP environment.
DrupalKernel::findSitePath in core/lib/Drupal/Core/DrupalKernel.php
Returns the appropriate site directory for a request.
drupal_generate_test_ua in core/includes/bootstrap.inc
Generates a user agent string with a HMAC and timestamp for tests.
ExtensionDiscovery::scan in core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
Discovers available extensions of a given type.

... See full list

File

core/includes/bootstrap.inc, line 164

Code

function drupal_valid_test_ua($new_prefix = NULL) {
    static $test_prefix;
    if (isset($new_prefix)) {
        $test_prefix = $new_prefix;
    }
    if (isset($test_prefix)) {
        return $test_prefix;
    }
    // Unless the below User-Agent and HMAC validation succeeds, we are not in
    // a test environment.
    $test_prefix = FALSE;
    // A valid test request will contain a hashed and salted authentication code.
    // Check if this code is present in a cookie or custom user agent string.
    $http_user_agent = $_SERVER['HTTP_USER_AGENT'] ?? NULL;
    $user_agent = $_COOKIE['SIMPLETEST_USER_AGENT'] ?? $http_user_agent;
    if (isset($user_agent) && preg_match("/^simple(\\w+\\d+):(.+):(.+):(.+)\$/", $user_agent, $matches)) {
        [
            ,
            $prefix,
            $time,
            $salt,
            $hmac,
        ] = $matches;
        $check_string = $prefix . ':' . $time . ':' . $salt;
        // Read the hash salt prepared by drupal_generate_test_ua().
        // This function is called before settings.php is read and Drupal's error
        // handlers are set up. While Drupal's error handling may be properly
        // configured on production sites, the server's PHP error_reporting may not.
        // Ensure that no information leaks on production sites.
        $test_db = new TestDatabase($prefix);
        $key_file = DRUPAL_ROOT . '/' . $test_db->getTestSitePath() . '/.htkey';
        if (!is_readable($key_file) || is_dir($key_file)) {
            header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
            exit;
        }
        $private_key = file_get_contents($key_file);
        // The string from drupal_generate_test_ua() is 74 bytes long. If we don't
        // have it, tests cannot be allowed.
        if (empty($private_key) || strlen($private_key) < 74) {
            header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
            exit;
        }
        // The file properties add more entropy not easily accessible to others.
        $key = $private_key . filectime(__FILE__) . fileinode(__FILE__);
        $time_diff = time() - $time;
        $test_hmac = Crypt::hmacBase64($check_string, $key);
        // Since we are making a local request a 600 second time window is allowed,
        // and the HMAC must match.
        if ($time_diff >= 0 && $time_diff <= 600 && hash_equals($test_hmac, $hmac)) {
            $test_prefix = $prefix;
        }
        else {
            header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden (SIMPLETEST_USER_AGENT invalid)');
            exit;
        }
    }
    return $test_prefix;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.