Problem/Motivation

The logout link can only be requested between the time a page was requested and when a session expires. If a user agent has a stale page, such as due to caching or a long lived page, then attempts to logout after the session expires, he will receive a 403 access denied.

Proposed resolution

if an anonymous session attempts to access user/logout, the site will redirect to the front page without fuss.

Behaviour changes

User redirected to <front> route instead of 403

Tested the patch in #61 on 9.1.x and can confirm that, as anonymous, an attempt to logout resulted in a 403 and after applying the patch an attempt to logout redirected to the front page.

Original report by jim_at_miramontes

I don't think this is a duplicate of any previous issues; I'm encountering this situation with a D7 site: a user:

  1. leaves a browser window open on the site,
  2. gets timed out on the back end for having been inactive too long,
  3. returns to the browser after that long delay, and
  4. without refreshing the page, tries to log out via a link on that page to user/logout.

The access callback for user/logout is user_is_logged_in(), which fails in this situation since the user is logged out. As a result, the user gets the results of a 403 error rather than being thrown back to the home page via the drupal_goto() in user_logout().

This is admittedly a minor point, but it wouldn't be hard to address:
Give user_logout() an open access callback so it can run even when the user is logged out, and
Modify user_logout() do only do its work if there is a logged-in $user (and maybe raise an error message via drupal_set_message if the user was already logged out).

