You are here

public function ShieldMiddleware::handle in Shield 8

File

src/ShieldMiddleware.php, line 68

Class

ShieldMiddleware
Middleware for the shield module.

Namespace

Drupal\shield

Code

public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
  $config = $this->configFactory
    ->get('shield.settings');
  $allow_cli = $config
    ->get('allow_cli');
  $user = NULL;
  switch ($config
    ->get('credential_provider')) {
    case 'shield':
      $user = $config
        ->get('credentials.shield.user');
      $pass = $config
        ->get('credentials.shield.pass');
      break;
    case 'key':
      $user = $config
        ->get('credentials.key.user');

      /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
      $storage = $this->entityTypeManager
        ->getStorage('key');

      /** @var \Drupal\key\KeyInterface $pass_key */
      $pass_key = $storage
        ->load($config
        ->get('credentials.key.pass_key'));
      if ($pass_key) {
        $pass = $pass_key
          ->getKeyValue();
      }
      break;
    case 'multikey':

      /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
      $storage = $this->entityTypeManager
        ->getStorage('key');

      /** @var \Drupal\key\KeyInterface $user_pass_key */
      $user_pass_key = $storage
        ->load($config
        ->get('credentials.multikey.user_pass_key'));
      if ($user_pass_key) {
        $values = $user_pass_key
          ->getKeyValues();
        $user = $values['username'];
        $pass = $values['password'];
      }
      break;
  }

  // Check if enabled.
  $shield_enabled = $config
    ->get('shield_enable') && !empty($user);
  if (!$shield_enabled || $type != self::MASTER_REQUEST || PHP_SAPI === 'cli' && $allow_cli) {

    // Bypass:
    // 1. Empty username or Disabled from configuration.
    // 2. Subrequests.
    // 3. CLI requests if CLI is allowed.
    return $this->httpKernel
      ->handle($request, $type, $catch);
  }
  else {

    // Check if user IP is in whitelist.
    $in_whitelist = FALSE;
    if ($whitelist = $config
      ->get('whitelist')) {
      $whitelist = array_filter(array_map('trim', explode("\n", $whitelist)));
      $in_whitelist = IpUtils::checkIp($request
        ->getClientIp(), $whitelist);
    }

    // Check if site domain is in whitelist.
    $allow_domain = FALSE;
    if ($domains = $config
      ->get('domains')) {
      if (!empty($domains)) {
        $allow_domain = $this->pathMatcher
          ->matchPath($request
          ->getHost(), $domains);
      }
    }

    // Check if user has provided credentials.
    if ($request->server
      ->has('PHP_AUTH_USER') && $request->server
      ->has('PHP_AUTH_PW')) {
      $input_user = $request->server
        ->get('PHP_AUTH_USER');
      $input_pass = $request->server
        ->get('PHP_AUTH_PW');
    }
    elseif (!empty($request->server
      ->get('HTTP_AUTHORIZATION'))) {
      list($input_user, $input_pass) = explode(':', base64_decode(substr($request->server
        ->get('HTTP_AUTHORIZATION'), 6)), 2);
    }
    elseif (!empty($request->server
      ->get('REDIRECT_HTTP_AUTHORIZATION'))) {
      list($input_user, $input_pass) = explode(':', base64_decode(substr($request->server
        ->get('REDIRECT_HTTP_AUTHORIZATION'), 6)), 2);
    }
    $authenticated = isset($input_user) && $input_user === $user && hash_equals($pass, $input_pass);
    if ($in_whitelist || $authenticated || $allow_domain) {
      return $this->httpKernel
        ->handle($request, $type, $catch);
    }
  }
  $response = new Response();
  $response->headers
    ->add([
    'WWW-Authenticate' => 'Basic realm="' . strtr($config
      ->get('print'), [
      '[user]' => $user,
      '[pass]' => $pass,
    ]) . '"',
  ]);
  $response
    ->setStatusCode(401);
  return $response;
}