summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxjm2018-02-21 16:58:22 (GMT)
committerxjm2018-02-21 16:59:15 (GMT)
commita2ae6fd09c14bc0993a919b93aab512fa68a29e0 (patch)
tree7fb043c4757e0137edbf6f22335e4abecc95a74d
parent987e147c0de746605efee78a3cb4bbc230bd987a (diff)
SA-CORE-2018-001 by cashwilliams, catch, cilefen, droplet, dawehner, bonus, agentrickard, David_Rothstein, Chi, Gábor Hojtsy, Heine, Wim Leers, Schnitzel, drpal, effulgentsia, tedbow, tim.plunkett, tstoeckler, xjm, will_c, stefan.r, samuel.mortenson, larowlan, greggles, logaritmisk, mpdonadio, pwolanin, plach
-rw-r--r--core/misc/drupal.es6.js5
-rw-r--r--core/misc/drupal.js2
-rw-r--r--core/modules/comment/src/Controller/CommentController.php5
-rw-r--r--core/modules/comment/tests/src/Functional/CommentAccessTest.php120
-rw-r--r--core/modules/comment/tests/src/Functional/CommentNonNodeTest.php1
-rw-r--r--core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php1
-rw-r--r--core/modules/node/node.install12
-rw-r--r--core/modules/node/src/NodeGrantDatabaseStorage.php3
-rw-r--r--core/modules/node/tests/src/Functional/NodeAccessLanguageFallbackTest.php131
-rw-r--r--core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php77
-rw-r--r--core/modules/system/src/Form/SystemBrandingOffCanvasForm.php18
-rw-r--r--core/modules/system/src/Form/SystemMenuOffCanvasForm.php3
12 files changed, 367 insertions, 11 deletions
diff --git a/core/misc/drupal.es6.js b/core/misc/drupal.es6.js
index 48f0510..546527a 100644
--- a/core/misc/drupal.es6.js
+++ b/core/misc/drupal.es6.js
@@ -239,9 +239,10 @@ window.Drupal = { behaviors: {}, locale: {} };
Drupal.checkPlain = function (str) {
str = str.toString()
.replace(/&/g, '&')
- .replace(/"/g, '"')
.replace(/</g, '&lt;')
- .replace(/>/g, '&gt;');
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;')
+ .replace(/'/g, '&#39;');
return str;
};
diff --git a/core/misc/drupal.js b/core/misc/drupal.js
index e080caa..39a74e4 100644
--- a/core/misc/drupal.js
+++ b/core/misc/drupal.js
@@ -48,7 +48,7 @@ window.Drupal = { behaviors: {}, locale: {} };
};
Drupal.checkPlain = function (str) {
- str = str.toString().replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ str = str.toString().replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
return str;
};
diff --git a/core/modules/comment/src/Controller/CommentController.php b/core/modules/comment/src/Controller/CommentController.php
index a01106d..5602338 100644
--- a/core/modules/comment/src/Controller/CommentController.php
+++ b/core/modules/comment/src/Controller/CommentController.php
@@ -279,9 +279,12 @@ class CommentController extends ControllerBase {
// Check if the user has the proper permissions.
$access = AccessResult::allowedIfHasPermission($account, 'post comments');
+ // If commenting is open on the entity.
$status = $entity->{$field_name}->status;
$access = $access->andIf(AccessResult::allowedIf($status == CommentItemInterface::OPEN)
- ->addCacheableDependency($entity));
+ ->addCacheableDependency($entity))
+ // And if user has access to the host entity.
+ ->andIf(AccessResult::allowedIf($entity->access('view')));
// $pid indicates that this is a reply to a comment.
if ($pid) {
diff --git a/core/modules/comment/tests/src/Functional/CommentAccessTest.php b/core/modules/comment/tests/src/Functional/CommentAccessTest.php
new file mode 100644
index 0000000..4094ec6
--- /dev/null
+++ b/core/modules/comment/tests/src/Functional/CommentAccessTest.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace Drupal\Tests\comment\Functional;
+
+use Drupal\comment\Entity\Comment;
+use Drupal\comment\Tests\CommentTestTrait;
+use Drupal\node\Entity\NodeType;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests comment administration and preview access.
+ *
+ * @group comment
+ */
+class CommentAccessTest extends BrowserTestBase {
+
+ use CommentTestTrait;
+
+ /**
+ * {@inheritdoc}
+ */
+ public static $modules = [
+ 'node',
+ 'comment',
+ ];
+
+ /**
+ * Node for commenting.
+ *
+ * @var \Drupal\node\NodeInterface
+ */
+ protected $unpublishedNode;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $node_type = NodeType::create([
+ 'type' => 'article',
+ 'name' => 'Article',
+ ]);
+ $node_type->save();
+ $node_author = $this->drupalCreateUser([
+ 'create article content',
+ 'access comments',
+ ]);
+
+ $this->drupalLogin($this->drupalCreateUser([
+ 'edit own comments',
+ 'skip comment approval',
+ 'post comments',
+ 'access comments',
+ 'access content',
+ ]));
+
+ $this->addDefaultCommentField('node', 'article');
+ $this->unpublishedNode = $this->createNode([
+ 'title' => 'This is unpublished',
+ 'uid' => $node_author->id(),
+ 'status' => 0,
+ 'type' => 'article',
+ ]);
+ $this->unpublishedNode->save();
+ }
+
+ /**
+ * Tests commenting disabled for access-blocked entities.
+ */
+ public function testCannotCommentOnEntitiesYouCannotView() {
+ $assert = $this->assertSession();
+
+ $comment_url = 'comment/reply/node/' . $this->unpublishedNode->id() . '/comment';
+
+ // Commenting on an unpublished node results in access denied.
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(403);
+
+ // Publishing the node grants access.
+ $this->unpublishedNode->setPublished(TRUE)->save();
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(200);
+ }
+
+ /**
+ * Tests cannot view comment reply form on entities you cannot view.
+ */
+ public function testCannotViewCommentReplyFormOnEntitiesYouCannotView() {
+ $assert = $this->assertSession();
+
+ // Create a comment on an unpublished node.
+ $comment = Comment::create([
+ 'entity_type' => 'node',
+ 'name' => 'Tony',
+ 'hostname' => 'magic.example.com',
+ 'mail' => 'foo@example.com',
+ 'subject' => 'Comment on unpublished node',
+ 'entity_id' => $this->unpublishedNode->id(),
+ 'comment_type' => 'comment',
+ 'field_name' => 'comment',
+ 'pid' => 0,
+ 'uid' => $this->unpublishedNode->getOwnerId(),
+ 'status' => 1,
+ ]);
+ $comment->save();
+
+ $comment_url = 'comment/reply/node/' . $this->unpublishedNode->id() . '/comment/' . $comment->id();
+
+ // Replying to a comment on an unpublished node results in access denied.
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(403);
+
+ // Publishing the node grants access.
+ $this->unpublishedNode->setPublished(TRUE)->save();
+ $this->drupalGet($comment_url);
+ $assert->statusCodeEquals(200);
+ }
+
+}
diff --git a/core/modules/comment/tests/src/Functional/CommentNonNodeTest.php b/core/modules/comment/tests/src/Functional/CommentNonNodeTest.php
index 5889d69..7580bb2 100644
--- a/core/modules/comment/tests/src/Functional/CommentNonNodeTest.php
+++ b/core/modules/comment/tests/src/Functional/CommentNonNodeTest.php
@@ -450,6 +450,7 @@ class CommentNonNodeTest extends BrowserTestBase {
'post comments',
'administer comment fields',
'administer comment types',
+ 'view test entity',
]);
$this->drupalLogin($limited_user);
diff --git a/core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php b/core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php
index a7fe6b5..72a941f 100644
--- a/core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php
+++ b/core/modules/comment/tests/src/Functional/CommentTokenReplaceTest.php
@@ -144,6 +144,7 @@ class CommentTokenReplaceTest extends CommentTestBase {
// Create a user and a comment.
$user = User::create(['name' => 'alice']);
+ $user->activate();
$user->save();
$this->postComment($user, 'user body', 'user subject', TRUE);
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index 6469245..9b0cda8 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -255,3 +255,15 @@ function node_update_8400() {
$schema['fields']['realm']['description'] = 'The realm in which the user must possess the grant ID. Modules can define one or more realms by implementing hook_node_grants().';
Database::getConnection()->schema()->changeField('node_access', 'realm', 'realm', $schema['fields']['realm']);
}
+
+/**
+ * Run a node access rebuild, if required.
+ */
+function node_update_8401() {
+ // Get the list of node access modules.
+ $modules = \Drupal::moduleHandler()->getImplementations('node_grants');
+ // If multilingual usage, then rebuild node access.
+ if (count($modules) > 0 && \Drupal::languageManager()->isMultilingual()) {
+ node_access_needs_rebuild(TRUE);
+ }
+}
diff --git a/core/modules/node/src/NodeGrantDatabaseStorage.php b/core/modules/node/src/NodeGrantDatabaseStorage.php
index f6ae1f6..b4947c9 100644
--- a/core/modules/node/src/NodeGrantDatabaseStorage.php
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php
@@ -211,6 +211,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface {
$query = $this->database->insert('node_access')->fields(['nid', 'langcode', 'fallback', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete']);
// If we have defined a granted langcode, use it. But if not, add a grant
// for every language this node is translated to.
+ $fallback_langcode = $node->getUntranslated()->language()->getId();
foreach ($grants as $grant) {
if ($realm && $realm != $grant['realm']) {
continue;
@@ -227,7 +228,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface {
$grant['nid'] = $node->id();
$grant['langcode'] = $grant_langcode;
// The record with the original langcode is used as the fallback.
- if ($grant['langcode'] == $node->language()->getId()) {
+ if ($grant['langcode'] == $fallback_langcode) {
$grant['fallback'] = 1;
}
else {
diff --git a/core/modules/node/tests/src/Functional/NodeAccessLanguageFallbackTest.php b/core/modules/node/tests/src/Functional/NodeAccessLanguageFallbackTest.php
new file mode 100644
index 0000000..4beacc3
--- /dev/null
+++ b/core/modules/node/tests/src/Functional/NodeAccessLanguageFallbackTest.php
@@ -0,0 +1,131 @@
+<?php
+
+namespace Drupal\Tests\node\Functional;
+
+use Drupal\language\Entity\ConfigurableLanguage;
+
+/**
+ * Tests that the node_access system stores the proper fallback marker.
+ *
+ * @group node
+ */
+class NodeAccessLanguageFallbackTest extends NodeTestBase {
+
+ /**
+ * Enable language and a non-language-aware node access module.
+ *
+ * @var array
+ */
+ public static $modules = ['language', 'node_access_test', 'content_translation'];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ // After enabling a node access module, the {node_access} table has to be
+ // rebuilt.
+ node_access_rebuild();
+
+ // Add Hungarian, Catalan, and Afrikaans.
+ ConfigurableLanguage::createFromLangcode('hu')->save();
+ ConfigurableLanguage::createFromLangcode('ca')->save();
+ ConfigurableLanguage::createFromLangcode('af')->save();
+
+ // Enable content translation for the current entity type.
+ \Drupal::service('content_translation.manager')->setEnabled('node', 'page', TRUE);
+ }
+
+ /**
+ * Tests node access fallback handling with multiple node languages.
+ */
+ public function testNodeAccessLanguageFallback() {
+ // The node_access_test module allows nodes to be marked private. We need to
+ // ensure that system honors the fallback system of node access properly.
+ // Note that node_access_test_language is language-sensitive and does not
+ // apply to the fallback test.
+
+ // Create one node in Hungarian and marked as private.
+ $node = $this->drupalCreateNode([
+ 'body' => [[]],
+ 'langcode' => 'hu',
+ 'private' => [['value' => 1]],
+ 'status' => 1,
+ ]);
+
+ // There should be one entry in node_access, with fallback set to hu.
+ $this->checkRecords(1, 'hu');
+
+ // Create a translation user.
+ $admin = $this->drupalCreateUser([
+ 'bypass node access',
+ 'administer nodes',
+ 'translate any entity',
+ 'administer content translation',
+ ]);
+ $this->drupalLogin($admin);
+ $this->drupalGet('node/' . $node->id() . '/translations');
+ $this->assertSession()->statusCodeEquals(200);
+
+ // Create a Catalan translation through the UI.
+ $url_options = ['language' => \Drupal::languageManager()->getLanguage('ca')];
+ $this->drupalGet('node/' . $node->id() . '/translations/add/hu/ca', $url_options);
+ $this->assertSession()->statusCodeEquals(200);
+ // Save the form.
+ $this->getSession()->getPage()->pressButton('Save (this translation)');
+ $this->assertSession()->statusCodeEquals(200);
+
+ // Check the node access table.
+ $this->checkRecords(2, 'hu');
+
+ // Programmatically create a translation. This process lets us check that
+ // both forms and code behave in the same way.
+ $storage = \Drupal::entityTypeManager()->getStorage('node');
+ // Reload the node.
+ $node = $storage->load(1);
+ // Create an Afrikaans translation.
+ $translation = $node->addTranslation('af');
+ $translation->title->value = $this->randomString();
+ $translation->status = 1;
+ $node->save();
+
+ // Check the node access table.
+ $this->checkRecords(3, 'hu');
+
+ // For completeness, edit the Catalan version again.
+ $this->drupalGet('node/' . $node->id() . '/edit', $url_options);
+ $this->assertSession()->statusCodeEquals(200);
+ // Save the form.
+ $this->getSession()->getPage()->pressButton('Save (this translation)');
+ $this->assertSession()->statusCodeEquals(200);
+ // Check the node access table.
+ $this->checkRecords(3, 'hu');
+ }
+
+ /**
+ * Queries the node_access table and checks for proper storage.
+ *
+ * @param int $count
+ * The number of rows expected by the query (equal to the translation
+ * count).
+ * @param $langcode
+ * The expected language code set as the fallback property.
+ */
+ public function checkRecords($count, $langcode = 'hu') {
+ $select = \Drupal::database()
+ ->select('node_access', 'na')
+ ->fields('na', ['nid', 'fallback', 'langcode', 'grant_view'])
+ ->condition('na.realm', 'node_access_test', '=')
+ ->condition('na.gid', 8888, '=');
+ $records = $select->execute()->fetchAll();
+ // Check that the expected record count is returned.
+ $this->assertEquals(count($records), $count);
+ // The fallback value is 'hu' and should be set to 1. For other languages,
+ // it should be set to 0. Casting to boolean lets us run that comparison.
+ foreach ($records as $record) {
+ $this->assertEquals((bool) $record->fallback, $record->langcode === $langcode);
+ }
+ }
+
+}
diff --git a/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php b/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
index 7475dab..cc87d28 100644
--- a/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
+++ b/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
@@ -73,7 +73,11 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
*
* @dataProvider providerTestBlocks
*/
- public function testBlocks($theme, $block_plugin, $new_page_text, $element_selector, $label_selector, $button_text, $toolbar_item) {
+ public function testBlocks($theme, $block_plugin, $new_page_text, $element_selector, $label_selector, $button_text, $toolbar_item, $permissions) {
+ if ($permissions) {
+ $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), $permissions);
+ }
+
$web_assert = $this->assertSession();
$page = $this->getSession()->getPage();
$this->enableTheme($theme);
@@ -174,6 +178,7 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
'label_selector' => 'h2',
'button_text' => 'Save Powered by Drupal',
'toolbar_item' => '#toolbar-item-user',
+ NULL,
],
"$theme: block-branding" => [
'theme' => $theme,
@@ -183,6 +188,7 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
'label_selector' => "a[rel='home']:last-child",
'button_text' => 'Save Site branding',
'toolbar_item' => '#toolbar-item-administration',
+ ['administer site configuration'],
],
"$theme: block-search" => [
'theme' => $theme,
@@ -192,6 +198,7 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
'label_selector' => 'h2',
'button_text' => 'Save Search form',
'toolbar_item' => NULL,
+ NULL,
],
// This is the functional JS test coverage accompanying
// \Drupal\Tests\settings_tray\Functional\SettingsTrayTest::testPossibleAnnotations().
@@ -203,6 +210,7 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
'label_selector' => NULL,
'button_text' => NULL,
'toolbar_item' => NULL,
+ NULL,
],
// This is the functional JS test coverage accompanying
// \Drupal\Tests\settings_tray\Functional\SettingsTrayTest::testPossibleAnnotations().
@@ -214,6 +222,7 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
'label_selector' => NULL,
'button_text' => NULL,
'toolbar_item' => NULL,
+ NULL,
],
];
}
@@ -552,6 +561,71 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
}
/**
+ * Tests access to block forms with related configuration is correct.
+ */
+ public function testBlockConfigAccess() {
+ $page = $this->getSession()->getPage();
+ $web_assert = $this->assertSession();
+
+ // Confirm that System Branding block does not expose Site Name field
+ // without permission.
+ $block = $this->placeBlock('system_branding_block');
+ $this->drupalGet('user');
+ $this->enableEditMode();
+ $this->openBlockForm($this->getBlockSelector($block));
+ // The site name field should not appear because the user doesn't have
+ // permission.
+ $web_assert->fieldNotExists('settings[site_information][site_name]');
+ $page->pressButton('Save Site branding');
+ $this->assertElementVisibleAfterWait('css', 'div:contains(The block configuration has been saved)');
+ $web_assert->assertWaitOnAjaxRequest();
+ // Confirm we did not save changes to the configuration.
+ $this->assertEquals('Drupal', \Drupal::configFactory()->getEditable('system.site')->get('name'));
+
+ $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['administer site configuration']);
+ $this->drupalGet('user');
+ $this->openBlockForm($this->getBlockSelector($block));
+ // The site name field should appear because the user does have permission.
+ $web_assert->fieldExists('settings[site_information][site_name]');
+
+ // Confirm that the Menu block does not expose menu configuration without
+ // permission.
+ // Add a link or the menu will not render.
+ $menu_link_content = MenuLinkContent::create([
+ 'title' => 'This is on the menu',
+ 'menu_name' => 'main',
+ 'link' => ['uri' => 'route:<front>'],
+ ]);
+ $menu_link_content->save();
+ $this->assertNotEmpty($menu_link_content->isEnabled());
+ $menu_without_overrides = \Drupal::configFactory()->getEditable('system.menu.main')->get();
+ $block = $this->placeBlock('system_menu_block:main');
+ $this->drupalGet('user');
+ $web_assert->pageTextContains('This is on the menu');
+ $this->openBlockForm($this->getBlockSelector($block));
+ // Edit menu form should not appear because the user doesn't have
+ // permission.
+ $web_assert->pageTextNotContains('Edit menu');
+ $page->pressButton('Save Main navigation');
+ $this->assertElementVisibleAfterWait('css', 'div:contains(The block configuration has been saved)');
+ $web_assert->assertWaitOnAjaxRequest();
+ // Confirm we did not save changes to the menu or the menu link.
+ $this->assertEquals($menu_without_overrides, \Drupal::configFactory()->getEditable('system.menu.main')->get());
+ $menu_link_content = MenuLinkContent::load($menu_link_content->id());
+ $this->assertNotEmpty($menu_link_content->isEnabled());
+ // Confirm menu is still on the page.
+ $this->drupalGet('user');
+ $web_assert->pageTextContains('This is on the menu');
+
+ $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['administer menu']);
+ $this->drupalGet('user');
+ $web_assert->pageTextContains('This is on the menu');
+ $this->openBlockForm($this->getBlockSelector($block));
+ // Edit menu form should appear because the user does have permission.
+ $web_assert->pageTextContains('Edit menu');
+ }
+
+ /**
* Test that validation errors appear in the off-canvas dialog.
*/
public function testValidationMessages() {
@@ -634,6 +708,7 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase {
public function testOverriddenConfigurationRemoved() {
$web_assert = $this->assertSession();
$page = $this->getSession()->getPage();
+ $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['administer site configuration', 'administer menu']);
// Confirm the branding block does include 'site_information' section when
// the site name is not overridden.
diff --git a/core/modules/system/src/Form/SystemBrandingOffCanvasForm.php b/core/modules/system/src/Form/SystemBrandingOffCanvasForm.php
index 35e68308..120a658 100644
--- a/core/modules/system/src/Form/SystemBrandingOffCanvasForm.php
+++ b/core/modules/system/src/Form/SystemBrandingOffCanvasForm.php
@@ -7,6 +7,7 @@ use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormBase;
+use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -31,13 +32,23 @@ class SystemBrandingOffCanvasForm extends PluginFormBase implements ContainerInj
protected $configFactory;
/**
+ * The current user.
+ *
+ * @var \Drupal\Core\Session\AccountInterface
+ */
+ protected $currentUser;
+
+ /**
* SystemBrandingOffCanvasForm constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
+ * @param \Drupal\Core\Session\AccountInterface $current_user
+ * The current user.
*/
- public function __construct(ConfigFactoryInterface $config_factory) {
+ public function __construct(ConfigFactoryInterface $config_factory, AccountInterface $current_user) {
$this->configFactory = $config_factory;
+ $this->currentUser = $current_user;
}
/**
@@ -45,7 +56,8 @@ class SystemBrandingOffCanvasForm extends PluginFormBase implements ContainerInj
*/
public static function create(ContainerInterface $container) {
return new static(
- $container->get('config.factory')
+ $container->get('config.factory'),
+ $container->get('current_user')
);
}
@@ -68,7 +80,7 @@ class SystemBrandingOffCanvasForm extends PluginFormBase implements ContainerInj
'#type' => 'details',
'#title' => t('Site details'),
'#open' => TRUE,
- '#access' => AccessResult::allowedIf(!$site_config_immutable->hasOverrides('name') && !$site_config_immutable->hasOverrides('slogan')),
+ '#access' => $this->currentUser->hasPermission('administer site configuration') && !$site_config_immutable->hasOverrides('name') && !$site_config_immutable->hasOverrides('slogan'),
];
$form['site_information']['site_name'] = [
'#type' => 'textfield',
diff --git a/core/modules/system/src/Form/SystemMenuOffCanvasForm.php b/core/modules/system/src/Form/SystemMenuOffCanvasForm.php
index 82390bc..a561a5b 100644
--- a/core/modules/system/src/Form/SystemMenuOffCanvasForm.php
+++ b/core/modules/system/src/Form/SystemMenuOffCanvasForm.php
@@ -3,7 +3,6 @@
namespace Drupal\system\Form;
use Drupal\Component\Plugin\PluginInspectionInterface;
-use Drupal\Core\Access\AccessResult;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityStorageInterface;
@@ -98,7 +97,7 @@ class SystemMenuOffCanvasForm extends PluginFormBase implements ContainerInjecti
'#type' => 'details',
'#title' => $this->t('Edit menu %label', ['%label' => $this->menu->label()]),
'#open' => TRUE,
- '#access' => AccessResult::allowedIf(!$this->hasMenuOverrides()),
+ '#access' => !$this->hasMenuOverrides() && $this->menu->access('edit'),
];
$form['entity_form'] += $this->getEntityForm($this->menu)->buildForm([], $form_state);