core/lib/Drupal/Core/Access/AccessResult.php | 3 ++- .../DefaultExceptionHtmlSubscriber.php | 4 +++- .../Core/Render/MainContent/HtmlRenderer.php | 8 ++++++++ core/lib/Drupal/Core/Routing/AccessAwareRouter.php | 22 +++++++++------------- .../contact/src/Access/ContactPageAccess.php | 2 +- .../contact/src/Tests/ContactPersonalTest.php | 2 ++ 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/core/lib/Drupal/Core/Access/AccessResult.php b/core/lib/Drupal/Core/Access/AccessResult.php index d515933..0a866e7 100644 --- a/core/lib/Drupal/Core/Access/AccessResult.php +++ b/core/lib/Drupal/Core/Access/AccessResult.php @@ -339,7 +339,8 @@ public function setCacheMaxAge($max_age) { * @return $this */ public function cachePerRole() { - $this->addCacheContexts(array('user.roles')); + $this->addCacheContexts(['user.roles']) + ->addCacheTags(['config:user_role_list']); return $this; } diff --git a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php index a98bf57..079c980 100644 --- a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php @@ -111,8 +111,10 @@ protected function makeSubrequest(GetResponseForExceptionEvent $event, $url, $st } try { - // Persist the 'exception' attribute to the subrequest. + // Persist the 'exception' and '_access_result' attributes to the + // subrequest. $sub_request->attributes->set('exception', $request->attributes->get('exception')); + $sub_request->attributes->set('_access_result', $request->attributes->get('_access_result')); // Carry over the session to the subrequest. if ($session = $request->getSession()) { diff --git a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php index 0bcdc5d..e9c21ba 100644 --- a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php +++ b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php @@ -10,6 +10,7 @@ use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheableInterface; use Drupal\Core\Controller\TitleResolverInterface; use Drupal\Core\Display\PageVariantInterface; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -145,6 +146,13 @@ public function renderResponse(array $main_content, Request $request, RouteMatch // Set the generator in the HTTP header. list($version) = explode('.', \Drupal::VERSION, 2); + // Merge the request's access result cacheability metadata, if it has any. + $access_result = $request->attributes->get('_access_result'); + if ($access_result instanceof CacheableInterface) { + $cache_contexts = Cache::mergeTags($cache_tags, $access_result->getCacheContexts()); + $cache_tags = Cache::mergeTags($cache_tags, $access_result->getCacheTags()); + } + return new Response($content, 200,[ 'X-Drupal-Cache-Tags' => implode(' ', $cache_tags), 'X-Drupal-Cache-Contexts' => implode(' ', $cache_contexts), diff --git a/core/lib/Drupal/Core/Routing/AccessAwareRouter.php b/core/lib/Drupal/Core/Routing/AccessAwareRouter.php index 93a31c3..569d92c 100644 --- a/core/lib/Drupal/Core/Routing/AccessAwareRouter.php +++ b/core/lib/Drupal/Core/Routing/AccessAwareRouter.php @@ -92,25 +92,21 @@ public function matchRequest(Request $request) { // the current user. // @todo This will be removed in https://www.drupal.org/node/2229145. $this->account->id(); - $this->checkAccess($request); + // The cacheability (if any) of this request's access check result must be + // applied to the response. + $access_result = $this->accessManager->checkRequest($request, $this->account, TRUE); + if (!$request->attributes->has('_access_result')) { + $request->attributes->set('_access_result', $access_result); + } + if (!$access_result->isAllowed()) { + throw new AccessDeniedHttpException(); + } // We can not return $parameters because the access check can change the // request attributes. return $request->attributes->all(); } /** - * Apply access check service to the route and parameters in the request. - * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request to access check. - */ - protected function checkAccess(Request $request) { - if (!$this->accessManager->checkRequest($request, $this->account)) { - throw new AccessDeniedHttpException(); - } - } - - /** * {@inheritdoc} */ public function getRouteCollection() { diff --git a/core/modules/contact/src/Access/ContactPageAccess.php b/core/modules/contact/src/Access/ContactPageAccess.php index 97d6b06..cb5630c 100644 --- a/core/modules/contact/src/Access/ContactPageAccess.php +++ b/core/modules/contact/src/Access/ContactPageAccess.php @@ -62,7 +62,7 @@ public function access(UserInterface $user, AccountInterface $account) { // Anonymous users cannot have contact forms. if ($contact_account->isAnonymous()) { - return AccessResult::forbidden(); + return AccessResult::forbidden()->cachePerRole(); } // Users may not contact themselves. diff --git a/core/modules/contact/src/Tests/ContactPersonalTest.php b/core/modules/contact/src/Tests/ContactPersonalTest.php index a1229d1..ab84697 100644 --- a/core/modules/contact/src/Tests/ContactPersonalTest.php +++ b/core/modules/contact/src/Tests/ContactPersonalTest.php @@ -151,11 +151,13 @@ function testPersonalContactAccess() { // Test that anonymous users can access admin user's contact form. $this->drupalGet('user/' . $this->adminUser->id() . '/contact'); $this->assertResponse(200); + $this->assertCacheTag('config:user_role_list'); // Revoke the personal contact permission for the anonymous user. user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access user contact forms')); $this->drupalGet('user/' . $this->contactUser->id() . '/contact'); $this->assertResponse(403); + $this->assertCacheTag('config:user_role_list'); $this->drupalGet('user/' . $this->adminUser->id() . '/contact'); $this->assertResponse(403);