Summary
When access is checked for a paragraph, part of the logic checks if the user has access to the parent entity. It does this by loading the default revision of the parent entity which is not correct. It should load the revision of the parent that the paragraph is attached to.
Because of this, paragraphs will not be viewable or editable unless the user has access to view/edit the default revision of the parent entity. Both scenarios can happen if a site has content moderation enabled, where users may be editing future revisions, or viewing past/future revisions of a parent entity.
Original report
My company is using paragraphs, custom content blocks, layout builder and content moderation with revisions. Overall it works really well for us, but we ran into a blocker with this combination when it came to content moderation. Normally, everything works wonderfully, until we want to make changes to a node that is already published, and have this new "draft" revision go through a moderation process before replacing the "current" published revision. When we have a "current revision" published and a "latest revision" going through the moderation process, we noticed that if we edited custom blocks with paragraphs in them, these paragraphs would disappear from the published "current revision". They would also fail to render in the "preview" mode of the layout builder after the draft revision was made. This is not the expected behavior: Not only would we expect the paragraph to render in both places, it was jarring to see that the creation of a draft revision effecting the display of the published revision! Normally the published revision should look untouched, but we were suddenly having entire paragraphs go missing. I believe I might have an edge case but wanted to share my workaround in case others are experiencing this issue.
Steps to reproduce:
- You will need the custom block module (core) and entity reference revision module in addition to paragraphs.
- Create a content type that utilizes layout builder and allows overrides on a per node basis.
- Enable a moderation workflow on this content type.
- Create a paragraph entity with some test fields.
- Create a custom paragraph block type utilizing this paragraph with the "custom blocks" module
- Create a new node, save it as a draft.
- Edit this node and click on the layout builder tab.
- Make sure the "Show content preview" checkbox is checked in the layout builder.
- Add a paragraph block into the layout, add sample text to the fields. After placing the block inside the layout builder, confim that the fields appear in the content preview within the layout builder.
- Save the layout and "publish" the node.
- "View" the published revision and confirm that the fields inside of the paragraph are rendered and present.
- Edit the node, click on the layout builder tab again and edit the paragraph fields, maybe adding some more text. Save the layout as a draft.
- Compare the current revision (published) with the latest revision (draft), you may find that the content inside the paragraph no longer renders on the published current revision, but appears fine in the draft revision.
- Return to the "layout" builder tab, note that the paragraph fields no longer render within the layout builder preview when "Show content preview" is checked
Proposed resolution
I do not know what is planned for additional revision support with the paragraphs module, but I have created a work around for block_content and paragraph parent entities, where the checkAccess method performs some due diligence to look up the correct revision ID of it's parent, instead of returning the most recent or active one which will always return the incorrect revision ID. I would love some help to modify this workaround to potentially work for all types of parent entities. The layout builder loads the parent entities for the page being viewed and generates a list of which revision IDs are present. This is checked against the parent entity passed by paragraphs, and in cases where we have a published current revision and a draft latest revision being juggled at the same time we need make sure the correct parent revision ID is passed along. What I have here is more of a workaround until better revision support is worked out for the paragraphs module.
Remaining tasks
- Need others experiencing this issue to test the patch & provide additions and feedback
- Need to identify scenarios where the revision ID query added to checkAccess might return more than one result, I cannot think of any, however if there is some sort of case where this would happen we'd need to add some code to determine of the results is the one we're looking for.
- figure out how to handle differing types of parent entities, my use case deals with block_content and also paragraph parent entities, there are probably others out there but I'm not sure what the best way is to make this parent type agnostic.
- I don't have a lot of testing experience, could use some input on how to create a test for this added parent revision ID check.
User interface changes
none
API changes
Modify ParagraphAccessControlHandler::checkAccess() to perform a query using information on the parent entity and the loaded paragraph to find the correct revision ID of the parent when a node has a different published and active revision. The current loaded paragraph revision and target ID is queried against all revisions of it's parent, this extracts the parent revision ID where the current loaded child is referenced. The parent is then loaded by it's revision ID and passed along to complete the access check process.
Data model changes
none
Release notes snippet
When using layout builder, custom blocks and content moderation, Paragraph access checks do not always return the the paragraph's correct parent revision ID. This is a bit of an edge case: when there is a published current revision along with a draft latest revision the parent's revision ID can not be assumed to be the default latest revision, otherwise access checks will automatically fail. This adds a query for parent entities of the block_content and paragraph type to have their correct revision IDs looked up before proceeding with the rest of the access check. It would not effect other parent types.
| Comment | File | Size | Author |
|---|---|---|---|
| #60 | 3090200-60-alternative.patch | 1020 bytes | amateescu |
Issue fork paragraphs-3090200
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
poindexterous commentedComment #3
poindexterous commentedThis patch works for me, just seeing if it passes the tests.
Comment #4
poindexterous commentedComment #5
poindexterous commentedRe-roll, could be line ending issues. Otherwise I'm not sure why it's not taking.
Comment #6
lpeabody commentedI'm running into a potentially related issue where I am building out some content, exporting it via Default Content, and then re-installing the site and importing it's default content. The result is the paragraphs render correctly when viewing the node, but when you edit the layout with "Show preview" checked then you don't see any of the paragraphs render.
I applied this patch and it did not fix the issue for me, unfortunately. I don't want to set to Needs work, however, since I was not testing this specific use case.
Comment #7
lpeabody commentedI sorted out my previous issue (the inline_block_usage table was not being populated when default content was imported).
I have since moved on to testing this use case, since it applies to us as we are using Content Moderation. After following the reproduction steps I can verify that this issue exists for me, but I can also verify that the attached patch does not resolve the issue, so I am setting it back to Needs work.
Comment #8
lpeabody commentedHmm, I just found https://www.drupal.org/project/drupal/issues/3047022#comment-13324107. I applied the most recent patch in that issue and made the 'view' addition to checked operations as you described @Poindexterous and now everything is magically working. Moving this back to Needs work because, honestly, I'm not actually sure what needs work. This is a cluster of a web of issues between Layout Builder, Paragraphs, Block Content, and Content Moderation.
I'm gonna dig in to this a bit but going to leave unassigned because I won't remember to re-assign it otherwise...
Comment #9
lpeabody commentedComment #10
lpeabody commentedComment #11
lpeabody commentedI had to tweak the patch in #3 to allow access on paragraphs when editing them in the settings tray in the builder UI after reverting to a previous version of the node.
The combination of this patch (#11) and the patch from https://www.drupal.org/project/drupal/issues/3047022#comment-13339620 have things working for me finally, it seems. I'll keep a close eye on things.
Comment #12
poindexterous commentedthanks @lpeabody!
this one was a tricky one for me to hunt down, similar to your scenario, it took some hands-on digging to figure out which modules were responsible for the different hiccups. It was kind of like a game of whack-a-mole. Glad to hear things are working for you now. Thanks for updating the patch, I didn't think to try the patch while revering to a previous revision. Good catch!
Comment #13
josephdpurcell commented@Poindexterous THANK YOU for documenting this wonderful ticket!
I tested the information in comment #11 and found this correct. You need these two patches:
just as @lpeabody said. I did not review either patch, only confirmed it resolved the behavior described in the ticket.
Comment #14
poindexterous commented@josephdpurcell
You're welcome! I am currently updating drupal core to 8.8.1 & will also be updating the paragraphs module and see if I experience any issues, whether the bug will still be there, and if so: will these patches till work...
I noticed you work at Bounteous (on your bio). Say Hi to the gang there for me, one of your teams (Sarah, Steve & Brad) worked on one of our recent projects.
Comment #15
acbramley commentedConfirming that #11 along with https://www.drupal.org/project/drupal/issues/3047022#comment-13339620 fixed my issues too, thanks so much for the hard work! We definitely need tests here though
EDIT: Spoke too soon, still having problems https://www.drupal.org/project/drupal/issues/3047022#comment-13432352
Comment #16
nadavoid commentedI was using the patch from #11, but encountered an issue where many paragraphs stopped displaying because of being access denied. The cause of that was that revision field data, e.g. from ERR, can have multiple records that point to the same paragraph revision. That means that this query can legitimately return multiple records.
Adding a
->sort('revision_id', 'DESC')gave me the result I expected, which is the latest field revision. Attaching a patch with that addition, plus using dependency injection for the entityTypeManger service.I'm not sure if there's a better way for a paragraph revision to find its true, current parent, when multiple revisions of the parent point to the same revision of the paragraph.
Comment #17
nadavoid commentedI bumped into another case where the query to get the correct revision of the parent was getting the wrong revision, leading to an access denied. This new case is pretty easy to replicate:
Because it seems really difficult to reliably load the correct revision of the parent entity for access checking, I've changed approach to just return the current $access_result if the parent entity is a block or paragraph.
Comment #18
poindexterous commentedSo after the recent round of drupal core updates and various 3rd party updates, I've found that I now need another patch for drupal core for layout builder and paragraph blocks to work correctly:
"[PP-1] Reverting entity revisions that contain custom blocks erroneously triggers EntityChangedConstrainy"
https://www.drupal.org/project/drupal/issues/3053881
I had started getting errors for in the layout builder when editing inline blocks: "the content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved." The patch above fixes it for me, I'm using patch #11 at the moment (https://www.drupal.org/files/issues/2019-05-13/3053881-11.patch)
That puts me at a total of 3 patches to fix this issue for my use case. 2 of the 3 being patches for drupal core's layout builder.
Comment #19
poindexterous commentedComment #20
erichhaemmerle commentedSo, I am also using Paragraphs on a custom block type, which is then used as an inline block in Layout Builder. I am also using Content Moderation and to make matters worse, this is a multilingual site. I'm pulling my hair out over here. I'm on Drupal 8.8.5. I've tried so many different combinations of patches and I am still having issues when placing the node that contains a paragraph block into draft status. If it was previously published, and then I edit the paragraph block in Layout Builder and then place the node in draft status and then go back to editing the block with the paragraph in it, I get "You are not allowed to edit or remove this {Paragraph}.", where {Paragrpah} is the name of the paragraph.
Is anyone else using a system with all of these modules successfully? I'm just trying to figure out the right combination of patches.
THANKS
Comment #21
acbramley commented@nadavoid unfortunately #17 breaks editing in certain situations, whereas #16 doesn't.
For transparency I have these other patches applied:
Core:
https://www.drupal.org/files/issues/2020-04-27/3131126-3.patch
https://www.drupal.org/files/issues/2019-05-21/3053887-11.patch
Paragraphs:
https://www.drupal.org/files/issues/2019-03-22/2901390-n24.patch
Steps to reproduce issues with #17:
1) Create LB controlled page
2) Add block with paragraphs (doesn't need to be nested)
3) Save the page
4) Edit the page, editing some of the data in the paragraphs
5) Revert to the previous revision
6) Edit the block again
7) You will see the "You are not allowed to edit or remove this ." message
This does not happen with #16
EDIT:
16 still has issues with editing blocks on reverted revisions and adding a new paragraph item - this results in an access denied again :(
Comment #22
jorgik commentedBased on your comments I've added update operation to the #17 patch, I'm not sure that it's right handling of this issue, but at least it works for editing flow.
Comment #23
erichhaemmerle commentedSWEET. It looks like #22 worked for me! THANKS
Comment #24
sime#22 appears to be working for me.
(Also, anyone experiencing or working on this issue, you are a good person, you are important, don't let it get you down.)
Comment #25
nmwd commented#22 seems to be working when creating a draft but seems to be breaking when reverting to a previous revision. After reverting, when I try to edit and save the block, I get the following error:
Anyone getting the same thing?
Comment #26
jbloomfield commentednmwd Yes, can confirm. I get the same error when trying to edit a paragraph that has previously been reverted. I get lot's of form errors and the message you mentioned. Shame, as the patch fixes our other issue :)
Comment #27
beanjammin commentedThe patch from 3053881-32 fixes the issue pointed out in #25 about not being able to edit after reverting to a previous revision.
Comment #28
azinck commentedLike Beanjammin, I'm using patch 22 here with #3053881-32: Reverting entity revisions that contain custom blocks erroneously triggers EntityChangedConstraint and things seem to be working well.
Comment #29
modestmoes commentedOur relevant core/paragraphs patch stack:
Comment #30
kim.pepperComment #31
anpolimusWe do have a similar issue, but it is connected to nodes that were cloned.
Cloned paragraph items still have the old node as parent id.
If a user doesn't have access to that node - he is not able to edit this node.
Comment #32
smustgrave commentedPatch #22 and the patch mentioned in #28 seem to work for me. What's needed to help move this forward?
Comment #33
poindexterous commentedI'm in the middle of a drupal 8 to 9 upgrade and noticing that this patch no longer works, it could be that one or both of the related patches needed in conjunction with this one might need to be updated or re-rolled. I will report back here with what I dig up.
Comment #34
poindexterous commentedLooks like if you update to drupal 9.2.7 from version 8, you'll need to change your core patches for issue 3053881 since the older ones for 8x won't apply anymore: "Reverting entity revisions that contain custom blocks erroneously triggers EntityChangedConstraint" to patch #45 https://www.drupal.org/files/issues/2021-04-06/3053881-3049332-45.patch. Things seem to be working again on my side of things.
Comment #35
poindexterous commentedEdit: looks like was also needed a patch for issue 3047022. Here's our current list of installed patches for core and paragraphs for drupal 9.2.7 in case it helps anyone:
Comment #36
aaron.ferris commentedPatch in #22 works well for the specific issue I was encountering, which is explained in the opening post.
(along with https://www.drupal.org/project/drupal/issues/3053881#comment-13814032)
Comment #37
leo liao commentedAccess check parent entity revision issue 3084934 and access controll issue 3090200 merge
Comment #38
maoxuan@ciandt.com commentedComment #39
jastraat commentedJust as an update, this applies to simply having a paragraph field in a custom block type. Layout builder is not required to trigger this error.
Comment #40
aloneblood commentedCombine 3090200-22.patch with another issue 3084934-13.patch(https://www.drupal.org/files/issues/2022-07-21/3084934-13.patch)
Comment #41
aloneblood commentedCombine 3090200-22.patch with another issue 3084934-13.patch(https://www.drupal.org/files/issues/2022-07-21/3084934-13.patch)
pls use https://www.drupal.org/files/issues/2022-10-26/3084934-13_combine_309020... instead
Comment #42
aloneblood commentedComment #43
aloneblood commentedComment #44
jjchinquistPatch 3084934-13_combine_3090200-22.patch reviewed and it is working. RTBC
Comment #45
artyom hovasapyan commentedUpdate #43 change andIf to orIf
Comment #47
artyom hovasapyan commentedUpdate #43 change andIf to orIf
Comment #48
bkosborneThat's not right. It should be set back to
andIf. Access to view a paragraph requires you have access to view both the paragraph entity AND the parent. Hiding those patches to avoid confusion.Comment #49
bkosborneI don't think this current patch is workable. As of the changes introduced in #17, it's just bypassing the parent entity access check entirely if the parent is a block or another paragraph. That seems wrong.
Comment #50
bkosborneMarked #3084934: Paragraph access check via parent entity incorrectly uses the default revision of the parent instead of the latest as a duplicate of this. It's trying to solve the same problem, which essentially is that when a paragraph performs the access check on its parent, it's using the parent's default (AKA "active") revision, when it should be using the revision that that specific paragraph is attached to. I don't think this can be resolved properly until #2954512: Store information about a paragraph's parent revision is resolved. Once it is, then this issue becomes really simple to solve.
That said, I think loading the parent's correct revision is most important when performing access control for the "view" operation of the paragraph. But for "edit" and "delete", loading the parent's latest revision generally seems appropriate. I think we can solve for that now without waiting on #2954512: Store information about a paragraph's parent revision
Comment #51
bkosborneComment #52
bkosborneComment #53
bkosborneComment #54
luke.leberI wasn't able to reproduce this against 9.5.x, but perhaps I'm doing something wrong?
Is it a precondition that the user:
for an entity type?
Comment #55
luke.leberI finally have another set of steps to reproduce some wonky behavior here:
These are the steps that I'll follow for acceptance testing once we have a patch that doesn't bypass any pre-existing access checks.
Comment #56
bkosborneLuke, indeed, I believe the root cause is responsible for both the issue where the paragraph cannot be viewed or edited. The issue with editing was documented in #3084934: Paragraph access check via parent entity incorrectly uses the default revision of the parent instead of the latest which I closed as a duplicate of this one.
Curious that in your reproduction steps, the paragraphs is still viewable on the published version of the page?
Comment #57
luke.leberYeah, they are still visible on the front end for me.
Wouldn't storing the paragraphs' parent revision be sort of impossible for historical data?
Comment #58
bkosborneI think I should explain further why this is bad. Imagine you had a private file field on the paragraph which is on the block. Private file fields defer their access control to the entity they're attached to. In this case, it would be the paragraph. This patch, as is, would allow everyone to access the private file.
Comment #59
chrissnyderPatch in #22 works well for the specific issue I was encountering, which is explained in the opening post.
Comment #60
amateescu commentedHere's an alternative solution for this problem. The idea is to rely on core's Typed Data system for retrieving the host entity of a paragraph, it's based on the patch proposed in this Drupal core issue: #3428635: Allow the 'entity' property of entity reference fields to be aware of its position in the typed data tree, and it also needs the
Entity Reference Revisionspatch from #3428639: Allow the 'entity' property of entity reference revision fields to be aware of its position in the typed data tree.Comment #61
amateescu commentedPosted a new patch in the ERR issue (#3428639-7: Allow the 'entity' property of entity reference revision fields to be aware of its position in the typed data tree), which is simpler and doesn't have to wait for the core issue. So all we need to solve the Layout Builder -> Custom block -> Paragraph problems is the Entity Reference Revisions patch and the one above for Paragraphs.
Comment #62
smethawee commentedHi @amateescu
The alternative patch #60 solution for this problem is not working for me. Do we still need waiting for review? Thanks!
Comment #63
amateescu commented@smethawee, have you also applied the patch for Entity Reference Revisions mentioned in #61?
Comment #64
smethawee commented@amateescu Thank you so much for you connected.
Yes, here what I did below anything that I have to add?
Regards,
"drupal/entity_reference_revisions": {
"#3428639-7": "https://www.drupal.org/files/issues/2024-03-16/3428639-7.patch"
},
"drupal/content_moderation": {
"content-moderation-events-79": "https://www.drupal.org/files/issues/2023-10-11/2873287-content-moderatio..."
}
Comment #65
realgt commentedi tried patch #60 and the Entity Reference Revisions patch mentioned in #61, and it does render my paragraphs in layout_builder edit mode but they are still locked and uneditable. previously the paragraphs would not even render while editing a layout
edit: patch #43 worked for me
Comment #66
smethawee commentedHi @amateescu and @realgt patch #43 is not working for me too. So wondering about this fix. Thanks!
Comment #67
phjouPatch #43 worked for me, it allowed to unblock the situation on both editing, and display on the frontend.
Comment #68
gordonio commentedPatch #43 worked for me. Layout builder shows the correct entities in a non published state, and the published version displays the correct revisions.
Comment #70
joe_carvajalCan confirm patch #43 worked for me too with Drupal 10.3.1 and Paragraphs 1.18.
Comment #71
aaronchristian commentedConfirming #43 Still works on 10.4.6
Using layout builder, paragraphs, content moderation & entity reference revisions.
Comment #72
steinmb commentedMaking the patch into a merge request (MR) increases changes for this getting merged. As the issue is tagged with "needs tests" and patch(es) contains none do I push this back to NW.
Comment #74
acbramley commentedI've rolled #22 into an MR as that's the patch we've been using in prod for years. I like the idea of #60 but that'll have much wider reaching BC issues for sites using
getParentEntityso I'm not sure how viable that'll be. Still NW for tests.Comment #75
bkosborneThese patches are not right. You need to be extra careful that the paragraphs on your sites don't have private file fields on them otherwise you risk anyone in the world being able to download those files. Maybe for 99% of you that's not the case, but I can't imagine this patch ever getting committed for that reason.
Comment #76
bkosborneClarifying the title to indicate that the scope of this issue is related specifically to the view permission of the paragraph and that the issue is present both with forward drafts from content moderation or when reverting host entities (page layouts) to previous revisions. Edit/delete permission should be resolved by this core issue that's hopefully committed soon: #3047022: Layout builder fails to assign inline block access dependencies for the overrides section storage on entities with pending revisions.
Comment #77
jpontet commentedCould someone help clarify what patch (if any) would be good for version 1.19?
Thanks in advance
Comment #78
rajab natshahComment #79
leonbasherPatch #43 worked for me!
Drupal version: 10.4.7
Paragraphs version: 1.18