You are here

class AccessDeniedSubscriber in SAML Authentication 4.x

Same name and namespace in other branches
  1. 8.3 src/EventSubscriber/AccessDeniedSubscriber.php \Drupal\samlauth\EventSubscriber\AccessDeniedSubscriber
  2. 8.2 src/EventSubscriber/AccessDeniedSubscriber.php \Drupal\samlauth\EventSubscriber\AccessDeniedSubscriber

Exception subscriber intercepting various "access denied" situations.

Hierarchy

  • class \Drupal\samlauth\EventSubscriber\AccessDeniedSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface

Expanded class hierarchy of AccessDeniedSubscriber

1 string reference to 'AccessDeniedSubscriber'
samlauth.services.yml in ./samlauth.services.yml
samlauth.services.yml
1 service uses AccessDeniedSubscriber
samlauth.event_subscriber.user_access_denied in ./samlauth.services.yml
Drupal\samlauth\EventSubscriber\AccessDeniedSubscriber

File

src/EventSubscriber/AccessDeniedSubscriber.php, line 20

Namespace

Drupal\samlauth\EventSubscriber
View source
class AccessDeniedSubscriber implements EventSubscriberInterface {

  /**
   * Routes which can throw TooManyRequestsHttpException.
   *
   * @var array
   */
  const FLOOD_CONTROL_ROUTES = [
    'samlauth.saml_controller_acs',
    'samlauth.saml_controller_sls',
  ];

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $account;

  /**
   * Constructs a new redirect subscriber.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user.
   */
  public function __construct(AccountInterface $account) {
    $this->account = $account;
  }

  /**
   * Redirects users when access is denied.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
   *   The event to process.
   */
  public function onException(GetResponseForExceptionEvent $event) {
    $exception = $event
      ->getException();

    // If our own routes threw a TooManyRequestsHttpException, don't spend time
    // redirecting to another page and rendering that. (Rendering would need to
    // be done from scratch because the page needs to include includes the
    // error message). Just a simple text string should do.
    if ($exception instanceof TooManyRequestsHttpException) {
      $route_name = $this
        ->getCurrentRouteName($event);
      if (in_array($route_name, self::FLOOD_CONTROL_ROUTES)) {
        $event
          ->setResponse(new Response($exception
          ->getMessage(), $exception
          ->getStatusCode()));
      }
    }

    // Authenticated access to /saml/login redirects to the user profile. This
    // is done in an event subscriber (rather than just opening up the route
    // and returning a redirect response from the controller route) because
    // this is what Core does for /user/login too. (Maybe it's a bit faster.
    // Maybe it's easier to override.) All our other routes do their
    // redirecting inside SamlController because there's more logic behind the
    // decision where to route.
    if ($exception instanceof AccessDeniedHttpException && $this->account
      ->isAuthenticated() && $this
      ->getCurrentRouteName($event) === 'samlauth.saml_controller_login') {
      $redirect_url = Url::fromRoute('entity.user.canonical', [
        'user' => $this->account
          ->id(),
      ], [
        'absolute' => TRUE,
      ]);
      $event
        ->setResponse(new RedirectResponse($redirect_url
        ->toString()));
    }
  }

  /**
   * Gets the current route name.
   *
   * @param \Symfony\Component\HttpKernel\Event\KernelEvent $event
   *   The event we're subscribed to.
   *
   * @return string
   *   The current route name.
   */
  private function getCurrentRouteName(KernelEvent $event) {

    // This method is just a reminder: we can either get the current request
    // from the event, or we can inject the current_route_match service if ever
    // necessary. There seems to be no consensus on what is 'better'.
    return RouteMatch::createFromRequest($event
      ->getRequest())
      ->getRouteName();
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {

    // Use a higher priority than
    // \Drupal\Core\EventSubscriber\ExceptionLoggingSubscriber, because there's
    // no need to log the exception if we can redirect.
    $events[KernelEvents::EXCEPTION][] = [
      'onException',
      75,
    ];
    return $events;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AccessDeniedSubscriber::$account protected property The current user.
AccessDeniedSubscriber::FLOOD_CONTROL_ROUTES constant Routes which can throw TooManyRequestsHttpException.
AccessDeniedSubscriber::getCurrentRouteName private function Gets the current route name.
AccessDeniedSubscriber::getSubscribedEvents public static function
AccessDeniedSubscriber::onException public function Redirects users when access is denied.
AccessDeniedSubscriber::__construct public function Constructs a new redirect subscriber.