You are here

public function CasGatewayAuthSubscriber::onResponse in CAS 2.x

Handle response event.

This is the client-side implementaton (JS) of CAS gateway authentication.

This works by attaching a JS library to the HTML response that will redirect the user agent to the CAS server for the gateway check.

Unlike the server-side implementation, this one works with page caching so we need to set appropriate cache metadata.

Parameters

\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event: The event.

File

src/Subscriber/CasGatewayAuthSubscriber.php, line 265

Class

CasGatewayAuthSubscriber
Event subscriber for implementing CAS gateway authentication.

Namespace

Drupal\cas\Subscriber

Code

public function onResponse(FilterResponseEvent $event) {
  if (!$event
    ->isMasterRequest()) {
    return;
  }

  // Only implement gateway feature for GET requests, to prevent users from
  // being redirected to CAS server for things like form submissions.
  if (!$event
    ->getRequest()
    ->isMethod('GET')) {
    return;
  }

  // Build up some cache metadata we'll need to attach to the response.
  $cacheMetadata = new CacheableMetadata();
  $response = $event
    ->getResponse();

  // Make sure we're configured for client-side gateway auth.
  $cacheMetadata
    ->addCacheTags([
    'config:cas.settings',
  ]);
  if (!$this->gatewayEnabled || $this->gatewayMethod !== CasHelper::GATEWAY_CLIENT_SIDE) {
    $this
      ->addCacheMetadataToResponse($response, $cacheMetadata);
    return;
  }

  // Only care about anonymous users.
  $cacheMetadata
    ->addCacheContexts([
    'user.roles:authenticated',
  ]);
  if ($this->currentUser
    ->isAuthenticated()) {
    $this
      ->addCacheMetadataToResponse($response, $cacheMetadata);
    return;
  }
  $cacheMetadata
    ->addCacheContexts([
    'request_format',
  ]);
  if (!$response instanceof HtmlResponse) {
    $this
      ->addCacheMetadataToResponse($response, $cacheMetadata);
    return;
  }

  // Some routes we don't want to run on.
  $current_route = $this->routeMatcher
    ->getRouteName();
  if (in_array($current_route, CasHelper::IGNOREABLE_AUTO_LOGIN_ROUTES)) {
    return;
  }

  // Check that the path matches what's been configured.
  // The cache context on the request path condition plugin is url.path
  // which is an "expensive" context, as it makes dynamic page cache
  // quite useless for serving 404 pages. Avoid it if we know the only
  // path we care about is the front page, which is a common config for
  // gateway.
  if (trim($this->gatewayPaths['pages']) === '<front>') {
    $cacheMetadata
      ->addCacheContexts([
      'url.path.is_front',
    ]);
  }
  else {
    $cacheMetadata
      ->addCacheContexts([
      'url.path',
    ]);
  }
  $condition = $this->conditionManager
    ->createInstance('request_path');
  $gatewayPaths = $this->gatewayPaths;
  $condition
    ->setConfiguration($gatewayPaths);
  if (!$this->conditionManager
    ->execute($condition)) {
    $this
      ->addCacheMetadataToResponse($response, $cacheMetadata);
    return;
  }

  // We're good to activate gateway redirect. Add all the cache metadata we've
  // built up to the existing page response and add our front-end library
  // that performs the redirect.
  $this
    ->addCacheMetadataToResponse($response, $cacheMetadata);

  // Start constructing the URL redirect to CAS for gateway auth.
  // Add the current path to the service URL as the 'destination' param,
  // so that when the ServiceController eventually processess the login,
  // it knows to return the user back here.
  $request = $event
    ->getRequest();
  $currentPath = str_replace($request
    ->getSchemeAndHttpHost(), '', $request
    ->getUri());
  $redirectData = new CasRedirectData([
    'destination' => $currentPath,
    'from_gateway' => TRUE,
  ], [
    'gateway' => 'true',
  ]);
  $redirectResponse = $this->casRedirector
    ->buildRedirectResponse($redirectData);
  if ($redirectResponse) {

    // Add our JS library used for redirecting and provide the redirect URL
    // and check frequency.
    $attachments = [];
    $attachments['library'][] = 'cas/client_side_gateway_redirect';
    $attachments['drupalSettings']['cas'] = [
      'gatewayRedirectUrl' => $redirectResponse
        ->getTargetUrl(),
      'recheckTime' => $this->gatewayRecheckTime,
      // We pass the list of known crawlers to the client so it knows not
      // to activate the redirect if the request comes from these. If we did
      // this check server-side, it wouldn't be compatible with caching
      // without varying every cache entry by user agent which is not
      // practical.
      'knownCrawlers' => implode('|', $this
        ->getKnownCrawlersList()),
    ];
    $response
      ->addAttachments($attachments);
  }
}