The major issue the function in question (permissions_by_term_node_access, and implementation of hook_node_access) is that is claims far too much control over unpublished content:
function permissions_by_term_node_access(NodeInterface $node, $op, AccountInterface $account) {
if (method_exists($node, 'id') && ($op == 'view' OR $op == 'update' OR $op == 'delete')) {
if (!$node->isPublished() && !$account->hasPermission('Bypass content access control', $account)) {
$eventDispatcher = \Drupal::service('event_dispatcher');
$accessDeniedEvent = new PermissionsByTermDeniedEvent($node->id());
$eventDispatcher->dispatch(PermissionsByTermDeniedEvent::NAME, $accessDeniedEvent);
return AccessResult::forbidden();
}
/* @var \Drupal\permissions_by_term\Service\AccessCheck $accessCheck */
$accessCheck = \Drupal::service('permissions_by_term.access_check');
return $accessCheck->handleNode($node->id());
}
}
This code simply should not be enforcing a forbidden on any and al unpublished content (ignoring the Bypass content access control perm for the moment). This clashes for a start is any and all workflows that would want to work with unpublished content. For example, on a site I have need to restrict some content types by taxonomy terms as advertised and other content types are not governed by permissions by term but have a need to be created and edited by a particular role, but not published by that role. Another role handles the publishing. Because of the above code, as long as the node is unpublished, the owner of the content cant see it or even edit it! So if I have a moderator asking for revisions before publishing it, the only person that can edit it is some like a full-blown admin.
Additional quirks I'm not quite sure why it's in the code: method_exists($node, 'id'). The node is type hinted going into the functions, so this check should always pass - NodeInterface based objects are always going to have the id() method. Was this originally a check to just make sure the node has an id?
Finally, what's the purpose of the event dispatch? I can't bypass the forbidden access return.
Taking the above into account, I think the function might be better as:
function permissions_by_term_node_access(NodeInterface $node, $op, AccountInterface $account) {
if ($op == 'view' OR $op == 'update' OR $op == 'delete') {
/* @var \Drupal\permissions_by_term\Service\AccessCheck $accessCheck */
$accessCheck = \Drupal::service('permissions_by_term.access_check');
return $accessCheck->handleNode($node->id());
}
}
I haven't tested this yet as I may be missing information leading to the inclusion of some of the code. I'm open to better ideas to fix this issue.
Comment | File | Size | Author |
---|---|---|---|
#15 | permissions_by_term-moderation_support-2927322-15.patch | 22.47 KB | sonnykt |
|
Comments
Comment #2
Peter MajmeskuWe have been authoritative in this function, because there were several issues with giving giving access to node view for anonymous users, if the node has not been published. AccessCheck::handleNode() is not taking care of anonymous users.
Yes, you are right. This method does not make sense. It was just a mistake, which current does not "hurt".
Probably
1., it's enough to check if $account contains just the anonymous role and return afterwards AccessResult::forbidden().
2., So the first if-case could be simplified.
3., The logic should be moved to the AccessCheck service.
4., Then there could be developed an KernelBase test to prove the functionality with several cases.
This function is crucial to make PbT work and not cause a serious security leak for > 1000 Drupal sites!!!
This issue is no bug. It is an improvement. If you are willing to work on it and you provide a patch for this, I would review it and commit to PbT on success.
Comment #3
Peter MajmeskuComment #4
sonnyktEven if it's not that restrictive, Pbt still has other issues when working with unpublished content managed by other workflow modules such as Content Moderation or Workbench Moderation. Pbt implements
node_grants
whereas the others don't. Withoutbypass content access
permission,node_access_view_all_nodes()
always checks for node grants innode_access
table if there is a module implementing node_grants. Pbt does not provide any grant for unpublished nodes. Non-admin users are not able to edit unpublished nodes if Pbt module is enabled.Context:
* Enabled modules: Content/Workbench Moderation, Permissions by Term
* Users with permission
access content overview
cannot see unpublished content in/admin/content
view* Users with permissions
view own unpublished content
andview any unpublished content
cannot view draft content.* Users with permission
update any content
cannot edit unpublished content. They can only edit published content.* Users with permission
bypass content access
don't get the above restrictions.Comment #5
hawkeye.twolfChanging issue category back to "Bug report"; disallowing all editors (except those with "bypass node access") from editing draft content—even their own that they just created!—certainly can't be acceptable behaviour, can it? This module is a no-go for any sites that use moderation, or indeed where any content might exist in unpublished state. I understand that this approach has fixed other problems for you, but it has done so in the wrong way and at high cost.
Comment #6
hawkeye.twolfBumping priority
Comment #7
hawkeye.twolfUpdating associated version.
Comment #8
danjdewhurst CreditAttribution: danjdewhurst commentedHow about adding `!$node->isDefaultRevision` to the if statement on line 261?
Comment #9
Peter MajmeskuIs now fixed in 8.x-1.43: https://www.drupal.org/project/permissions_by_term/releases/8.x-1.43
I have removed the entire part which was blocking access for unpublished nodes. This must have been implemented in a previous version of the AccessCheck service. Before it probably was not returning AccessResult::neutral(), if PbT wasn't handing the node because of no relation to a restricted taxonomy term.
So PbT will not block you in your content moderation process.
I have been testing this change - but - please (please!) be so kind and test this release carefully and report any issue related to this change! Feel free to re-open this issue, if you have any objections.
Comment #11
Peter MajmeskuComment #12
dgs-vic CreditAttribution: dgs-vic commented@peter-majmesku, I've just tried 1.43 and I still have the same issue. I have a user with edit permissions on a content type that has a permissions by term taxonomy field on it. The user has the permission. If I create a new node as an administrator, I cannot edit the node with a non administrator user (a user without the Bypass permission).
Have you tested this change with the Workbench moderation module? Are there special permissions combinations or settings that are required?
Comment #13
Peter MajmeskuThere is one setting for single term permission inside PbT. You can reach it via configuration. Have you used it?
No ability to edit an node: you have no terms set on this node?
Comment #14
sonnyktThe issue is not from Pbt itself, but instead from the core Node Grants system. Amongst Pbt, Workbench Moderation (WbM), and Content Moderation (CM); Pbt is the only module implementing
hook_node_grants()
(see #4). When there is an implementation ofhook_node_grants()
, all access checks will refer to thenode_access
table. Pbt does not provide a grant for unpublished nodes, and neither CM/WbM do. Thus, accessing to unpublished nodes will always get access denied without thebypass content access
permission.To make Pbt work with CM/WbM, I have a workaround by implementing node_grants for unpublished nodes.
It'd be good if Pbt can include a submodule implementing the above hooks.
Comment #15
sonnyktThis patch added the above hooks to a submodule
permissions_by_term_moderation
.Comment #16
Peter MajmeskuThanks. I will check this on coming weekend.
Comment #17
Peter MajmeskuIt is crucial, that users without the "Bypass content access control" are able to edit unpublished nodes.
There should not be an extra module necessary for this, which dependency to the content moderation or workbench moderation. This should be implemented in the base module.
Right now I am not sure, if it has even anything to do with node access records. Because I have commented out
permissions_by_term_node_access_records()
and the unpublished node was still unaccessible. Have you checked which function of PbT disallows the access to unpublished nodes?
Comment #18
Peter Majmesku> Thus, accessing to unpublished nodes will always get access denied without the bypass content access permission.
I gave an user all node permissions except the "Bypass content access control" permission. The PbT module was uninstalled and all permission rebuild at /admin/reports/status/rebuild. What was the result on accessing the node with this user?:
Then I was enabling PbT and then I have rebuild the permissions. I was able to edit this node, without having set any term permissions via PbT. Afterwards I have added term permissions and gave my user the permission for this node via them: I was able to edit the node. Then I have removed permissions from this user via terms: I was still able to edit this node with this user.
PbT is not "too" authoritative anymore since the commit from https://www.drupal.org/commitlog/commit/69545/5c74ed084dbf16df99fe3a27be....
I will not add any extra module for workbench moderation or content moderation. Please create an new project on Drupal.org for this. This goes quick: https://www.drupal.org/node/1068942. Let me know, when you have created it. Then I will link from PbT's project page to your project.
I am closing this issue, since PbT works as designed. Please feel free to re-open this issue, if you have any objections.
Comment #19
ironsizide CreditAttribution: ironsizide at Message Agency commentedI've tried the patch in #15, and it's working in the respect that I can now view unpublished nodes as long as the account has the general view any/own unpublished content perms. However I'm still not allowed to edit content for which the account has specific content type permissions. In my use case, an account with the role of "Blog Contributor" has the permission "edit own blog_post content" for the blog_post content type. I have the content moderation module installed and set up to allow Blog Contributors to create new drafts (unpublished), and theoretically edit published blog posts, which actually creates a new draft (unpublished revision). Users with the role of "Manager" can move drafts to the published state. Basically, BCs can create and edit blog posts, and managers must reviews them, approve them, and publish them.
When I am logged in as a Blog Contributor user I can see the all blog posts, and the operations (edit) only show up for my own content, which is expected. If the blog post is published and has no revisions in a draft state, I can edit the blog post, and save a new revision in a draft state. At that point (when there's a draft revision), while there is an edit operation available, I get an access denied result when clicking on the edit op. I would expect to be able to edit a draft (unpublished) revision with the permissions granted.
I am happy to expand the code, but I'm unsure where I should be working. Is the permissions_by_entity submodule supposed to be handling entity-specific permissions, or is the permissions_by_term_moderation submodule just not drilling down far enough? The moderation module is only checking view permissions, and the global ones at that - not entity specific permissions. I tried setting a break point in the PermissionsByEntityKernelEventSubscriber from the permissions_by_entity submodule, but it's not getting hit when I try to load a blog post edit form. Am I barking up the wrong tree with the permissions_by_entity submodule?
Comment #20
Peter Majmesku> I am happy to expand the code
Great! As I have written, please create an new module project for that, which has the Permissions by Term module as dependency: https://www.drupal.org/node/1068942.
I am not going to support the content moderation and workbench moderation modules. I do not need them. Also I do not integration a submodule for this into the Permissions by Term module. If you need this module: please create an new module project for it. I will link to it. You can also ask me questions regarding PbT via issues.
> I am happy to expand the code, but I'm unsure where I should be working.
Permissions as controlled in hook_node_access() and hook_node_access_records() in the modules/permissions_by_term/permissions_by_term.module file. Also the KernelEventListener class is restricting access for nodes. Check the onKernelRequest method there.
The Permissions by Term module is based on node access records. Make sure you understand how they work: https://api.drupal.org/api/drupal/core%21modules%21node%21node.api.php/f...
> I tried setting a break point in the PermissionsByEntityKernelEventSubscriber from the permissions_by_entity submodule
The permissions_by_entity submodule is only handling permissions on custom entities and it is experimental. The Permissions by Term module is handling access to Drupal nodes (node entity type - shipped with Drupal core).
If you need support for the content moderation or workbench moderation module, please create:
Comment #21
gr8tkicks CreditAttribution: gr8tkicks at University of California commentedHas anyone made a module that supports Permissions By Term with Content Moderation moderation support, this being in Core now on 8.4 and later?
Comment #22
higherform CreditAttribution: higherform commentedJust ran into this bug on a fresh 9.4.1 and PbT 3.1.17 install. On install, non-admin users lost all access to own unpublished content in views, node/edit, etc. Tried flushing caches, rebuilding permissions, etc, but no change.
Uninstalling PbT cleared the bug and restored access own unpublished content functionality.
Unfortunately, this makes PbT unusable for us, whereas it could have been a huge help in our publishing model.
Happy to contribute troubleshooting and testing time, when a real fix for this issue is available.
Thanks
Comment #23
iainp999 CreditAttribution: iainp999 as a volunteer commentedWe're in a similar position to @higherform
Drupal 9.4.5, PBT 3.1.19
Users cannot see unpublished content in views listings, node/edit.
Unfortunately, we'll need to look for another solution to our use-case for now.