Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / core / modules / basic_auth / src / Authentication / Provider / BasicAuth.php
index c72e3f0c0168e24e49d9a694257d079d85910d09..01034f4a8c44d0406cf2900c8dd13868c70d5cda 100644 (file)
@@ -5,12 +5,13 @@ namespace Drupal\basic_auth\Authentication\Provider;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Authentication\AuthenticationProviderInterface;
 use Drupal\Core\Authentication\AuthenticationProviderChallengeInterface;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Flood\FloodInterface;
+use Drupal\Core\Http\Exception\CacheableUnauthorizedHttpException;
 use Drupal\user\UserAuthInterface;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
 
 /**
  * HTTP Basic authentication provider.
@@ -126,11 +127,35 @@ class BasicAuth implements AuthenticationProviderInterface, AuthenticationProvid
    * {@inheritdoc}
    */
   public function challengeException(Request $request, \Exception $previous) {
-    $site_name = $this->configFactory->get('system.site')->get('name');
+    $site_config = $this->configFactory->get('system.site');
+    $site_name = $site_config->get('name');
     $challenge = SafeMarkup::format('Basic realm="@realm"', [
       '@realm' => !empty($site_name) ? $site_name : 'Access restricted',
     ]);
-    return new UnauthorizedHttpException((string) $challenge, 'No authentication credentials provided.', $previous);
+
+    // A 403 is converted to a 401 here, but it doesn't matter what the
+    // cacheability was of the 403 exception: what matters here is that
+    // authentication credentials are missing, i.e. that this request was made
+    // as the anonymous user.
+    // Therefore, all we must do, is make this response:
+    // 1. vary by whether the current user has the 'anonymous' role or not. This
+    //    works fine because:
+    //    - Thanks to \Drupal\basic_auth\PageCache\DisallowBasicAuthRequests,
+    //      Page Cache never caches a response whose request has Basic Auth
+    //      credentials.
+    //    - Dynamic Page Cache will cache a different result for when the
+    //      request is unauthenticated (this 401) versus authenticated (some
+    //      other response)
+    // 2. have the 'config:user.role.anonymous' cache tag, because the only
+    //    reason this 401 would no longer be a 401 is if permissions for the
+    //    'anonymous' role change, causing that cache tag to be invalidated.
+    // @see \Drupal\Core\EventSubscriber\AuthenticationSubscriber::onExceptionSendChallenge()
+    // @see \Drupal\Core\EventSubscriber\ClientErrorResponseSubscriber()
+    // @see \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onAllResponds()
+    $cacheability = CacheableMetadata::createFromObject($site_config)
+      ->addCacheTags(['config:user.role.anonymous'])
+      ->addCacheContexts(['user.roles:anonymous']);
+    return new CacheableUnauthorizedHttpException($cacheability, (string) $challenge, 'No authentication credentials provided.', $previous);
   }
 
 }