(See https://drupal.org/node/2192401 for a bit more discussion of this, btw.)

CommentFileSizeAuthor
#66 BeforeApplyPatch61.png29.2 KBpaulocs
#66 AfterApplyPatch61.png27.71 KBpaulocs
#61 interdiff.2193803.58-61.txt573 bytesabhisekmazumdar
#61 2193803-61-anonymous_users_receive_access_denied_when_attempting_logout.patch1.72 KBabhisekmazumdar
#58 interdiff_52-58.txt548 bytesridhimaabrol24
#58 2193803-58.patch1.67 KBridhimaabrol24
#58 2193803-58-test-only.patch701 bytesridhimaabrol24
#53 afterPatch.JPG25.71 KBpankaj.singh
#53 beforePatch.JPG24.1 KBpankaj.singh
#52 interdiff_49-52.txt422 bytesnarendra.rajwar27
#52 2193803-52.patch1005 bytesnarendra.rajwar27
#50 2193803-49.patch1010 bytesmanish.upadhyay
#41 userinterdiff.txt1.14 KBPavan B S
#41 2193803-40.patch993 bytesPavan B S
#40 interdiff-2193803-36-39.txt2.57 KBwturrell
#40 2193803-39.patch2.27 KBwturrell
#36 2193803-36.patch2.23 KBwturrell
#36 interdiff-2193803-34-36.txt1.38 KBwturrell
#34 interdiff-2193803-32-34.txt1.15 KBwturrell
#34 2193803-34.patch2.33 KBwturrell
#32 interdiff-2193803-30-32.txt1004 byteswturrell
#32 2193803-32.patch2.11 KBwturrell
#30 interdiff-2193803-26-30.txt724 byteswturrell
#30 2193803-30.patch2.03 KBwturrell
#26 2193803-26-test-only.patch971 byteswturrell
#25 interdiff-2193803-21-25.txt1.09 KBwturrell
#25 2193803-25.patch1.93 KBwturrell
#22 interdiff-2193803-18-21.txt1.87 KBwturrell
#22 2193803-21.patch2.07 KBwturrell
#20 interdiff-2193803-18-20.txt1.1 KBwturrell
#20 2193803-20.patch2.08 KBwturrell
#18 interdiff-2193803-15-18.txt1.1 KBwturrell
#18 2193803-18.patch2.08 KBwturrell
#15 2193803-logout-access-denied-15.patch1005 bytesdpi
#8 logged_out_user_goes_to-2193803-8.patch1.28 KBmglaman
#7 logged_out_user_goes_to-2193803-7.patch9.13 KBmglaman
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Jooblay.net’s picture

Do you have any rules setup on user logout?

jim_at_miramontes’s picture

No, I don't.

Charles Belov’s picture

Version: 7.26 » 8.0.x-dev
Issue tags: +Usability

Reproduced in 8.0-alpha14 (also happens if logging out from 2 browser tabs). Alternative solution would be going to <front> if already logged out.

That said, while the current behavior is harmless, I find it disconcerting and unfriendly, so added the usability tag.

Charles Belov’s picture

Status: Active » Closed (duplicate)

Duplicate of [#2192401] https://drupal.org/node/2192401

Charles Belov’s picture

Charles Belov’s picture

Status: Closed (duplicate) » Active

Closed by mistake. #2192401 is a support request, not an issue.

mglaman’s picture

Status: Active » Needs review
FileSize
9.13 KB

Here is a patch that removes requirements on user/logout route, and in user_logout() checks if the user is not anonymous to finish log out and session destroy.

mglaman’s picture

FileSize
1.28 KB

Wrong patch. Here's right one.

dawehner’s picture

Status: Needs review » Needs work
+++ b/core/modules/user/user.routing.yml
@@ -10,8 +10,6 @@ user.logout:
   path: '/user/logout'
   defaults:
     _controller: '\Drupal\user\Controller\UserController::logout'
-  requirements:
-    _user_is_logged_in: 'TRUE'
 

I would love to have route level based checking, as it will just work better. For example the other code might return a 200 even it should return a 403. IN general this will fail completly, because you always need some access checking at least.

The last submitted patch, 7: logged_out_user_goes_to-2193803-7.patch, failed testing.

mglaman’s picture

I see. I'm not sure how we could make the best of both worlds happen, I'll try to do some research.

The last submitted patch, 8: logged_out_user_goes_to-2193803-8.patch, failed testing.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dpi’s picture

Title: logged out user goes to user/logout -> access denied :( » Anonymous users receive access denied when attempting to logout
Issue summary: View changes
Status: Needs work » Needs review
FileSize
1005 bytes

Reworded IS/title

I'm not sure I follow #2193803-9: Anonymous users receive access denied when attempting to logout. Here is a new patch.

wturrell’s picture

Partial review.

- Can reproduce initial problem
- issue fixed by patch #15 (8.2.x)
- Passes tests (+ no issues with manually logout as an authenticated user)
- Seems in scope
- Automated coding standard checks OK
- No UI changes

Probably needs a new test?

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

wturrell’s picture

dpi’s picture

Status: Needs review » Needs work

+class UserLogoutTest extends WebTestBase {

New tests should use functional browserbase.

+ * Test anonymous users can visit /user/logout without Access Denied.

*~test both logged in, and not logged in can access /user/logout.

(create two test methods: testAnonymousUserLogout, testUserLogout)

+    $request = Request::create('/user/logout');
+    $request->setFormat('html', ['text/html']);
+
+    /** @var \Symfony\Component\HttpKernel\HttpKernelInterface $kernel */
+    $kernel = \Drupal::getContainer()->get('http_kernel');
+    $response = $kernel->handle($request)->prepare($request);

If you're going to fake a request, you may as well use kernel test base...

Though, I think these tests should be browser tests.

+ $this->assertNotEqual($response->getStatusCode(), Response::HTTP_FORBIDDEN,

assertNoting anything is dangerous. Avoid when you can.

This will no fail if for example, something bad is causing the system to 404 everything (or any other non 403 code)

The test is to assert that all users *can* access. So, assertEqual 200.

+ 'Anonymous users may view /user/logout without 403 error'
+ );

Assert message shouldn't be multiline. Strict 80 char wrapping is for PHP comments.

wturrell’s picture

Status: Needs work » Needs review
FileSize
2.08 KB
1.1 KB

[EDIT - ignore - wrong upload]

Status: Needs review » Needs work

The last submitted patch, 20: 2193803-20.patch, failed testing.

wturrell’s picture

Status: Needs work » Needs review
FileSize
2.07 KB
1.87 KB

Try again…

dpi’s picture

Status: Needs review » Needs work
+   * Test authenticated users can logout successfully.
+   */
+  public function testUserLogout() {
+    // Login as an ordinary authenticated user.
+

Inline comment is unnecessary given the method comment directly above.

+    $account = $this->drupalCreateUser([]);

empty array for first arg.

+ public function testUserLogout() {

Perhaps 'authenticated' is better than 'user'. Makes for easier comparison.

dpi’s picture

+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+  }

Empty method.

wturrell’s picture

Status: Needs work » Needs review
FileSize
1.93 KB
1.09 KB

Yep, all sensible.

wturrell’s picture

Test-only patch at @dpi's request

Status: Needs review » Needs work

The last submitted patch, 26: 2193803-26-test-only.patch, failed testing.

dpi’s picture

Status: Needs work » Reviewed & tested by the community

#26 Thanks! Looks good

catch’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/user/src/Tests/UserLogoutTest.php
@@ -0,0 +1,33 @@
+    $this->assertSession()->statusCodeEquals(200);

We've had bugs with fatal errors showing up as 200s before (and this still isn't 100% solved), so this could use a positive assertion, i.e. that we're on the front page, as well as the check for the 200.

I've been hit by this many, many times, so would be nice to fix it.

wturrell’s picture

Status: Needs work » Needs review
FileSize
2.03 KB
724 bytes

addressEquals() assertions added.

dpi’s picture

Status: Needs review » Needs work

+ $this->assertSession()->addressEquals('/');

Url::fromRoute('<front>')->toString(); reads better / self documenting

wturrell’s picture

Generate URLs for the tests with Url::fromRoute()

Status: Needs review » Needs work

The last submitted patch, 32: 2193803-32.patch, failed testing.

wturrell’s picture

Status: Needs work » Needs review
FileSize
2.33 KB
1.15 KB

Failure was:

Current page is "/", but "/checkout/" expected.

Attempting to fix by copying this patch

dpi’s picture

Status: Needs review » Needs work
+    $this->assertSession()->addressEquals(Url::fromRoute('<front>')
+                                             ->setAbsolute()
+                                             ->toString());

Method call indents are maximum 2 spaces.

You can choose to do it all on one line, where the method calls are simple (usually just one method).

However, I suggest you using our chaining style, creating a variable beforehand:

$expected_url = j->k()
  ->l()
  ->m();
addressEquals($expected_url);
wturrell’s picture

Status: Needs work » Needs review
FileSize
1.38 KB
2.23 KB

Coding style changed as per #35.

dawehner’s picture

+++ b/core/modules/user/src/Controller/UserController.php
--- /dev/null
+++ b/core/modules/user/src/Tests/UserLogoutTest.php

+++ b/core/modules/user/src/Tests/UserLogoutTest.php
@@ -0,0 +1,44 @@
+class UserLogoutTest extends BrowserTestBase {

Note: BrowserTests should be placed inside user/tests/src/Functional

dpi’s picture

+ $expected_url = Url::fromRoute('<front>')

So close!

Place expected variable right before you use it. Doesnt make a lot of sense re-locating them so far back.

Status: Needs review » Needs work

The last submitted patch, 36: 2193803-36.patch, failed testing.

wturrell’s picture

Moved from src/Tests to /tests/src/Functional (#37)
Reordered statements (#38)
Believe previous test fail was random (passed locally)

Pavan B S’s picture

After applying the patch, i got the error as UserLogoutTest.php already exist, re -updating the patch by removing that, please suggest me if i am wrong.

dpi’s picture

@41

After applying the patch, i got the error as UserLogoutTest.php already exist, re -updating the patch by removing that, please suggest me if i am wrong.

The test certainly does not exist: http://cgit.drupalcode.org/drupal/tree/core/modules/user/tests/src/Funct.... Re-check your local environment.

In the future, if you need to check whether a patch still applies, use the retest facility.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

bvoynick’s picture

Patch #40 (file is labeled 39) still passes, at least against 8.6/PHP 7.1. Does it need anything else before being a candidate for RBTC?

goodboy’s picture

  1. Delete the extra line
    +  public function testAnonymousLogout() {
    +
    +    $this->drupalGet('/user/logout');
    
  2. Using Response::HTTP_OK instead of 200
  3. Maybe it's debatable, but I would prefer a message like this.
         if ($this->currentUser()->isAuthenticated()) {
           user_logout();
         }
    +   else {
    +     \Drupal::logger('user')->notice('You are already logged out.');
    +   }
    
  4. Change version to 8.7.x-dev

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.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.

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

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should 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.

manish.upadhyay’s picture

Patch for 8.9 Drupal release.

Status: Needs review » Needs work

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

narendra.rajwar27’s picture

Status: Needs work » Needs review
FileSize
1005 bytes
422 bytes

coding standards fixes only

pankaj.singh’s picture

FileSize
24.1 KB
25.71 KB

Tested the patch given in #52, it's working fine. Post applying the patch and appending user/logout its re-direct to the front page.

Please refer to SS attached for ref.

Liam Morland’s picture

Status: Needs review » Reviewed & tested by the community

Code looks good. Works for me.

catch’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

This is a reasonable change, however it could use test coverage. - i.e. as an anonymous user, visit user/logout, and make sure you land on the front page with no errors.

surya.s’s picture

Status: Needs work » Reviewed & tested by the community

Verified the patch.Works fine. Not getting access denied page and its redirecting to page.

amateescu’s picture

Status: Reviewed & tested by the community » Needs work

Back to NW per #55.

ridhimaabrol24’s picture

Status: Needs work » Needs review
FileSize
701 bytes
1.67 KB
548 bytes

Added a test for this change. Please review!

The last submitted patch, 58: 2193803-58-test-only.patch, failed testing. View results

Liam Morland’s picture

Looks good. I would mark this RTBC except that I suggest adding this to the test:

$this->assertSession()->statusCodeEquals(200);
abhisekmazumdar’s picture

Liam Morland’s picture

Status: Needs review » Reviewed & tested by the community

Looks good. Thanks.

quietone’s picture

Version: 8.9.x-dev » 9.1.x-dev
Issue tags: -Needs tests

There is a test, so removing tag. This is a feature request, so pretty sure it needs to be fixes on HEAD, changing version and running tests. Correct me if I am wrong about that.

quietone’s picture

Status: Reviewed & tested by the community » Needs review

Setting NR while waiting on tests

quietone’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

Nice. This applies to 9.1.x and tests pass.

I also manually tested on 9.1.x and this works as expected, updated the IS with those results.

Since I haven't made any changes to the patch I am setting back to RTBC.

paulocs’s picture

Patch #61 looks good and it is a more friendly approach than as it is now.
I attached images before and after I applied the patch.

RTBC +1

Cheers, Paulo.

  • catch committed 1b628f4 on 9.1.x
    Issue #2193803 by wturrell, ridhimaabrol24, mglaman, Pavan B S, narendra...
catch’s picture

Category: Feature request » Bug report
Status: Reviewed & tested by the community » Fixed

Committed 1b628f4 and pushed to 9.1.x. Thanks!

Thought about backporting. For me this is an obvious bug, but there is a tiny chance that contrib or custom code is altering the route access, and changing the access could interfere with that. So... leaving in 9.1.x but if you feel strongly this should be backported please re-open and we can discuss a bit more.

Status: Fixed » Closed (fixed)

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