ip_login-4.x-dev/src/StackMiddleware/EarlyIpLoginMiddleware.php

src/StackMiddleware/EarlyIpLoginMiddleware.php
<?php

namespace Drupal\ip_login\StackMiddleware;

use Drupal\ip_login\IpLoginController;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;

/**
 * Provides a HTTP middleware to implement IP based login.
 *
 * The role of this "early" middleware is to determine if a user can be logged
 * in automatically. If so, a request attribute is set and IpLoginMiddleware
 * does the actual login, because that needs to happen after the Drupal kernel
 * is initialized by \Drupal\Core\StackMiddleware\KernelPreHandle.
 */
class EarlyIpLoginMiddleware implements HttpKernelInterface {

  /**
   * The service container.
   */
  protected ContainerInterface $container;

  /**
   * The decorated kernel.
   *
   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
   */
  protected $httpKernel;

  /**
   * The session service name.
   *
   * @var string
   */
  protected $sessionServiceName;

  /**
   * Cache the front page path.
   *
   * @var string
   */
  protected $frontPage;

  /**
   * Constructs an EarlyIpLoginMiddleware.
   *
   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
   *   The decorated kernel.
   * @param string $service_name
   *   The name of the session service, defaults to "session".
   */
  public function __construct(HttpKernelInterface $http_kernel, $service_name = 'session') {
    $this->httpKernel = $http_kernel;
    $this->sessionServiceName = $service_name;
  }

  /**
   * Sets the service container.
   */
  public function setContainer(ContainerInterface $container): void {
    $this->container = $container;
  }

  /**
   * {@inheritdoc}
   */
  public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = TRUE): Response {
    // Bail out early if we already determined that we can not auto-login.
    if ($request->cookies->get('ipLoginAttempted', NULL)) {
      return $this->httpKernel->handle($request, $type, $catch);
    }

    $uid = NULL;
    if ($type === self::MAIN_REQUEST && PHP_SAPI !== 'cli') {
      // Put the current (unprepared) request on the stack so we can initialize
      // the session.
      $this->container->get('request_stack')->push($request);

      $session = $this->container->get($this->sessionServiceName);
      $session->start();
      $uid = $session->get('uid');

      // Remove the unprepared request from the stack,
      // \Drupal\Core\StackMiddleware\KernelPreHandle::handle() adds the proper
      // one.
      $this->container->get('request_stack')->pop();
    }

    // Do nothing if the user is logged in, or if this is not a web request.
    if ($uid || PHP_SAPI === 'cli') {
      return $this->httpKernel->handle($request, $type, $catch);
    }

    if ($this->ipLoginCheckPath($request) === FALSE) {
      return $this->httpKernel->handle($request, $type, $catch);
    }

    // Check the user's IP.
    if ($matched_uid = IpLoginController::checkIpLoginExists($request)) {
      // For clarity about every scenario, use extensive logic.
      $can_login_as_another_user = $request->cookies->get('ipLoginAsDifferentUser', NULL);
      if ($can_login_as_another_user === NULL) {
        // First time login for user, so log in automatically.
        $request->attributes->set('ip_login_uid', $matched_uid);
      }
      elseif ($can_login_as_another_user == FALSE) {
        // User logged out, but is not allowed to use another user, so log in
        // again.
        $request->attributes->set('ip_login_uid', $matched_uid);
      }
      elseif ($can_login_as_another_user == TRUE) {
        // User logged out, and is allowed to login as another user, so do
        // nothing, just stay on this page and wait for user action.
      }
      else {
        // Do automatic login.
        $request->attributes->set('ip_login_uid', $matched_uid);
      }
    }
    $response = $this->httpKernel->handle($request, $type, $catch);

    // If we determined that we can't auto-login the user, set a session cookie
    // so we don't repeat the user IP check for this browser session.
    if (empty($matched_uid)) {
      $response->headers->setCookie(new Cookie('ipLoginAttempted', 1));
    }
    return $response;
  }

  /**
   * Checks path of current page matches to see if IP login should occur.
   *
   * @return bool
   *   True if the path matches the configured pages, false otherwise.
   */
  private function ipLoginCheckPath(Request $request): bool {
    $config = $this->container->get('config.factory')->get('ip_login.settings');
    $check_mode = $config->get('check_mode');
    $paths = $config->get('paths');
    if (!empty($paths)) {
      // Compare with the path with allowed pages.
      $path = $request->getPathInfo();
      if ($path === '/') {
        // If the path is the front page, use the front page path from config.
        $path = $this->getFrontPagePath();
      }

      $page_match = $this->matchPath($path, $paths);
      // When $check_mode has a value of 0, the IP check happens on
      // all paths except those listed in $paths. When set to 1, IPs
      // are checked only on those paths listed in $paths.
      $page_match = !($check_mode xor $page_match);

      // If we don't have a path match, don't log in.
      if (!$page_match) {
        return FALSE;
      }
    }

    // All is well, continue with login.
    return TRUE;
  }

  /**
   * Checks if a path matches any pattern in a set of patterns.
   *
   * @param string $path
   *   The path to match.
   * @param string $patterns
   *   A set of patterns separated by a newline.
   *
   * @return bool
   *   TRUE if the path matches a pattern, FALSE otherwise.
   */
  private function matchPath(string $path, string $patterns): bool {
    // Convert path settings to a regular expression.
    $to_replace = [
      // Replace newlines with a logical 'or'.
      '/(\r\n?|\n)/',
      // Quote asterisks.
      '/\\\\\*/',
      // Quote <front> keyword.
      '/(^|\|)\\\\<front\\\\>($|\|)/',
    ];
    $replacements = [
      '|',
      '.*',
      '\1' . preg_quote($this->getFrontPagePath(), '/') . '\2',
    ];
    $patterns_quoted = preg_quote($patterns, '/');
    $regex = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
    return (bool) preg_match($regex, $path);
  }

  /**
   * Gets the current front page path.
   *
   * @return string
   *   The front page path.
   */
  protected function getFrontPagePath(): string {
    // Lazy-load front page config.
    if (!isset($this->frontPage)) {
      $this->frontPage = $this->container->get('config.factory')
        ->get('system.site')
        ->get('page.front');
    }
    return $this->frontPage;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc