Problem/Motivation

Currently when the media library does access checking on the entity that opened the media library, it does so by loading the entity using a simple \Drupal\Core\Entity\EntityStorageInterface::load. When editing inline blocks and layout builder both of these things are true:

  • You aren't guaranteed to be modifying the latest or default revision of an inline block.
  • The revision ID of an inline block is very important to it's access control.

Steps to reproduce:

  • Enable media_library, layout_builder.
  • Add a media field + media library to a custom block type.
  • Enable layout builder + per entity overrides on a content type.
  • Embed a block with the media library field into a per entity override.
  • Create two revisions, modify the inline block in both.
  • Go to the "Revisions" tab and revert to the first revision.
  • Go back to the layout tab and try to edit and save a new image in the media library.
  • AJAX request will come back a 403.

What is happening under the hood:

  • The media library has an block content entity ID.
  • It loads that entity and checks access against it.
  • The inline block's access is based on it's host entity, so it loads the host and confirms the revision ID of the block is used on the layout (\Drupal\layout_builder\EventSubscriber\SetInlineBlockDependency::isBlockRevisionUsedInEntity).
  • The media libraries ::load call doesn't match the actual revision ID in the layout and the access chain is broken, resulting in an access denied.

Proposed resolution

Pass the host entity's revision ID around, instead of it's ID and load that instead for the purposes of access control.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Comments

Sam152 created an issue. See original summary.

sam152’s picture

Issue summary: View changes
sam152’s picture

Status: Active » Needs review
StatusFileSize
new1.91 KB

What about something like this?

sam152’s picture

Issue summary: View changes
seanb’s picture

Issue tags: +Media Initiative, +Needs tests

This seems to make sense to me. Can we add a test for this?

sam152’s picture

Issue tags: -Needs tests
StatusFileSize
new4.77 KB
new6.68 KB

Sure, what about something like this?

The last submitted patch, 7: 3124302-7-TEST-ONLY.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

