This seems to happen because the update and the view moderation history use the same access function.

The function is: _workbench_moderation_access().
Inside the function is this block of code:

<?php
   // The user must be able to view the moderation history.
   $access &= user_access('view moderation history');
 
   // The user must be able to edit this node.
   $access &= node_access('update', $node);

   if ($op == 'unpublish') {
?>

The first node_access check is fine, but the second node_access check should not apply to the view moderation history.

I looked around to see what calls the said function and found that the only cases where when the user was doing an unpublish or a moderation (via the menu url paths) or
is called from _workbench_moderation_access_current_draft() that ends up calling the _workbench_moderation_access() function.

I am suggesting that the update access check only be done when there is a potential update/edit, such as the unpublish process.
The attached patch moves the update access check to inside the unpublish op if block.

There is also this in that same function call:

<?php
  // Allow other modules to change our rule set.
  drupal_alter('workbench_moderation_access', $access, $op, $node);
?>

This makes me think I should alter the patch to only do the view update test for any/all update operations?
And what are those operations?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Vc Developer’s picture

Sub.......

lotyrin’s picture

Component: User interface » Code

This also breaks viewing drafts.

Regarding the current patch, Is unpublish the only op that should check for node update access?

thekevinday’s picture

I suppose any "edit"-like op would need to check for the node update access.

I mentioned that I was not sure what ops there are to process, so maybe I should change the patch to work like this instead:

<?php
if ($op != 'view') {
  $access &= node_access('update', $node);
}
?>

Which would catch all unknown states while allowing the known 'view' state.
But this then changes the question to, are there any non-"edit"-like states that should not have the node_access('update') check??

I would think that the only operations are CRUD (or in drupals case, CVUD).
- Create, Read(View), Update, Delete.

I just can't find the supporting documentation to confirm this.

It just occured to me after writing all the above that the following might be even better:

<?php
  $access &= node_access($op, $node);
?>

Instead of guessing, just pass the operation through node_access() and let it decide.
Is this redundant in anyway?

lotyrin’s picture

Status: Needs review » Needs work

I'd say we should make a decent effort to see what the possible operations are and rework this function to be correct for all of them.

As it is it doesn't make much sense at all and fixing one-off cases just dusts the rest under the rug.

lotyrin’s picture

Not sure if this is right (haven't tested), but illustrates the direction I want this to go in.

zphen’s picture

This issue is limiting us on a system soon to go to prod.

Specifically we are trying to create a publisher role cannot edit a node, but can move it through transition states.

Due to the issue in this thread, the publisher role does not have the "view moderation history" link unless we give them permission to edit nodes.

Q: When will a patch be released for this?

Thanks for your assistance.

julien66’s picture

Status: Needs work » Patch (to be ported)

I run into the same issue. I have a simple workflow where anonymous user should be able to see the revision history + each past revision. I was unable to set it because I was not willing to grant them an editing access on the concerned node type.

=> I can confirm your patch (#5) is solving the issue without forgetting any operation where the code shouldn't grant the access ('update', 'unpublish'). It should be ported asap in my opinion since this seems to affect a quite common usage case...
++

hass’s picture

Status: Patch (to be ported) » Needs work
JvE’s picture

Status: Needs work » Needs review
JvE’s picture

Status: Needs review » Reviewed & tested by the community

#5 works fine for me. Thanks.

hass’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/workbench_moderation.moduleundefined
@@ -450,15 +450,20 @@ function workbench_moderation_node_access($node, $op, $account) {
-function _workbench_moderation_access($op, $node) {
-  global $user;
+function _workbench_moderation_access($op, $node, $account = NULL) {
+  if (empty($account)) {
+    $account = $GLOBALS['user'];
+  }

Looks not good. That's why we have $user, isn't it?

JvE’s picture

You mean like this?

global $user;
if (empty($account)) {
  $account = $user;
}

Doesn't make any difference to me.

stmh’s picture

I came accross the same problem and fixed it via a custom module implementing the hook_workbench_moderation_access_alter

function my_module_workbench_moderation_access_alter(&$access, $op, $node) {
  if($op == 'view history') {
    $access = user_access('view moderation history');
  }
}
hass’s picture

#12: yes, that's what I mean.

pfrenssen’s picture

Status: Needs work » Needs review
FileSize
2.37 KB
1.67 KB

Addressed Hass' remarks from #11 and did some further cleanup.

cboyden’s picture

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

Unlike other links on the moderation history tab, the "Edit draft" courtesy link doesn't check permissions. Starting at line 165 of workbench_moderation.node.inc:

    // Provide a courtesy edit operation if this is the current revision.
    if ($revision->vid == $node->workbench_moderation['current']->vid) {
      // The edit operation's default link title, "Edit draft", matches
      // the logic tree in workbench_moderation_edit_tab_title().
      $edit_operation_title = t('Edit draft');

      // Modify the edit operation's link title to "New draft", matching the
      // logic tree in workbench_moderation_edit_tab_title() when the current
      // revision is the published node.
      if (isset($node->workbench_moderation['published']) && $revision->vid == $node->workbench_moderation['published']->vid) {
        $edit_operation_title = t('New draft');
      }
      $revision_operations['edit'] = l($edit_operation_title, "node/{$revision->nid}/edit", array('query' => array('destination' => "node/{$revision->nid}/moderation")));
    }

With this patch in place, someone who can view moderation history but not edit will see an "Edit draft" or "New draft" link that leads them to a page with an access denied error. Instead, the courtesy link should check permissions, because it can no longer depend on the fact that this tab isn't visible to someone who can't edit.

cboyden’s picture

The updated patch adds an access check to the edit courtesy link that prevents showing it if the user can't edit the node.

Status: Needs review » Needs work

The last submitted patch, 17: 1512442-17-workbench_moderation-fix_access_check.patch, failed testing.

The last submitted patch, 17: 1512442-17-workbench_moderation-fix_access_check.patch, failed testing.

cboyden’s picture

Previous patch failed because the order of arguments was wrong for _workbench_moderation_access - it's the opposite of the order from _workbench_moderation_revision_access.

dzy’s picture

thanks! it worked.
Fix this issue then "moderator" can do his job with limit permission. I think it is the MOST important feature for this module.

dzy’s picture

function _workbench_moderation_moderate_access() had this:

$access = node_access('update', $node, $user)  // the user can edit the node
&& $my_revision->is_current // this is the current revision (no branching the revision history)
&& (!empty($next_states)) // there are next states the user may transition to
&& isset($next_states[$state]);  // this state is in the available next states

I think we should allow "moderator" role moderate content without edit node permission, he only need view node and moderate state permission.

about #20, function _workbench_moderation_access(), There is no return value?

+  if ($op == 'view revisions' || $op == 'view history') {
+    // The user must be able to see revisions.
+    _node_revision_access($node, 'view', $account);
+  }
dsnopek’s picture

Version: 7.x-1.x-dev » 7.x-3.x-dev
FileSize
3.09 KB

Reading over the patch, I think that @dzy made a good catch in #22 that nothing is being done with the return value of _node_revision_access(). That should either be integrated into $access, or perhaps that whole section should be removed? That bit of code (which up until now has done nothing) has been part of the patch since #5.

First, here's a patch that integrates that into $access - I want to see if any of the automated tests fail.

Status: Needs review » Needs work

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

dsnopek’s picture

Tests failed on #23, although, it's not super clear to me that it's from the change I made. I've queued a re-test of #20 just to make sure that patch is still passing (and it's not broken too due to some changes in the 7.x-3.x branch, or changes to Drupal or dependencies or the testbot)

dsnopek’s picture

Status: Needs work » Needs review
FileSize
3.13 KB
575 bytes

It looks like that was a legitimate failure. Here's an updated patch that attempts to fix.

Basically, my thinking is that previously you needed the ability to update the node for everything. The issue here is to change it so that for 'view revisions' and 'view history' you don't, only the permission to view node revisions. However, my update on the patch is to make is that the users who have update permission still get access, in addition to those with just the ability to view revisions.