Problem/Motivation
Visiting the approval URL for a comment that is already published gives a 403 response. Access denied is not really correct, the user has access, it's just already published.
Steps to reproduce
- Install Drupal
- Add an article
- Post a comment and make sure it is unpublished
- Copy the URL to approve the comment
- Publish/approve the comment
- Visit the approve URL again
- Get 'Access Denied' message
Proposed resolution
#16 suggests allowing access to the URL but showing a message, e.g., "This comment is published."
Remaining tasks
- Agree on the ideal behaviour
- Write a patch with tests
- Review
User interface changes
N/A
API changes
N/A
Data model changes
N/A
Release notes snippet
N/A
Original issue summary
This was pointed out by @webchick somewhere and passed along through several issues - see e.g. #66264-29: Remove CSRF vulnerability from comment module.
The bug is a relatively minor one, but if you try to approve a comment that is already published (by visiting the appropriate comment/%/approve URL directly), you are not prevented from doing so - instead you get a "Comment approved" message on the screen.
We should at least change the message in that case, if not prevent it via the access callback completely (the latter because if anyone tries to use this link as anything other than a menu callback, they presumably don't want the "approve" link to show up in places where it doesn't make sense).
| Comment | File | Size | Author |
|---|
Issue fork drupal-748996
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 #1
sunI'd expect a redirect back to where I came from + proper message "The comment is already published.".
Comment #2
lyricnz commentedPatch that changes the message attached.
Comment #3
sunComment #4
lyricnz commentedPatch works fine on D8 too.
Comment #5
marvil07 commentedMinor re-roll for core/ directory change.
This works as expected.
Comment #7
marvil07 commentedUn-related error:
Comment #8
karthid commentedThe patch no longer applies. Because drupal 8.x folder structure has been changed now.
Comment #9
karthid commentedRe-roll for core/ directory change.
This works as expected.
Comment #10
marvil07 commentedYep, last two patches are exactly equal ;-)
This is trivial, so hopefully it's OK to move it to RTBC.
Comment #11
marvil07 commentedBTW, this is a bug.
Comment #12
marvil07 commentedhttp://drupal.org/node/314328#assigned
Comment #13
webchickNice fix! Let's add an automated test to make sure we don't break it again. :)
Also, this is a nitpick, but
Let's also shorten up that message so it's more inline with the approved one. Something like "Comment already published."
Does this need backport to D7 as well?
Comment #14
andypost\Drupal\comment\Controller\CommentController::commentApprove()nowComment #15
andrey_zb commentedI reviewed this issue and wonder if there is anything to do?
Having approve functionality in \Drupal\comment\Controller\CommentController::commentApprove() (#14) marks published comments as "approved".
May be there are any test cases, when the issue can be reproduced?
Comment #16
David_Rothstein commentedNot sure why this was moved to 8.1.x. And yes, it needs backport to Drupal 7.
Testing this in Drupal 8 it looks like it may be fixed. There is nothing in \Drupal\comment\Controller\CommentController::commentApprove() itself to fix this, but I get access denied when I try to approve an already-approved comment. (This is one of the suggestions I made when filing this issue originally, although the patches since then were going in the other direction - i.e. keeping access to the URL but displaying a message instead.)
I guess tests would still be a good idea for this in Drupal 8, if they don't already exist.
Comment #17
andypostminor bug with tests + UX could came in for 8.0
Comment #18
Usha Gavva commentedPatch rerolled!
Comment #19
andypostpatch is totally wrong, keep tags!
Comment #20
andypostproper re-roll, still needs tests
Comment #21
marvil07 commentedRevisiting this issue, the problems mentioned seems to be resolved.
First, _csrf_token prevents access directly to the link.
Second, as reiterated on comment #16, there is already a check for the published status in place after #2322949: Implement generic entity link view field handlers, i.e. see
CommentAccessControlHandler::checkAccess(); which should prevent the bad message on a race condition, e.g. two users approving the content at the same time.About tests, the csrf part already has tests on
CommentAdminTest::testApprovalNodeInterface(), and the other part I think is not possible to be tested unless we can have in parallel to users in different screens.The only possible improvement I see now may be to be able to return 400 (Bad Request) http status on the race condition case instead of the current 403, but I guess that could be another issue instead.
Pending: someone to confirm the position before closing this, and maybe open a new issue for the 403 to 400 change.
Comment #22
andypostThe reason behind the issue is UX, having 403/400 here is wrong, because user has permission to approve.
So in this case controller should properly report status of approval operation.
Comment #31
pameeela commentedUpdated IS for current state.
Comment #33
mohit_aghera commentedComment #34
mohit_aghera commentedComment #36
mohit_aghera commentedI have implemented the following changes:
- Re-roll the patch.
- Add a test case to validate the message.
For the test cases, I am bypassing CSRF token and other validation by adding a new route in comment_test module.
My main intention is to test the proper messages only.
I agree that 400/403 is somewhat confusing because the admin already has the permission to approve the comment.
As @andypost mentioned that it is validated in the below AccessController method.
To get the proper message and response code, I think we can remove
!$entity->isPublished()validation as we are already showing proper messages in controller method.I haven't removed that as of now as it would be great if we have some inputs from the product owner or subsystem maintainers.
Comment #37
larowlanI think it would be better to add a custom exception handler, check the route name, and if its this route, display a message and send them back to the commented entity via a redirect
e.g extend from HttpExceptionSubscriberBase and add a method `on403`
Inject the route match and messenger service, and if the route is the comment approval one, display the message and return a new redirect response (to the comment canonical path)
For testing, fetch the page that has the approve link then publish the comment via the api (e.g. $comment->status = 1; $comment->save())
Then click the link and assert the message is output and the redirect occurs.
Comment #38
larowlanalternatively we could probably remove the published check from the route and handle it in the controller instead, with a redirect from there
might be better than having a custom exception handler in memory in the event dispatcher on every page
Comment #39
mohit_aghera commentedImplemented the following changes:
- Removed
!$entity->isPublished())from thecheckAccess()in AccessController- Update test cases to validate that accordingly.
- Remove additional changes added in previous commit.
Comment #41
paulocsSmall fix to remove the t() calls in the test file. See: https://www.drupal.org/docs/automated-testing/phpunit-in-drupal/phpunit-browser-test-tutorial#t
Except for that, the merge request looks good.
Comment #42
larowlanHiding patch files
Comment #43
larowlanLeft a minor readability suggestion, but this looks good to me
Comment #44
joachim commentedLGTM.
Comment #45
larowlanThere are at least two contrib projects checking the 'approve' permission http://grep.xnddx.ru/search?text=-%3Eaccess%28%27approve&filename=
Can we just confirm that there's no security impact of this change
Comment #46
andypostLooking at related list I bet there's impact
Comment #47
mohit_aghera commented@andypost @larowlan
I did a quick review of all the MR/issues mentioned in the above comment.
In our case, primarily we are changing "approve" operation access.
I think https://www.drupal.org/project/drupal/issues/2879087 might have significant conflicts.
IMO, can we revisit later after the https://www.drupal.org/project/drupal/issues/2879087 is merged?
Comment #51
smustgrave commentedCan we update MR to 10.1 please.
Comment #54
rpayanmPlease review.
Comment #55
lyricnz commentedI can't believe this issue is still open! :)
Comment #56
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
Seems the D10 MR 3384 has some failures.
@andypost and @larowlan does #47 answer your comments about security?