seanb’s picture

  1. +++ b/core/modules/media_library/tests/src/Kernel/MediaLibraryWidgetTest.php
    @@ -0,0 +1,156 @@
    +class MediaLibraryWidgetTest extends KernelTestBase {
    

    We already have a MediaLibraryAccessTest. Might make sense to put this in there?

  2. +++ b/core/modules/media_library/tests/src/Kernel/MediaLibraryWidgetTest.php
    @@ -0,0 +1,156 @@
    +  protected function buildWidgetForm($entity) {
    

    Not really sure if we need to build the widget, in MediaLibraryAccessTest we simply create a state ourselves and check access. Which should be sufficient.

        $state = MediaLibraryState::create(
          $state->getOpenerId(),
          $state->getAllowedTypeIds(),
          $state->getSelectedTypeId(),
          $state->getAvailableSlots(),
          $parameters
        );
    
  3. +++ b/core/modules/media_library/tests/src/Kernel/MediaLibraryWidgetTest.php
    @@ -0,0 +1,156 @@
    +    $this->createUser();
    

    I know we do this a lot, but a comment that this is to make sure our uid is not 1 would be nice I think.

sam152’s picture

+++ b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
@@ -473,6 +473,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
+      if ($entity->getEntityType()->isRevisionable()) {
+        $opener_parameters['revision_id'] = (string) $entity->getRevisionId();
+      }

The new test class and building the widget ensures this part of the patch is covered.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

sam152’s picture

StatusFileSize
new644 bytes
new6.75 KB

Addressing #9.3.

@seanB, are you happy with the explanation in #10. I think covering the additional code in the widget is worthwhile splitting out a new test class.

Status: Needs review » Needs work

The last submitted patch, 12: 3124302-12.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

sam152’s picture

Status: Needs work » Needs review
StatusFileSize
new619 bytes
new6.76 KB
sanjayk’s picture

Assigned: Unassigned » sanjayk
sanjayk’s picture

Assigned: sanjayk » Unassigned
Status: Needs review » Needs work

I have test on d9 patch apply and test executed successfully but when I try to reproduce the issue I got below js issue please see below issue

EntityToolbarView.js?v=9.1.0-dev:145 Uncaught TypeError: Cannot read property 'get' of null
at r.position (EntityToolbarView.js?v=9.1.0-dev:145)
at render (EntityToolbarView.js?v=9.1.0-dev:51)
at p (backbone.js:337)
at v (backbone.js:322)
at u (backbone.js:110)
at r.a.trigger (backbone.js:312)
at r.set (backbone.js:525)
at r.set (BaseModel.js?v=9.1.0-dev:29)
at r.success (EntityModel.js?v=9.1.0-dev:175)
at Drupal.AjaxCommands.entitySaverAjax.commands.quickeditEntitySaved (EntityModel.js?v=9.1.0-dev:234)

sam152’s picture

Status: Needs work » Needs review

I don't think a JS error in the toolbar module has anything to do with this patch.

seanb’s picture

Status: Needs review » Reviewed & tested by the community

The reason I was a bit triggered by the class name MediaLibraryWidgetTest is because we had #3087227: [META] Split up and refactor MediaLibraryTest where we split up all kinds of widget related tests that were in 1 class (which became unmaintainable). So that is why I'm trying to see if we can have smaller, more specifically named classes.

Besides that, since this is already specifically named for widget related tests, it is good enough for me.

sam152’s picture

Ah, fair enough. Thanks for following up.

alexpott’s picture

Title: The media library should perform access checks against the revision of the entity being edited » [Backport] The media library should perform access checks against the revision of the entity being edited
Version: 9.1.x-dev » 8.9.x-dev
Status: Reviewed & tested by the community » Needs work

Committed and pushed d901cf487b to 9.1.x and 49f78bc356 to 9.0.x. Thanks!

diff --git a/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php b/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php
index 49a741b13e..348f22f104 100644
--- a/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php
+++ b/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php
@@ -73,7 +73,7 @@ public function checkAccess(MediaLibraryState $state, AccountInterface $account)
       $entity = $storage->loadRevision($parameters['revision_id']);
       $entity_access = $access_handler->access($entity, 'update', $account, TRUE);
     }
-    else if ($parameters['entity_id']) {
+    elseif ($parameters['entity_id']) {
       $entity = $storage->load($parameters['entity_id']);
       $entity_access = $access_handler->access($entity, 'update', $account, TRUE);
     }
diff --git a/core/modules/media_library/tests/src/Kernel/MediaLibraryWidgetTest.php b/core/modules/media_library/tests/src/Kernel/MediaLibraryWidgetTest.php
index 41df47c047..450bbda0dc 100644
--- a/core/modules/media_library/tests/src/Kernel/MediaLibraryWidgetTest.php
+++ b/core/modules/media_library/tests/src/Kernel/MediaLibraryWidgetTest.php
@@ -80,7 +80,7 @@ protected function setUp(): void {
 
     $this->adminUser = $this->createUser([
       'administer entity_test content',
-      'view media'
+      'view media',
     ]);
   }
 
@@ -101,7 +101,7 @@ public function testWidgetAccess() {
    */
   public function testRevisionableWidgetAccess() {
     $allowed_revision = EntityTestRev::create([
-      'name' => 'allowed_access'
+      'name' => 'allowed_access',
     ]);
     $allowed_revision->save();
 

Fixed coding standards on commit.

Leaving open for backport to 8.9.x as this is bug there. The test set up method will need fixing to not typehint.

  • alexpott committed f142dd7 on 9.1.x
    Issue #3124302 by Sam152, seanB: The media library should perform access...

  • alexpott committed 49f78bc on 9.0.x
    Issue #3124302 by Sam152, seanB: The media library should perform access...
sam152’s picture

Status: Needs work » Needs review
StatusFileSize
new619 bytes
new6.75 KB

Thanks for committing, adding the backport.

sam152’s picture

Status: Needs review » Reviewed & tested by the community

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 23: 3124302-23.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

acbramley’s picture

Status: Needs work » Reviewed & tested by the community

Rando fail

acbramley’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new6.75 KB
new1.37 KB

Woops, there was actually some phpcs issues. Fixed those.

sam152’s picture

Status: Needs review » Reviewed & tested by the community
phenaproxima’s picture

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 27: 3124302-27.patch, failed testing. View results

phenaproxima’s picture

Status: Needs work » Reviewed & tested by the community

There was a random failure. Restoring RTBC.

alexpott’s picture

Title: [Backport] The media library should perform access checks against the revision of the entity being edited » The media library should perform access checks against the revision of the entity being edited
Status: Reviewed & tested by the community » Fixed

Committed d89941f and pushed to 8.9.x. Thanks!

  • alexpott committed d89941f on 8.9.x
    Issue #3124302 by Sam152, acbramley, seanB: The media library should...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

pameeela’s picture

Adding the error that I got when hitting this, for searchability:

Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: Non-reusable blocks must set an access dependency for access control. in Drupal\Core\Routing\AccessAwareRouter->checkAccess() (line 120 of /app/site/web/core/lib/Drupal/Core/Routing/AccessAwareRouter.php)

maskedjellybean’s picture

I received the same error as @pameeela recently on 8.9.13 when editing a Layout Builder block that contains a Media field with Media Library enabled. The only solution I could find was to manually delete the block from Layout Builder and recreate/readd it. Based on comment #33, shouldn't this have been resolved long before 8.9.13? How could we still be experiencing this error?

pameeela’s picture

Hmm you're right, I hadn't checked versions yet, but my site also has the fix from this issue already. We just deleted the blocks and recreated them as you suggested in the other ticket.

But I don't have steps to reproduce this, it only occurred on one node on a staging site, have not had any other reports.

imalabya’s picture

Version: 8.9.x-dev » 9.5.x-dev

This issue exists in Drupal 9.5 with entity clone

Steps to reproduce:

  • Add a Block which have a media reference in a Layout Builder enabled node
  • Clone the node
  • Go to layout of the new cloned node and edit the block.
  • Remove the arrached media reference and try to add a new Media reference (Either by selecting existing media item or upload new)
  • Throws an AJAX error Non-reusable blocks must set an access dependency for access control.
permanaj’s picture

I have similar case with @imalabya

I get error `Non-reusable blocks must set an access dependency for access control.` after uploading the image for the second time

Steps to reproduce:

  • Add a Block which have a media reference in a Layout Builder enabled node
  • Clone the node
  • Go to the layout of the new cloned node and edit the block.
  • Remove the attached media reference and try to add upload new image. Save block. Save layout.
  • Go to the layout of the cloned node again, and edit the block.
  • Remove the attached media reference and again, try to add upload new image. After selecting the image there is an error on the browser console

I test this on simplytest.me using Drupal 10.3.6 and 10.3.9 with Entity clone module version 2.1.x.