Problem/Motivation

Drupal login requires user browser cookie support. However, in the case that a user does not have cookies enabled and attempts to log in, no error message is given. Instead, the user is returned to the /user/{uid} page with 403 error code. As well as being a bug, the lack of cookie notification constitutes a key usability barrier in that users who hit the bug have no cue as to what is needed in order to log in.

Related issue at install time: #791004: Installer does not warn the user that cookies must be enabled with the correct cookie domain (and fails when they aren't).

Other PHP applications by way of comparison:

Wordpress:
Code is in http://core.svn.wordpress.org/trunk/wp-login.php. Prior to login, a test cookie is set:

//Set a cookie now to see if they are supported by the browser.
setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN);
if ( SITECOOKIEPATH != COOKIEPATH )
	setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN);

A hidden element is added to the login form:

<input type="hidden" name="testcookie" value="1" />

On login attempt, if the testcookie flag is set but the test cookie is not present, an error is raised:

	// If cookies are disabled we can't log in even with a valid user+pass
	if ( isset($_POST['testcookie']) && empty($_COOKIE[TEST_COOKIE]) )
		$errors->add('test_cookie', __("<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href='http://www.google.com/cookies.html'>enable cookies</a> to use WordPress."));

Joomla: Reportedly doesn't provide user feedback on cookie failure; see this forum post.
Symfony: Cookie handling doesn't appear to include a test for browser cookie support.

Proposed resolution

The proposed patch takes the following approach:

  • Add a querystring parameter "state=check_logged_in" upon login form submission.
  • On Kernel Request, if the parameter exists and the user is not actually logged in, then we know they don't have cookies enabled so we set a form error.

Remaining tasks

  • Additional test coverage, and/or remove "Needs tests" tag
  • Drupal\Core\EventSubscriber\MaintenanceModeSubscriber::checkUserCookies should be moved to a better appropriate ServiceSubscriber such as: Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber. For now, the checkUserCookies has nothing in relation with the MaintenanceMode
  • Discuss about the comment of #217 of user_login_form_submit hook. What was the purpose should we keep it?
  • The current patch was an initial draft. Several other possibilities have been suggested since, with no clear consensus as yet. #145 includes a reasonably current summary of options. Latest comment from D8 maintainer catch: "I don't like either the double redirect option, or the runtime check on every page here, but neither do I have any better ideas - would be good to get some feedback from others."
  • #138 reports the following issue with the patch: "if the user logs off and uses the browser's history or back button to return to the page containing the "state=loggedin" query, then the cookie warning message is displayed when it shouldn't be. It would be possible to reword the message to allow for this possibility, absent a better solution."
  • #123: "some of the information in this issue needs to be added to user_init() in a comment if we go for this option."
  • The current patch generates two errors. From #160: "Those two failures look like they're specific to the solution here (probably code that expects a specific URL after logging in and therefore gets confused by the new ?state=loggedin). So not worth fixing unless this is the actual solution we're going with."
  • Given that this is a common need that's been addressed in many other PHP applications but not in Drupal, we'd do well to look around. Some information is above in the issue summary. More research welcome.

User interface changes

Users attempting to log in will receive an error message if they don't have cookies enabled.

API changes

Modifies the user login process by adding a query string "state=loggedin" and testing for it during KernelEvents::REQUEST.

Original report by anders

since drupal relies on cookies for logging in, not warning the user if the cookie is not allowed is plain old stupidity.

We need a warning to regular user (on an already installed Drupal site) that they need to enable cookies to be able to log in on the site.

Right now nothing is displayed if cookies and not enabled and the user have not clues as to why.

We did have a patch (but it need a reroll), and a test.

CommentFileSizeAuthor
#300 2021-12-22 22_09_24-Window.jpg7.44 KBcosolom
#293 Screen Shot 2021-06-25 at 2.34.29 pm.png71.79 KBlarowlan
#279 2946-279.patch10.52 KBquietone
#256 2020-12-12-130826-2946-255-one-time-login.png224.69 KBmichaellenahan
#256 2020-12-12-130732-2946-255-user-login.png203.54 KBmichaellenahan
#255 2946-255.patch10.38 KBalexpott
#255 252-255-interdiff.txt10.3 KBalexpott
#252 interdiff_245-252.diff8.83 KBmichaellenahan
#252 2946-252.patch12.46 KBmichaellenahan
#247 Screenshot.png19.01 KBifrik
#245 2020-12-11-143729-2946-245-your-browser-must-accept-cookies.png227.1 KBmichaellenahan
#245 interdiff_239-245.diff1.47 KBmichaellenahan
#245 2946-245.patch9.01 KBmichaellenahan
#243 interdiff.2946.233-239.txt5.25 KBifrik
#239 2946-239.patch8.83 KBwengerk
#233 2946-233.patch9.33 KBtatarbj
#232 2946-232.patch9.51 KBtatarbj
#228 interdiff-2946-226-228.txt626 bytesAaronBauman
#228 2946-228.patch9.42 KBAaronBauman
#226 interdiff-2946-223-226.txt7.91 KBAaronBauman
#226 2946-226.patch9.42 KBAaronBauman
#224 interdiff-2946-217-223.txt3.95 KBwengerk
#224 2946-223.patch7.87 KBwengerk
#217 interdiff-2946-210-217.txt2.92 KBwengerk
#217 2946-217.patch7.33 KBwengerk
#210 login_fails-2946-210.patch7.13 KBGogowitsch
#202 login_fails-2946-202.patch6.79 KBdeepakrmklm
#201 2946-diff-196-201.txt930 bytesvijaycs85
#201 2946-201.patch10.1 KBvijaycs85
#196 login_fails_and_no-2946-196.patch10.19 KBjcnventura
#196 interdiff.txt3.46 KBjcnventura
#192 interdiff.txt2.23 KBWim Leers
#192 login_fails_and_no-2946-192.patch9.53 KBWim Leers
#188 login_fails_and_no-2946-188.patch8.77 KBjcnventura
#188 interdiff.txt806 bytesjcnventura
#185 interdiff-2946-182-185.txt3.77 KBanoopjohn
#185 login_fails_and_no-2946-185.patch7.06 KBanoopjohn
#182 login_fails_and_no-2946-182.patch6.79 KBiMiksu
#182 interdiff.txt1.27 KBiMiksu
#177 login_fails_and_no-2946-177.patch5.52 KBjcnventura
#173 cookie-validate-2946-mine.patch5.5 KBjcnventura
#164 cookie-validate-2946-164.patch6.76 KBpplantinga
#162 cookie-validate-2946-162.patch5.04 KBpplantinga
#158 cookie-validate-2946-158-TESTS-ONLY.patch2.2 KBDavid_Rothstein
#158 cookie-validate-2946-158.patch4.8 KBDavid_Rothstein
#114 cookie_validate_2946_114.patch1.69 KBOwen Barton
#104 cookie_validate_2946_reroll.patch2.63 KBbleen
#85 cookie-validation-2946.patch2.27 KBrobeano
#76 cookie-validation.patch2.23 KBnedjo
#68 user-no-cookies-2946-67.patch1.71 KBchx
#55 user-no-cookies-2946-55.patch2.31 KBsoxofaan
#48 user-no-cookies-2946-48.patch3 KBchx
#47 user-no-cookies-2946-47.patch2.93 KBchx
#46 user-no-cookies-2946-46.patch2.96 KBchx
#45 user-no-cookies-2946-45.patch2.96 KBchx
#43 user-no-cookies-2946-43.patch2.63 KBchx
#35 user-no-cookies-2946-34.patch3.06 KBbjaspan
#30 drupal-HEAD.no-cookies.patch2.62 KBsun
#27 drupal-HEAD.no-cookies.patch2.64 KBsun
#26 no-cookie-2946-26.patch2.68 KBsalvis
#21 no-cookie-2946-21.patch2.68 KBsalvis
#17 no-cookie-2946-17.patch1.96 KBchx
#10 no_cookie-2946-10.patch6.78 KBchx
#7 no-cookie.patch1.96 KBchx

Issue fork drupal-2946

Command icon 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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Dries’s picture

Category: bug » feature
Priority: Critical » Normal

Making this a feature request instead of critical bug report. Tss.

JonBob’s picture

katok’s picture

bdragon’s picture

Version: » 6.x-dev
Status: Active » Closed (duplicate)

Marking as duplicate of http://drupal.org/node/137678

dww’s picture

Status: Closed (duplicate) » Active

There's some useful discussion over at http://drupal.org/node/137678 but we should continue with this, the oldest issue, as the active one that needs to be resolved.

beginner’s picture

Category: feature » bug

Offering a user to log-in in a situation where the login will automatically fail can safely be considered a bug.

chx’s picture

Status: Active » Needs review
FileSize
1.96 KB

This is a bit tricky but I figured it out. Messages do not work here too well because you get a new session on every single page. So we redirect you to a help page if there are no cookies, but not everytime.

chx’s picture

snufkin’s picture

Status: Needs review » Reviewed & tested by the community

trying to log in now brings to a page with a brief description about the missing cookie support. It could be enhanced later, but with this the bug is solved for now.

chx’s picture

FileSize
6.78 KB

Yeah but as comment cookies need path set so do these. It's not trivial under testing because it's only a problem if you land on the non-root page and try to log on another page.

beginner’s picture

Status: Reviewed & tested by the community » Needs review

Errr... can you explain patch #10. Is it the right issue?

As to patch #7, this is a patch my poor brain can understand. I am satisfied that it is a good approach.
But we are only at the stage of reviewing the concept. #10 has not been reviewed, and #7 is not RTBC in any case: if the patch works and is accepted, at the very least the message on the no_cookie page should be improved (poor grammar, not enough information). It's good enough for testing, so it's good enough for now, but it will have to be improved before we can set it RTBC.

beginner’s picture

Speakind about the documentation on the no_cookie page, see #6 here:
http://drupal.org/node/137678#comment-271450

I personally think it's a bit too much, but it can give some ideas. What do you think?

drewish’s picture

yeah #10 looks like the wrong patch.

Chris Johnson’s picture

#10 looks like the completely wrong file got uploaded. Yoohoo, CHX...

beginner’s picture

I think we know that, by now.

What I would like to know, is the answer to #12, so that we can move ahead...

snufkin’s picture

roll a patch with this text, so we can check it ;)

I think this could be committed though, its only the cosmetics of the text we try to fix now, the issue itself is solved.

chx’s picture

FileSize
1.96 KB

Well, #10 and #7 wanted to differ only in the path component and I indeed upped the wrong version. About the text, it's a placeholder, someone else will write the text, it's not my cup of tea.

chx’s picture

Also, about the linked comment. One, it misses firefox, opera, safari and ie7. Second, the big problem here is that it's not necessarily the browser that kills your cookies -- it can be your personal firewall (zonealarm is a notorious offender), it can be a bad proxy in the way etc etc

snufkin’s picture

Let's have this committed, and I will open a new issue about the text. This way we keep this thread to the technological issue, and that to discuss the helptext. How about it?

nedjo’s picture

Nice work chx.

Needed this so turned it into a D5 contrib module, http://drupal.org/project/cookie_check. Here's the message I used:


  global $base_url;
  $url = parse_url($base_url);
  $text = t('It seems that your browser does not accept cookies. To log into this site, you will need to accept cookies from the domain @domain.', array('@domain' => $url['host']));
  return $text;

salvis’s picture

Status: Needs review » Needs work
FileSize
2.68 KB

Applied nedjo's text and rerolled for HEAD.

Unfortunately, user/no_cookie gives me "Page not found."

nedjo’s picture

Thanks for the updated patch.

Unfortunately, user/no_cookie gives me "Page not found."

Did you refresh your menu item cache? Since the module is already enabled, you'll need to do so to get the new menu item available. You could try e.g. disabling then reenabling a module.

salvis’s picture

Status: Needs work » Needs review

Ah, yes, clearing the cache has made it work. Thanks!

catch’s picture

Status: Needs review » Reviewed & tested by the community

This looks good to me. Tested, works great.

catch’s picture

Status: Reviewed & tested by the community » Needs review

Actually no, "Cookie problems" isn't a great title - implies that Drupal's having problems rather than the user's browser.

Would suggest "Please Enable Cookies" or something like that.

salvis’s picture

FileSize
2.68 KB

Ok, I've changed the title to 'Please Enable Cookies!'

sun’s picture

Slightly changed wording.

catch’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me.

On a side note, I tested the patch in IE7 to avoid affecting tabs in firefox. Then left cookies off. Then cleared my D6 install and later wanted to test some js in IE7. How much did I miss this patch the first couple of times I tried to log in! Only took five seconds to work out what was going on in this case, but a big improvement.

RobRoy’s picture

Status: Reviewed & tested by the community » Needs work

- Drupal core paths use dashes instead of underscores...should be user/no-cookie.
- Might as well just return t(...) instead of setting an unneeded $text variable.

sun’s picture

Status: Needs work » Needs review
FileSize
2.62 KB
bjaspan’s picture

subscribe

sun’s picture

Status: Needs review » Reviewed & tested by the community
bjaspan’s picture

I suggest that user_no_cookie() should return theme('user_no_cookie') so sites can override this hard-coded text.

sun’s picture

Status: Reviewed & tested by the community » Needs work
bjaspan’s picture

New patch. The only change here relative to #30 is the theme_user_no_cookie() instead of hard-coding the text.

This bug has always annoyed me but perhaps it is too late for D6. I think there are valid outstanding questions:

1. The default text (http://drupal.org/node/137678 has something but it isn't done).
2. Should the cookie path really be "/" and not session.cookie_path?
3. Probably others.

bjaspan’s picture

Oh, and how long should the login_check cookie survive and/or should it use some kind of unique value to try to identify if the login_check cookie that is coming back is the one that just got set?

I think while testing in IE6 I observed that by turning off cookies I was only turning off accepting new cookies, not disabling the delivering cookies I already had. So a login_check cookie I received while testing yesterday was being delivered even though I had "turned off cookies" so my new session cookie wasn't being accepted. The result was that login failed but I did *not* get redirected to the no_cookie page b/c the login_check cookie was delivered. This could make debugging login problems even harder, so we need to understand this before committing.

chx’s picture

The cookie should be deleted after logging in.

Gábor Hojtsy’s picture

Patch looks reasonable. I am not sure, but maybe we can expalain how cookies can be set to be accepted in simple terms (ie. "turn off private browsing" if this is common enough among browsers).

http://drupal.org/node/137678 has good source data for a documentation page to put up. While that should not be included in Drupal itself, and it might not be wise to direct innocent users to drupal.org, it would be a good docs page. :| Thinking out loud.

salvis’s picture

Gábor, please don't try to save the world with this patch! There are countless reasons why cookies might not go through, beyond what the browser does, and every browser uses its own terminology anyway. I've never heard of "private browsing" -- would you really want to take responsibility for whatever could happen if a user "turns off private browsing" on some unknown system? Helping the user to solve the problem is way beyond what Drupal can do.

The intent of this humble patch is to diagnose the problem, and this alone will put us miles ahead of where we are now, where the user has absolutely no clue about why his password is accepted, but he still doesn't get access.

Users who have cookies turned off, will usually know how to turn them on, because the situation comes up regularly on all sorts of sites -- but they need to know what the problem is!!!

Please excuse me if this comes accross a bit too strong, but I'm desperate about this...

Gábor Hojtsy’s picture

OK, let's fix chx's concern at least first.

chx’s picture

Status: Needs work » Needs review
FileSize
2.63 KB

A lot better patch. Instead of session.inc , I patched drupal_anonymous_user. Same: if your system can't hold cookies then on the page load your cookie will be set but it's only available on the next page load. I have adjusted the cookie domain to the session cookie domain, too. And now I delete it in user_login_submit.

Gábor Hojtsy’s picture

Status: Needs review » Needs work

Actually, drupal_anonymous_user() is used to as generic anonymous user object fetcher function (I have seen it used as an $account parameter generator for access checks for example). So I don't think it is a good idea to build side effects into it.

chx’s picture

Status: Needs work » Needs review
FileSize
2.96 KB

OK then. it's still better than the older ones because we now patch both places where anonymous user can happen.

chx’s picture

Doh.

chx’s picture

Adjusted user_no_cookie function to use the relevant domain.

chx’s picture

Added domains to the setcookie .

salvis’s picture

Status: Needs review » Reviewed & tested by the community

Yes, now it works perfectly, including deleting the cookie upon log-in. Thanks!

Dries’s picture

I'm not really sure this is worth fixing. Looks a bit crufty to me.

beginner’s picture

This is a huge useability improvement, and makes Help Desk workers happier :)

++ 1 for the patch.

catch’s picture

+1 from me as well. We get regular e-mails from people saying "I can't log in!!11!!" and if this reduces them by even 5% that'd be great.

salvis’s picture

I run with paranoid firewall and browser settings, and I can't remember encountering a site that didn't tell me I needed to enable cookies when it requires them, except for Drupal sites, that is.

Drupal really, really stands out (negatively!) in that respect...

dww’s picture

+1 from me, too. This is not cruft. This is a frequent source of support effort on nearly every Drupal site (certainly all the ones I have personal experience with). Almost all sites on the net are smart enough to diagnose this problem and warn you when you can't log in because your browser is not accepting cookies. Drupal should, too. Quick visual inspection of patch #48 looks good to my eyes.

soxofaan’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
2.31 KB

Maybe I am missing something, but why is it needed to do a "setcookie('drupal_login_check', ..."?
If cookies are disabled, $_COOKIE will always be empty and if cookies are enabled, $_COOKIE will have at least one entry with the session name (except for first visit).
So in user_login_submit() if (count($_COOKIE) == 0) should be equivalent with the if (!isset($_COOKIE['drupal_login_check'])) from patch #48.
If so, there is no need to add "cruft" to session.inc and there is no "cruft" needed for deleting the 'drupal_login_check' cookie.

See attached patch. I tested it and it behaves the same as the patch from #48.
(But I could be wrong about the assumption that $_COOKIE will always be non-empty after first visit when cookies are enabled.)

salvis’s picture

Interesting thought, but can we be sure that the browser doesn't send any cookies at all, if they're currently turned off? Or could it be sending old cookies?

Maybe we do need the 'drupal_login_check' cookie, but with a very short lifetime? Or add a timestamp so that we can verify that we're getting a fresh cookie?

chx’s picture

Status: Needs review » Reviewed & tested by the community

I re-RTBC #48 -- I would never rely on an empty cookies array. In theory it's not even impossible that this check fails, ie. the browser holds the login checker cookie and not the session one... but it's imo much better than relying on an empty cookie array.

dww’s picture

I agree #48 is more reliable and therefore superior.

soxofaan’s picture

I would never rely on an empty cookies array. In theory it's not even impossible that this check fails, ie. the browser holds the login checker cookie and not the session one... but it's imo much better than relying on an empty cookie array.

Fair enough. But you can never trust a/every browser. You could even create a browser so that #48 would fail.
This issue is a usability issue, so we should solve it for most use cases/standard browsers, not all imaginable exotic corner cases. The point is to find the right balance between adding cruft and solving the issue for enough people/cases.
It would be nice to have some real life examples that would show that #55 is significantly inferior.
I just wanted to address the cruftiness concern of Dries.

soxofaan’s picture

On a slightly different note: why deleting the 'drupal_login_check' cookie in patch of #48?
Some modules might want to check if cookies are enabled. The CAPTCHA module (of which I'm co-maintainer) for example requires sessions (and by consequence cookies) to work properly. It would be nice if there would be a standard drupal way of detecting if cookies are enabled.
So why not renaming 'drupal_login_check' to 'has_cookie' (just like the 'has_js' cookie) and not deleting it.
Just thinking out loud.

salvis’s picture

@soxofaan: see #36...

(this problem may apply to the has_js cookie, too!)

Gábor Hojtsy’s picture

Version: 6.x-dev » 7.x-dev

Looks like last minute campaigning did not get Dries' favor, so moving to the 7.x queue, in the hopes that it will be getting in early in the cycle.

Gábor Hojtsy’s picture

Category: bug » task
salvis’s picture

Well, now that soxofaan has successfully kept this patch from getting into D6, maybe we can pick up the pieces and put #48 into D7?

Anonymous’s picture

+1 to make something like this a core feature.

Another way to look at this might be to stop the user from logging in if the person doesn't have cookies enabled before they actually login. Or just a standard text message on the login page stating that cookies must be enabled to login.

Edit: rewrote this post a bit.

Dries’s picture

Status: Reviewed & tested by the community » Needs work

* The patch does no longer apply.

* Is this something we can write a test for?

Dries’s picture

* The patch does no longer apply.

* Is this something we can write a test for?

chx’s picture

Status: Needs work » Needs review
FileSize
1.71 KB

Dries -- no, because you can not even get to test page if your install does not keep cookies and also the test path is server->server meanwhile the request path is browser->firewall->ISP proxy->whatever->server.

nedjo’s picture

I made a D5 module based on this patch, http://drupal.org/project/cookie_check

Users reported a bug, possibly limited to IE7:

drupal.org/node/242060

The bug may be due to some change I made in adapting the patch but we shd try to reproduce before applying this.

Status: Needs review » Needs work

The last submitted patch failed testing.

Frank Steiner’s picture

I shouldn't complain as I didn't do any work to solve this issue, but it's hard to understand why there has been a patch that solves this problem for almost a year and it still hasn't been added. I often have user coming to me and complaining that login doesn't work and it's always because they haven't enabled cookies for this site.

Sometimes it seems a bit strange how difficult it is and how long it takes to get such basic things to be added to drupal. Every other CMS we use at the university does have this cookie warning feature...

catch’s picture

@Frank, the patch was posted in May. Count the number of people who've tested it since then, there's your answer. If you tested it, and it worked, why didn't you post back here to say so?

Frank Steiner’s picture

I can only apply it to 6.x and I learned that almost no one cares about this because everything is patched in HEAD and maybe backported afterwards, maybe not.

It works fine in 6.x for my site, but I don't see how this helps :-(

> the patch was posted in May

That's not really true. The patch is from January, but it has been ignored until it didn't apply anymore, see #66. Then chx made the new version which just differs in the context lines, not in the patch code itself. And then this has again been ignored until it didn't apply anymore. And now it looks like chx is not interested in making another version of the patch (which might again be ignored for months?).

According to http://testing.drupal.org/pifr/file/1/user-no-cookies-2946-67.patch it was received for testing on November 8th. So I wonder what happened between May and November. It seems likely that a patch written in May for HEAD doesn't apply in November anymore.
Same for 6.x, but it was again just adjusting the context lines. If I had 7.x I would try to correct the patch, but I've no idea (yet?) how this testing stuff works and what must be done to make a patch get into this testing.

So, I don't know what I can do more to say "Works great in 6.x". But you're right, I could have said that earlier!

nedjo’s picture

Status: Needs work » Needs review

Here is an updated and reworked patch.

Changes:

* Move the cookie checking to a validation handler, alongside the three existing user login validation handlers.
* Set a form error rather than forwarding to a separate page.
* Default to $_SERVER['HTTP_HOST'] if ini_get('session.cookie_domain') is empty.

These changes:

* Address changes in HEAD that made the previous approach no longer work.
* Increase flexibility--sites can alter or remove this validation.
* Avoid creating a new menu item.
* Prevent the potential confusion of users being at or returning to a page with a message saying their browser doesn't support cookies after they have enabled cookie acceptance from the domain.
* May increase usability by returning users to the login form they used.

nedjo’s picture

chx noted in #7 that messaging is potentially problematic in that, without cookies, data don't persist in the session.

In this case we remain on the same page and so messages set in the $_SESSION variable remain available for rendering; the form_set_error() call works.

This would break if e.g. a contrib module set a validation handler that called drupal_goto(). I think we can live with that though. Handling this as validation feels the cleanest.

nedjo’s picture

FileSize
2.23 KB

With patch...

Status: Needs review » Needs work

The last submitted patch failed testing.

nedjo’s picture

Status: Needs work » Needs review

I ran tests locally and didn't get the reported error. Setting back to 'code needs review'.

Owen Barton’s picture

Status: Needs review » Needs work

Patch applies and generally looks good. A couple of notes:

We may want to consider the help text "It seems your browser does not accept cookies." seems like slightly odd phrasing perhaps. Also, I wonder if it would be good to link to some generic "what the heck are cookies" page (e.g. on wikipedia?).

 /**
 * A FAPI validate handler. Sets an error if cookies are not supported.
 */

This looks a little nonstandard also - the function below it (which is equivalent) starts as "A validate handler on the login form....".

salvis’s picture

Status: Needs work » Needs review

People who don't know what cookies are, are unlikely to have this problem. And if they do, then this is not the first site where they encounter the problem, and they need to get help anyway. It's quite likely the first site that fails to provide any indication about the nature of the problem though... 8-(

What we desperately need is a terse message that tells those who know, what the problem is, so they can immediately start work on fixing it rather than having to search for why login attempts might be ignored.

There can be many other reasons besides the browser, so the messages must not be more specific than it can rightfully be.

Please propose improved wording for the comments.

Frank Steiner’s picture

I think it's more important to have any hint on what's going wrong than just beeing unable to login. There are pages explaining how to activate cookies, but they usually miss my browser anyway or are for Netscape 6.x or sth.

Status: Needs review » Needs work

The last submitted patch failed testing.

beginner’s picture

Priority: Normal » Critical

This affects the installer as well. Some people have cookies turned off by default, but have a whitelist of web sites where it's accepted.
When installing a new site, the new domain may not yet be in the whitelist.
In such conditions, it is impossible to install Drupal at all, but the the warning given make it sounds like it's a sql issue, which is very confusing and does not help finding the solution.

The following critical installation issues are caused by the absence of cookie:
#234539: Critical SQL error in installer with {menu_router}
#261148: menu_masks variable is empty (race condition)
#280015: cannot install drupal - menu_router error

richard.e.morton’s picture

I agree, this is a bug from the users point of view (the only view that counts).
Cookies being disabled/not-supported should be gracefully handled. a fix should also (ideally) be backported to 5 and 6 also.

subscribing.

robeano’s picture

robeano’s picture

Status: Needs work » Needs review

Fixed domain name display from nedjo's patch in comment #76

beginner’s picture

As an example of how absence of cookies are handled elsewhere, turn off cookies and visit this web site:
http://www.expedia.com/
Can't miss the (scary) warning!

beginner’s picture

Another example:
A simple warning is given here (again, visit with cookies turned off).
http://www.autism-society.org/site/PageServer?pagename=asa_home

xmacinfo’s picture

Status: Needs review » Reviewed & tested by the community

I think it's time to get the fix for this 2003 request rolling.

I've block cookies, log out of the fresh Drupal 7 head install and applied the patch. As soon as I try to log in, I get the proper warning "It seems your browser does not accept cookies. To log into this site, you need to accept cookies from the domain example.com".

Are there some issues which would prevent this patch from being committed?

chx’s picture

Holy Batman, my patch is not in yet????

xmacinfo’s picture

Batman is not holy. :-)

I guess we should grab webchick today for the code sprint. I've have not seen her yet this morning.

nedjo’s picture

Since this patch is limited to responding to attempted logins using login forms, it doesn't yet address two other needs:

1. We need to issue a warning at install time what cookies are required. (User does not log in using the login form.)

2. There are other cases where cookies may be required although users are not logging in. E.g., functionality that uses cookies to track anonymous users.

Still, it's probably a good first step. It handles the most pressing issue in Drupal core and could later be extended or modified to address these other needs.

xmacinfo’s picture

I think it would be best for you to create two new issues for:

  1. We need to issue a warning at install time what cookies are required. (User does not log in using the login form.)
  2. There are other cases where cookies may be required although users are not logging in. E.g., functionality that uses cookies to track anonymous users.

:-)

alexanderpas’s picture

We need to issue a warning at install time what cookies are required

hook_requirements() of the user module?

There are other cases where cookies may be required although users are not logging in. E.g., functionality that uses cookies to track anonymous users.

new hook?

webchick’s picture

Status: Reviewed & tested by the community » Needs work

We need tests for this. I check with cwgordon7 and he said it should be possible to override curlConnect() in your test case.

alexanderpas’s picture

@webchick

any updates weither this is testable or not?

webchick’s picture

I relayed what I was told. There's a testing sprint going on this weekend, so plenty of people to ask in #drupal. :)

xmacinfo’s picture

Can we just commit and add the test later?

Most of the experienced core commiters have already worked on this issue without raising the test issue.

Weka’s picture

++ 1 Bug Report
++ 1 Usability Issue
++ 1 Expand this issue to cover other forms in addition to user_login

Any functionality that requires the presence of a cookie should alert the user if the cookie is absent.

Many thanks to chx and nedjo for addressing this issue and contributing to a solution.

As nedjo correctly pointed out in #92

2. There are other cases where cookies may be required although users are not logging in. E.g., functionality that uses cookies to track anonymous users.

The issue #502816: Anonymous users do not see status messages is one of those examples.

I was very surprised reading Dries comments on this issue.

salvis’s picture

No, don't expand, commit!

As chx explained in #68, SimpleTest is close to useless for this. We'd test the behavior with one "browser" (that doesn't even exist in the real world) in an extremely unrealistic environment. The real world is much more complex and we won't know whether it works out in the wild until we let it loose.

Do we really want Drupal 7 (!) to become known as the one CMS/Framework that still, in 2010, doesn't even make an attempt at detecting this obvious stumbling block? What a cool way to fingerprint Drupal sites! :-(

If this had been committed in spring we'd have half a year's worth of almost-real-world testing by now. But we're still dabbling — it's pathetic...

xmacinfo’s picture

Status: Needs work » Reviewed & tested by the community

robeano patch in #86 still applies. I'm requesting a re-test of his patch.

As per other comments I'm putting this back to RTBC. :-)

Status: Reviewed & tested by the community » Needs review

xmacinfo requested that failed test be re-tested.

xmacinfo’s picture

Status: Needs review » Needs work

The patch fails. Needs a reroll.

1 out of 3 hunks FAILED -- saving rejects to file modules/user/user.module.rej.
[23:31:46] Encountered error on [apply], details:
array (
  '@filename' => 'cookie-validation-2946.patch',
)
bleen’s picture

Status: Needs work » Needs review
FileSize
2.63 KB

Here is a straight reroll of the patch in #85

I saw the node id of this issue and was sure I was misreading. I'm amazed this hasn't been addressed since Dries reported it in 2003

sun’s picture

+++ modules/user/user.module	10 Dec 2009 04:38:39 -0000
@@ -1770,17 +1770,18 @@ function user_login($form, &$form_state)
+  return array('user_login_name_validate', 'user_login_cookie_validate', 'user_login_authenticate_validate', 'user_login_final_validate');

Shouldn't the cookie validator run first, so the potential error message appears first?

+++ modules/user/user.module	10 Dec 2009 04:38:39 -0000
@@ -1794,6 +1795,16 @@ function user_login_name_validate($form,
+ * A FAPI validate handler. Sets an error if cookies are not supported.

"Form validation handler to ..."

+++ modules/user/user.module	10 Dec 2009 04:38:39 -0000
@@ -1794,6 +1795,16 @@ function user_login_name_validate($form,
+  if (!$_COOKIE) {
+    $domain = ini_get('session.cookie_domain') ? ltrim(ini_get('session.cookie_domain'), '.') : $_SERVER['HTTP_HOST'];

These two lines need an inline code comment (each), explaining what is being done here.

+++ modules/user/user.module	10 Dec 2009 04:38:39 -0000
@@ -1920,6 +1931,7 @@ function user_authenticate($name, $passw
+  

@@ -1944,6 +1956,7 @@ function user_login_finalize(&$edit = ar
+  

Trailing white-space.

Lastly, we need a test for this functionality.

This review is powered by Dreditor.

Status: Needs review » Needs work

The last submitted patch failed testing.

mcrittenden’s picture

Sub.

coderintherye’s picture

Status: Needs work » Needs review

#104: cookie_validate_2946_reroll.patch queued for re-testing.

Kind of just hoping that the requested test is now there. If not maybe I can work on writing one.

Status: Needs review » Needs work

The last submitted patch, cookie_validate_2946_reroll.patch, failed testing.

Frank Steiner’s picture

This is really getting nasty. It's an obvious issue which is seven years old. The patch is few lines of code which everyone can read and understand, but it's been delayed for 2 1/2 years, and now it's blocked again because it needs a simpletest.

I wonder why every other website I know is able to issue a warning when trying to login without cookies, but drupal makes this a huge, unsolvable problem.

JamesK’s picture

Does anyone have any examples of Simpletests that check/manipulate the HTTP headers? I'm not really sure where to start with coding this without an example test to base it off of.

Basically we need to test two "browser"s:
- one that ignores any Set-Cookie response header (ignoring Set-Cookie means that a Cookie header is not added to subsequent requests), and
- one that handles Set-Cookie headers normally (Cookie header is added to requests)

coderintherye’s picture

Well, drupal_http_request will handle getting/setting the headers for us, I know there are a few tests out there using it. I have one maybe could put up this weekend, but thinking how about we make this something to work on at the core code sprint next week? I'll be there, so I'll be pushing for this issue.

c960657’s picture

You cannot assume that just because $_COOKIE is empty, the browser does not accept cookies. Since #201122: Drupal should support disabling anonymous sessions was fixed in January 2009, we no longer create sessions for anonymous users. If JavaScript is not enabled, the has_js cookie is not set. If JavaScript is disabled in your browser, you cannot log in with this patch.

If $_COOKIE is non-empty, then the browser supports cookies, at least partially. I don't know whether any browser has "partial" support for cookies. I would think (but it's just a guess) that if $_COOKIE is non-empty, we can assume that it will accept our cookie. Comments #57-59 discuss this, but without any clear conclusion AFAICT.

In any case, we need to set a cookie in one request a verify its existance in the next request. Setting a cookie from PHP to all anonymous visitors seems like a bad idea, because a Set-Cookie header is usually a sign that the page should not be cached (e.g. by default (and design) Varnish does not cache pages with a Set-Cookie header).

One possibility is to make the login form return to an interim page that just checks for the existance of the session cookie and then redirects to the final destination. This will add an extra request to all logins. The redirect happens automatically, so the additional request will be invisible to the user (except for a small delay).

If we conclude that a non-empty $_COOKIE is a safe sign that the session cookie will be accepted and the form submission contains a non-empty $_COOKIE (usually containing just the has_js cookie), we can skip the extra round-trip and just redirect to the final destination immediately. This would make the login as fast as today for users with JavaScript enabled, while other with JavaScript disabled would need the extra round-trip.

For inspiration on how to write tests for this, you may want to take a look at modules/simpletest/tests/session.test. To emulate a browser without cookie support you should probably tell cURL to not follow redirects using CURLOPT_FOLLOWLOCATION and then instead follow the redirects “manually” and reset the session cookie between each request.

Owen Barton’s picture

Component: base system » ajax system
Status: Needs work » Needs review
FileSize
1.69 KB

I confirmed that the previous approach does not work with the new lazy session creation.

Here is an alternate approach that avoids adding a redirect simply to detect a cookie. What we do is add a querystring parameter to the destination page the user would end up on. We then check for this parameter and, if the user is not actually logged in, then we know they don't have cookies enabled. We might want to change the user flow a little. For example it may be nicer to do a set_message and redirect to "user", because right now if you log in on /user without cookies you end up on user/123 with the cookies message, but it is an access denied page. This would certainly need a simpletest to check the various combinations of /user vs. block, and with page caching enabled/disabled. First though - what do people think about this approach in general?

Owen Barton’s picture

Component: ajax system » base system
Issue tags: +cookie

Status: Needs review » Needs work

The last submitted patch, cookie_validate_2946_114.patch, failed testing.

Owen Barton’s picture

Status: Needs work » Needs review

Still looking for review on the general approach

catch’s picture

I think we should consider doing the redirect here. #547570: Login via user login block renders page twice points out that this happens anyway from the login block, and that the redirect is quite expensive - so it adds a dedicated redirect callback to save page rendering. If we used that same redirect callback for user/login then the additional bootstrap would be very cheap, and this would presumably allow us to redirect somewhere useful on failure too.

amc’s picture

subscribing

Owen Barton’s picture

@catch - my patch does not actually use (or need) any redirect. I think either approach should work fine - but I am not sure which I prefer...what do you think?

catch’s picture

Even though the user_init() is just an isset(), I'd be happier with a check just during the process of logging in rather than having that code in the critical path.

Also if we're going to do a redirect from the login block anyway, and have a nice handy callback which controls that, then putting the cookie checking code in there is fairly tidy. The question then is whether the isset() in user_init() and very small bit of code weight there is better or worse than an extra bootstrap (but no page render) on logging in via the form. I'm not sure either way on that but lean slightly towards the log in form.

Owen Barton’s picture

Actually, now that I think about it, I am not sure #547570: Login via user login block renders page twice really changes anything that helps us here. The basic workflow is the same as it is now (just we hit a lightweight page, rather than a content page). Specifically in the following, it just changes pageload 2 from building an entire node/123 page, to a simple page - however it is still a single redirect, and we actually need 2 redirects.

Load 1: /node/123 - we can't add a cookie here (without breaking caching) because we don't know if the user will actually use the login block, or just click away

Load 2: user submits login form - we process the login then redirect them on to their destination - we can add a cookie here (and we do already, in fact)

Load 3: user back at node/123 - we can check for a cookie here, but this is basically the same as the patch I have already

If we are going to drop the hook_init isset, then we need to add another redirect either before or after load 2, that has the single purpose of setting or detecting cookies. Given this, I think my approach, or some variant of it is preferable to having 2 redirects on login.

catch’s picture

Status: Needs review » Needs work

I don't like either the double redirect option, or the runtime check on every page here, but neither do I have any better ideas - would be good to get some feedback from others. However some of the information in this issue needs to be added to user_init() in a comment if we go for this option.

c960657’s picture

Status: Needs work » Needs review

This is somewhat along what I proposed earlier, but not completely:

Do you think that we can assume that the browser uses the same logic for determining whether to accept or reject a cookie when set using a HTTP header and from JavaScript, assuming that the cookie is set using the same parameters except for the name? In that case we can set a cookie using JavaScript in the onsubmit handler for the login form. The cookie should have the same path+domain+lifetime as the login cookie. When the login form is submitted, we do the extra redirect as already suggested, but only if the cookie set in JS is not present. This allows most users to login without an extra redirect.

MichaelCole’s picture

Status: Needs review » Needs work

The tests are failing, so the patch still needs some work...

David_Rothstein’s picture

Some of the comments above referred to this being an issue with the installer as well, which is still true. It was reported recently here, and is still an issue in Drupal 7:

#791004: Installer does not warn the user that cookies must be enabled with the correct cookie domain (and fails when they aren't)

Since the installer is something of a separate problem (which the latest patch here doesn't address), it's probably best to keep two separate issues for this, so I am leaving that one open but just cross-linking it here.

webchick’s picture

Sorry. Issues that have been in Drupal since 2003 don't get to hold "critical" status.

webchick’s picture

Priority: Critical » Normal
Frank Steiner’s picture

Ignoring the problem for 7 years doesn't make it less critical. Getting rejected to login without any notice why it happens is a critical usability issue.

salvis’s picture

Shhh, we're aiming for a world record here...

CZ’s picture

Subscribe.

EvanDonovan’s picture

Subscribing. Is #114 going to work with lazy session creation, or should we try for #124?

Yar1984’s picture

Status: Needs work » Needs review
Issue tags: -cookie

#114: cookie_validate_2946_114.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +cookie

The last submitted patch, cookie_validate_2946_114.patch, failed testing.

kgeographer’s picture

re: cookies and usability
The most recent 6.17 patch update rendered existing Firefox cookies useless. The result is that no recent visitor to my site can log in without first clearing cookies. Unfortunately, they have no way of knowing that. Truthfully, how many would think to do it given no prompt or message to that effect? Attempts to change password fail when following the emailed link. And what is the pain-in-the-a$$ cost for clearing all one's other, perfectly good cookies?

Nice software, generally, though!! Thanks to its authors :^)

salvis’s picture

@satchinsb: Please don't hijack this issue — create a new one against 6.17.

klonos’s picture

subscribing...

DanChadwick’s picture

Re: 114, I implemented this technique in a module for my own (not generalized) situation. The only minor issue I found is that if the user logs off and uses the browser's history or back button to return to the page containing the "state=loggedin" query, then the cookie warning message is displayed when it shouldn't be. It would be possible to reword the message to allow for this possibility, absent a better solution.

In reading through the 130+ messages, there seems to be a lack of agreement on the urgency which is hard to explain. Perhaps it is relatively uncommon for Drupal sites to be used by authenticated non-technical users -- the type likely to be frustrated by this. My site has exactly this type of user. I would very much like to see this fixed in D7 and backported to D6. Even if the fix is not absolute perfection, could we get something into core and keep open another issue for research for the next 7 years? ;-)

Please. It's time to plug a serious usability bug for those unlucky enough -- or unskilled enough -- to fall into it ... and for the site owners who then suffer. D7 emphasizes usability after all, no?

dpatte’s picture

subscribe

Owen Barton’s picture

Version: 7.x-dev » 8.x-dev
amc’s picture

Status: Needs work » Needs review
Issue tags: -cookie

#114: cookie_validate_2946_114.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +cookie

The last submitted patch, cookie_validate_2946_114.patch, failed testing.

dww’s picture

Priority: Normal » Major

Issues like this make we want to stop trying to contribute to Drupal core at all... ;)

- This is at least a major UX bug/WTF. We seem to be totally schizophrenic when it comes to our UI/UX priorities. Half-baked UX solutions are rushed into core under the banner of "UX trumps all" while critical UX bugs like this that actually affect 1000s (millions?) of Drupal users are postponed and punted to low priority. Either creating a "delightful experience" is important or not. If so, we can't downgrade obvious bugs like this to "normal task" just because so many people got burned out trying to get this in and faced various roadblocks.

- I think I'm with catch and I'm leaning towards the double redirect solution. Although it does delay login slightly (in an automated way), a) logging in is a very infrequent operation even on sites that allow authenticated users and b) not all sites even have real authenticated traffic. So, I'd hate to slow down the critical path of user_init() with this check on every page load for every site, just to handle a relatively infrequent thing. Also, it's extremely common on the existing web that when you click the "login" button, you wait a few seconds for at least a few redirects, if not more. It's not like users are going to be shocked or angry if logging in seems complicated and/or slow. And, if the first redirect sends you to a relatively cheap page that just ensures your cookie worked and either prints you the warning message or sends you off to where you wanted to go, it's not going to really be that slow.

Cheers,
-Derek

p.s. Please stop requesting #114 for retesting. The patch will never apply now that #22336: Move all core Drupal files under a /core folder to improve usability and upgrades is done. If we're going that route, we need a re-roll.

coderintherye’s picture

So do we need a completely new patch or do we want to wait for #547570 to land?

As for the concerns about a redirect for authenticated users, as someone who has run a few sites that allow *only* authenticated users, I can say that we had to write our own cookie checks anyways since obviously we wanted those users with cookies disabled to know why they were not able to login. I'd imagine this is pretty true across most sites that require authenticated logins (especially government ones trying to meet 508 guidelines).

So, +1 to the double-redirect, the performance hit should be worth the trade-off.

Owen Barton’s picture

Looking through the session code, it seems that as long as $_SESSION is left empty we should still be able to set other cookies without breaking caching (even reverse proxies with vary-cookie should be OK). If we did this wherever the user form is displayed it seems this might be the most simple option (compared to wiring in an additional redirect). The only downside I can think of is the extra few bytes per-page for all users. We could reduce the latter by using a short cookie name/value. We could even set "has_js" to 0 in php (if it is not yet set), although I think that is more complex since we need to consider the JS interaction.

Note that if we go the double redirect option, it is actually the second redirect (rather than the first) that checks for a cookie. The first redirect would process the login, then redirect to a second page that would check for cookies and direct the user on to their final destination or set a message and send them back (to their original URL, ideally, although we might need to figure in some "origin" querystring parameter for that, I think, since we are no longer in the form processing cycle). Here is the page flow for the double-redirect option.

- Load 1: /node/123 - we can't add a cookie here (without breaking caching) because we don't know if the user will actually use the login block, or just click away
- Load 2: user submits login form - we process the login then redirect them on to a cookie check page - we can add a cookie here (and the login process does already, of course)
- Load 3: user goes to /user/checkcookie?destination=user&origin=node/123, checks for the session cookie and redirects as needed.
- Load 4: user back at node/123 if no cookie, or at user if cookies enabled

Of the 2, I think my preference is for adding a small cookie with login forms, but this is primarily because it feels simpler, rather than performance.

ZenDoodles’s picture

xmacinfo’s picture

#791004: Installer does not warn the user that cookies must be enabled with the correct cookie domain (and fails when they aren't) is not a duplicate. It deals only with the installer.

We need a warning to regular user (on an already installed Drupal site) that they need to enable cookies to be able to log in on the site.

Right now nothing is displayed if cookies and not enabled and the user have not clues as to why.

xmacinfo’s picture

Issue tags: +Needs tests

Adding Needs tests tag.

xmacinfo’s picture

Issue summary: View changes

Added more information in the issue summary.

Kazanir’s picture

I am posting here to echo the others -- how unbelievable is it that Drupal, one of the (allegedly) most mature and complete CMS solutions available, doesn't have a fix for such an obvious, disturbing (and ancient!) UX issue?

xmacinfo’s picture

@Kazanir: It means that no one was able to write the test required for this patch.

DanChadwick’s picture

@xmacinfo - Since this bug is 10 years old and is -- I think we all agree -- quite a serious UX issue, I would propose that we remove the Needs tests flag and re-roll 114 for testing by the community. If it turns out in the future that a better solution than 114 exists, it can always be proposed in new issue.

znurgl’s picture

Status: Needs work » Needs review

#7: no-cookie.patch queued for re-testing.

nedjo’s picture

Given that this is a common need that's been addressed in many other PHP applications but not in Drupal, we'd do well to look around. What have Joomla and Wordpress done? Anyone who's following this issue able to take on that research and report back?

dww’s picture

nedjo raises a good point. Another place to look would be Symfony. ;) Isn't solving stuff like this "for free" part of the promise of having imported so much Symfony code into Drupal core?

salvis’s picture

If the missing tests are the problem, then looking around in other projects won't help at all. Technically this is solved, it's a people problem.

Looking in Symfony is certainly a good idea for D8, but it should go into a new issue IMO, because it won't work for D7. This issue here has the code to fix the problem in D7. We could have committed this years ago -- gasp, without tests -- and have it well-tested in the field by now.

I know what our standard procedures are, but in the tenth (!) year of this embarrassing issue, it's pretty obvious that our standard procedures are a hindrance in this case rather than a help. I've come to the conclusion that we lack the will to fix this. Looking around in other projects is just another way to derail this even further. (Not picking on you, nedjo, I know you've worked to bring this forward in the past.)

salvis’s picture

Issue summary: View changes

Clarified that the patch is too old.

nedjo’s picture

Title: no warning is issued if cookies are not enabled » Login fails and no warning is issued if cookies are not enabled
Category: task » bug

Recategorizing as a bug, since login is broken without cookies. The priority reflects the fact that the bug presents significant usability issues.

D8 maintainer catch has been responsive in this issue and there's every reason to believe we could get this in for D8, but the patch is not yet ready. I've had a stab at updating the summary with remaining tasks.

David_Rothstein’s picture

I took a quick look at Wordpress, and it seems to me they do something similar to Owen Barton's first suggestion in #145 (set a cookie when the form is displayed and check it when the form is submitted).

However:

Looking through the session code, it seems that as long as $_SESSION is left empty we should still be able to set other cookies without breaking caching (even reverse proxies with vary-cookie should be OK).

Don't a lot of Varnish configurations strip cookies they don't recognize, and bypass caching entirely if there are any cookies left over? I'm looking, for example, at http://www.lullabot.com/articles/varnish-multiple-web-servers-drupal :

  # Remove all cookies that Drupal doesn't need to know about. ANY remaining
  # cookie will cause the request to pass-through to Apache.
...
  set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]+|NO_CACHE)=", "; \1=");

If I understand that correctly, that means people would need to change their Varnish configurations for this approach to work at all, and if they do, suddenly a whole bunch of pages won't be cached anymore. (On the other hand, one could make the argument that if a site wants this behavior, that's something they'll have to live with.)

In terms of Drupal 7 backport, a new cookie would also break things for people using a "blacklist" approach to cookies in Varnish (rather than a whitelist approach) although I suppose those people should already be getting used to things breaking anyway...

David_Rothstein’s picture

In any case, here is a test. This was kind of a pain to figure out how to write.

It includes a rerolled version of #114; this should at least serve the purpose of verifying that the test behaves as expected.

Status: Needs review » Needs work

The last submitted patch, cookie-validate-2946-158.patch, failed testing.

David_Rothstein’s picture

Those two failures look like they're specific to the solution here (probably code that expects a specific URL after logging in and therefore gets confused by the new ?state=loggedin). So not worth fixing unless this is the actual solution we're going with.

David_Rothstein’s picture

Issue summary: View changes

Add issue summary.

nedjo’s picture

@David_Rothstein: thanks, it's great to have a test in place!

I've updated the summary with details from the Wordpress approach.

In general I lean towards the cookie setting and checking approach. It has the advantage of being outside the critical path, it's explicit (testing to see if we have a logged in user feels hackish), it could be used elsewhere, e.g., at install time, and as Owen suggested it feels simpler than a double redirect.

But, yes, interference with Varnish or other cache solutions is an issue. Currently we set various cookies only in response to user actions (form submissions, logins, etc.), see http://api.drupal.org/api/drupal/modules!user!user.module/function/calls.... But a login form is often presented on all pages of a site.

Looking again to Wordpress, some sys admins explicity skip the wordpress_test_cookie in Varnish config, see http://kaanon.com/blog/work/making-wordpress-shine-varnish-caching-syste.... Presumably we'd see the same with Drupal, meaning that this fix would be missing from Varnish-served sites.

pplantinga’s picture

Status: Needs work » Needs review
FileSize
5.04 KB

Re-roll. I support this approach.

nedjo’s picture

Status: Needs review » Needs work

Thanks for rerolling. hook_init() is gone, https://drupal.org/node/2013014, so the patch would need to use a different approach.

pplantinga’s picture

Status: Needs work » Needs review
FileSize
6.76 KB

Fair enough.

How's this for proof-of-concept? I kind of hijacked the MaintenenceModeSubscriber, so we'd probably have to move the code to its own Subscriber or rename that subscriber, but at least it seems to fix the issue for me. Test might need to be tweaked though.

Status: Needs review » Needs work

The last submitted patch, cookie-validate-2946-164.patch, failed testing.

pplantinga’s picture

Status: Needs work » Needs review
xmacinfo’s picture

Status: Needs review » Needs work

Cannot be reviewed until the patch is rerolled.

pplantinga’s picture

I set it to needs review because I needed input about whether the method was a valid one. It gives the correct result in manual testing (though the test needs to be tweaked, which I couldn't figure out either).

pplantinga’s picture

Issue summary: View changes

Update summary with test info and example from Wordpress.

jessebeach’s picture

Priority: Major » Normal

After 11 years of surviving with the bug in place, I think we can safely downgrade this to Normal.

jessebeach’s picture

Priority: Normal » Major

I was convinced in chat to put this back to Major.

effulgentsia’s picture

For context, the reasoning I gave for this being Major is similar to #143. https://drupal.org/node/45111 defines major bugs as ones that have significant repercussions as opposed to normal bugs that are isolated to one piece of functionality. Since the inability to log in affects the use of the entire software, that makes this major by that definition. However, it's not critical, since it affects a tiny percentage of users and has a workaround (enable cookies).

jhedstrom’s picture

Issue tags: -Needs tests

The patch here has tests, removing tag.

jcnventura’s picture

jcnventura’s picture

Status: Needs work » Needs review

Test bots are go!

Status: Needs review » Needs work

The last submitted patch, 173: cookie-validate-2946-mine.patch, failed testing.

The last submitted patch, 173: cookie-validate-2946-mine.patch, failed testing.

jcnventura’s picture

Status: Needs work » Needs review
FileSize
5.52 KB

Status: Needs review » Needs work

The last submitted patch, 177: login_fails_and_no-2946-177.patch, failed testing.

The last submitted patch, 177: login_fails_and_no-2946-177.patch, failed testing.

The last submitted patch, 177: login_fails_and_no-2946-177.patch, failed testing.

iMiksu’s picture

Assigned: Unassigned » iMiksu

Taking a look on the failures.

iMiksu’s picture

Assigned: iMiksu » Unassigned
Status: Needs work » Needs review
FileSize
1.27 KB
6.79 KB

There are two methods (\Drupal\system\Tests\Session\SessionHttpsTest::loginHttp() and \Drupal\system\Tests\Session\SessionHttpsTest::loginHttps()) which needed some improvements to support recently added ?state=loggedin query suffix to the login process from comment #177.

I changed them by passing query parameters separately to \Drupal\simpletest\WebTestBase::drupalGet() call:

    // Follow the location header.
    $path = $this->getPathFromLocationHeader(TRUE);
    $parsed_path = parse_url($path);
    $query = array();
    if (isset($parsed_path['query'])) {
      parse_str($parsed_path['query'], $query);
    }
    $this->drupalGet($this->httpsUrl($parsed_path['path']), array('query' => $query));
catch’s picture

Version: 8.0.x-dev » 8.1.x-dev
Status: Needs review » Needs work

Since this adds new public functions and interface text, moving to 8.1.x.

Patch also needs updating for $GLOBALS['user'] removal.

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

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now 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.

anoopjohn’s picture

Removed global $user and rerolled the patch. Made some minor coder corrections as well.

Status: Needs review » Needs work

The last submitted patch, 185: login_fails_and_no-2946-185.patch, failed testing.

ifrik’s picture

Issue tags: +Usability
jcnventura’s picture

Sorry BigPipeTest.php, but you can't test for no redirects in a page where we actually redirect on purpose.

jcnventura’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 188: login_fails_and_no-2946-188.patch, failed testing.

ifrik’s picture

Looks like the test needs fixing then.

Wim Leers’s picture

Status: Needs work » Needs review
Issue tags: +Needs tests
FileSize
9.53 KB
2.23 KB

Sorry BigPipeTest.php, but you can't test for no redirects in a page where we actually redirect on purpose.

This analysis is not correct I'm afraid.

This patch is making changes that causes certain defaults/expectations to change. So, yes, BigPipeTest needs a very minor change: it needs to now expect that ?state=loggedin query argument. Fixed that.

(Also reverted the change in #188, that was the wrong change.)


But, more importantly, this patch uncovers a bug in the redirect.destination service. Because BigPipe calls this:

\Drupal::service('redirect.destination')->getAsArray()])->toString()

… but it returns /user/1, whereas it should return /user/1?state=loggedin.

Fortunately a simple fix! :)


This will also need to update \Drupal\Tests\Core\Routing\RedirectDestinationTest, because that unit test clearly is not yet testing this. Hence Needs tests.

Wim Leers’s picture

Status: Needs review » Needs work

And since I touched this patch now anyway, here's a review:

  1. +++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
    @@ -140,6 +140,24 @@ protected function getSiteMaintenanceMessage() {
    +    if (isset($_GET['state']) && $_GET['state'] == 'loggedin' && !$this->account->isAuthenticated()) {
    

    This should not use $_GET. It should use $event->getRequest()->query->get('state') === 'loggedin'.

  2. +++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
    @@ -140,6 +140,24 @@ protected function getSiteMaintenanceMessage() {
    +      $domain = ini_get('session.cookie_domain') ? ltrim(ini_get('session.cookie_domain'), '.') : $_SERVER['HTTP_HOST'];
    

    This should also use the Request object.

  3. +++ b/core/modules/user/src/Tests/UserBlocksTest.php
    @@ -73,7 +73,8 @@ function testUserLoginBlock() {
    +    $url = \Drupal::url('user.admin_permissions', [], ['absolute' => TRUE, 'query' => ['state' => 'loggedin']]);
    

    Should use Url::fromRoute().

The last submitted patch, 192: login_fails_and_no-2946-192.patch, failed testing.

Wim Leers’s picture

Failures in RedirectDestinationTest… so that was testing this stuff, but with the wrong expectations!

jcnventura’s picture

Status: Needs work » Needs review
FileSize
3.46 KB
10.19 KB

This patch addresses the problems identified by Wim in his review (#193).

It does not fix the failing tests, but I'm setting it to review to make sure I didn't break other tests.

Wim Leers’s picture

Status: Needs review » Needs work

#196's interdiff looks great! Next: fixing RedirectDestinationTest, and potentially adding missing test coverage there :)

The last submitted patch, 196: login_fails_and_no-2946-196.patch, failed testing.

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

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now 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.

xjm’s picture

Component: base system » user.module
Issue tags: +Triaged core major

@webchick, @catch, @Cottser, @effuglentsia, and I agreed that this is a major issue because it interferes with normal visitors' use of the site in a way they cannot troubleshoot without a meaningful error message.

We decided this is a bug in the User module, even if we make additions to lower subsystems to support the fix.

vijaycs85’s picture

Status: Needs work » Needs review
FileSize
10.1 KB
930 bytes

Fixing test fails...

deepakrmklm’s picture

Passing query parameters separately to \Drupal\simpletest\WebTestBase::drupalGet() call is fine.

Status: Needs review » Needs work

The last submitted patch, 202: login_fails-2946-202.patch, failed testing.

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

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now 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.

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

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now 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.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now 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.

ifrik’s picture

Status: Needs work » Needs review
xmacinfo’s picture

Status: Needs review » Needs work

Please leave at Needs work, as any patch existing in this issue needs an update or a reroll.

ifrik’s picture

Sorry, I hadn't actually meant to change this issue at all.

Gogowitsch’s picture

Status: Needs work » Needs review
FileSize
7.13 KB

I can confirm this works.

I've updated the patch from #202 so it applies cleanly to the 8.6.x-dev branch.

Status: Needs review » Needs work

The last submitted patch, 210: login_fails-2946-210.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

xmacinfo’s picture

In the past, this issue failed to be pushed to core because tests were missing.

@Gogowitsch were you able to run the tests too?

Gogowitsch’s picture

@xmacinfo unfortunately no. I kept fighting various issues and have given up after 8 hours. I keep getting many more than the 2 failed big_pipe tests. I've looked at the BigPipeTest.php, but cannot match the output to the 8.6.x-dev branch. I'm fine adding tests to the patch myself, but would need an environment first that lets me reproduce what drupal.org's CI sees.

Can you point me to the right resources? I'm currently using an old custom vagrant machine for running Drupal tests.

Frank Steiner’s picture

This issue hasn't been resolved for 15 years now? That's simply laughable. Really a deterrent example for everyone who's thinking about writing a patch for Drupal.

cilefen’s picture

Why is that comment making me sad? It is like some other comments on this issue. It is an anti-contribution. It is demotivating.

How about motivating instead? Organizations that are feeling pain from this issue for so long and want to get this done could do so in a number of ways:

  • Fix it and contribute the solution.
  • Host a focused sprint.
  • Sponsor developers—it is amazing what some funding can do.

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

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now 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.

wengerk’s picture

Here is the reroll of #210 with the Drupal\Tests\big_pipe\Functional\BigPipeTest::testNoJsDetection() fix.

What can we do to go forward with this issue ?

I also remove the whole user_login_form_submit as all the code was already done by \Drupal\user\Form\UserLoginForm::submitForm(), am I wrong ? What was the purpose of this hook, the comment wasn't very usefull of Why it was here ^^ ? By removing it no tests fails, so what was the real purpose of this hook, something uncovered ?

/**
+ * Submit handler for the login form.
+ *
+ * Load current_user and perform standard login tasks. The user is then
+ * redirected to the My Account page. Setting the destination in the query
+ * string overrides the redirect.
+ */
+function user_login_form_submit($form, &$form_state) {
+  $account = User::load($form_state['uid']);
+  $form_state['redirect'] = ['user/' . $account->id(), ['query' => ['state' => 'loggedin']]];
+  user_login_finalize($account);
+}
xmacinfo’s picture

Status: Needs work » Needs review

As per previous patch by @wengerk.

xmacinfo’s picture

The tests are passing. Congratulations!

The next step is to find someone to review the code (and possibly test your patch against 8.7.x-dev on their computer).

@wengerk : we generally need only one user to validate the patch and change the issue to RTBC. I am not setup yet to do this.

tstoeckler’s picture

nedjo’s picture

@wengerk

Thanks for the new patch.

What can we do to go forward with this issue ?

Another step could be to update the issue summary (and then remove the "Needs issue summary update" tag). Relevant documentation is here.

wengerk’s picture

Status: Needs review » Needs work

Thanks for your help @xmacinfo & @nedjo !

I was more wondering about a code review & code approach. Here are some suggestions of code that could be changed :

  1. Drupal\Core\EventSubscriber\MaintenanceModeSubscriber::checkUserCookies should be moved to a better appropriate ServiceSubscriber such as: Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber. For now, the checkUserCookies has nothing in relation with the MaintenanceMode.
  2. The @see user_login_form_submit(). should be @see \Drupal\user\Form\UserLoginForm::submitForm()
  3. The access of Global $_GET should be avoided. We should use the Symfony Request Object. So this implementation $_GET['state'] should be $event->getRequest()->query->get('state');.
  4. The access of Global $_SERVER should be avoided. We should use the Symfony Request Object. So this implementation $_SERVER['HTTP_HOST'] should be $event->getRequest()->server->get('HTTP_HOST');.
  5. The $events[KernelEvents::REQUEST][] = ['checkUserCookies']; should follow the naming convention & be renamed as onRequestlCheckUserCookies or onKernelCheckUserCookies
  6. Simplify the readability by using $this->account->isAnonymous() instead of !$this->account->isAuthenticated().
  7. \Drupal::url should be Url::fromRoute().
  8. Improve the altered test assertion to be more readable:
    -    $this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . base_path() . 'user/1" />' . "\n" . '</noscript>');
    +    $this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . base_path() . 'user/1%3Fstate%3Dloggedin" />' . "\n" . '</noscript>');
    

    We should not use %3Fstate%3Dloggedin but &state=loggedin. We need to alter the tests a little bit with UrlHelper::encodePath to make it readable.

What do you think ?

PS: Oppsy I didn't see the message #193 of Wim Leers where he already spotted some of those changes ! So I think we should change them before requesting a review.

xmacinfo’s picture

@wengerk Of course, you can apply all the enhancements you and Wim Leers spotted.

Your changes, along with the explanations you provided will make it easier to review the patch and increase the chance of the patch to be accepted by the core maintainer.

wengerk’s picture

Status: Needs work » Needs review
FileSize
7.87 KB
3.95 KB

So after reading & making a diff of the latest patches from this issue, it seems something went wrong on #202.

The patch #201 was pretty good, but the patch #202 remove some improvement of #201 without nobody notices it. Then we rerolled the #202 instead of #201 and it snowball until my own patch on #217.

Here is a patch from #217 which include (I hope so) all the necessary changes from #201 & #222.

So here a list of changes we still have to work on it, some are suggestions & others are actions to do before merging:

  • Drupal\Core\EventSubscriber\MaintenanceModeSubscriber::checkUserCookies should be moved to a better appropriate ServiceSubscriber such as: Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber. For now, the checkUserCookies has nothing in relation with the MaintenanceMode.
  • Another step could be to update the issue summary (and then remove the "Needs issue summary update" tag). Relevant documentation is here.
  • Discuss about the comment of #217 of user_login_form_submit hook. What was the purpose should we keep it ?
wengerk’s picture

AaronBauman’s picture

Updated issue summary and rerolled to reflect #217 tasks.

Changes in this patch from #217:

  • Moved checkUserCookies to AnonymousUserResponseSubscriber, per #217
  • @@ -22,6 +24,7 @@
      */
     class UserLoginBlock extends BlockBase implements ContainerFactoryPluginInterface {
     
    +  use UrlGeneratorTrait;
       use RedirectDestinationTrait;
     
       /**

    UrlGeneratorTrait was not used. Removed.

To address some of the remaining tasks / outstanding questions:

  • user_login_form_submit appears to have been cruft, possibly something inadvertantly added from D7? We're good to remove it.
  • The tests UserBlocksTest, SessionHttpsTest.php, and BigPipeTest have been updated to reflect the changes in this patch.
    Does this need additional test coverage?
    If so, can someone suggest a testing strategy?
    If not, please remove the "Needs tests" tag, and this is ready for RTBC
  • To address #138 specifically, since i didn't see it addressed in the thread above:

    if the user logs off and uses the browser's history or back button to return to the page containing the "state=loggedin" query, then the cookie warning message is displayed when it shouldn't be. It would be possible to reword the message to allow for this possibility, absent a better solution.

    If the user doesn't have cookies enabled, they won't get logged in.
    If they use the back button it will still be relevant.
    If the user does enable cookies and successfully logs in, then uses the back button to go all the way back... seems like that's a pretty far edge case that we don't really need to worry about. Core doesn't use special handling anywhere else to deal with oddities that may arise from the back button, and I don't think we should start now.

Status: Needs review » Needs work

The last submitted patch, 226: 2946-226.patch, failed testing. View results

AaronBauman’s picture

xmacinfo’s picture

Issue tags: -Needs tests

As previous comment, removing the “needs tests” tag.

I am not setup to test this patch, so leaving the Status to “Needs review”.

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tatarbj’s picture

let's see how does the code behave on 8.8.x, retest is sent.

tatarbj’s picture

Rerolled patch on 8.8.x

tatarbj’s picture

FileSize
9.33 KB

fixing the coding standard issues from #232

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

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). 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.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now 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.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

larowlan’s picture

mxr576’s picture

Issue tags: +Needs reroll
wengerk’s picture

Here a rerolled patch for working on 9.1.x & 9.2.x.

During the reroll, I address the usage of deprecated Symfony\Component\HttpKernel\Event\GetResponseEvent to use Symfony\Component\HttpKernel\Event\ResponseEvent on Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber

This patch reroll does not apply to 8.9.x and 9.0.x, we need to create another specific patch if we want to merge on 8.9.x, 9.0.x, 9.1.x & 9.2.x.

Since it target 9.2.x-dev I did not create those reroll (8.9.x, 9.0.x).

PS: I was not able to create interdiff between 233 and 239. it crash with "Error applying patch1 to reconstructed file". Sorry people.

ifrik’s picture

Working on this during contrib day today.

michaellenahan’s picture

After applying #239 patch on 9.2.0-dev in a browser with cookies completely disabled, I get this error after login.

https://sprint-20201209-1650.ddev.site:8443/en/user/login

TypeError: Argument 1 passed to Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber::onKernelCheckUserCookies() must be an instance of Symfony\Component\HttpKernel\Event\ResponseEvent, instance of Symfony\Component\HttpKernel\Event\RequestEvent given in Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber->onKernelCheckUserCookies() (line 90 of core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php).

Here is the backtrace:

Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber->onKernelCheckUserCookies(Object, 'kernel.request', Object)
call_user_func(Array, Object, 'kernel.request', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.request') (Line: 134)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 2) (Line: 80)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 2, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 2, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 2, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 2, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 2, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 2, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 2, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 2) (Line: 166)
Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber->makeSubrequest(Object, '/system/403', 403) (Line: 112)
Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber->on403(Object) (Line: 109)
Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase->onException(Object, 'kernel.exception', Object)
call_user_func(Array, Object, 'kernel.exception', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.exception') (Line: 219)
Symfony\Component\HttpKernel\HttpKernel->handleThrowable(Object, Object, 1) (Line: 91)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 706)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

ifrik’s picture

Status: Needs review » Needs work

The same error also occurs _with_ cookies enabled, and for users who are already logged in.

ifrik’s picture

FileSize
5.25 KB

Interdiff

wizonesolutions’s picture

Issue tags: +Europe2020

I "mentored" @michaellenahan on fixing the error in this patch. Someone else will likely explain more, but the issue was that the reroll by @wengerk refactored GetResponseEvent to ResponseEvent, but the kernel actually passes a RequestEvent to KernelEvents::REQUEST listeners now. We were on screen share and saw the changes work after fixing that.

michaellenahan’s picture

Getting great mentoring from wizonesolutions, ifrik and jcnventura today at Drupalcon Europe.

I made the changes as suggested by wizonesolutions, see this interdiff:
https://www.drupal.org/files/issues/2020-12-11/interdiff_239-245.diff

New patch attached:
https://www.drupal.org/files/issues/2020-12-11/2946-245.patch

With the patch applied, I confirm that, with cookies disabled, when I log in, I get the error message as shown in this screenshot:
To log in to this site, your browser must accept cookies from the domain

michaellenahan’s picture

Status: Needs work » Needs review
ifrik’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
19.01 KB

The patch works. If a user doesn't have cookies enabled, then they see not only "Access denied" when they try to log in, but also a message that states that they need to enable cookies to login.

Screenshot:

To log in to this site, your browser must accept cookies from the domain
https://www.drupal.org/files/issues/2020-12-11/Screenshot.png

xmacinfo’s picture

Oh nice! That's an 18 year old bug! Thank you so much for all your work!

xmacinfo’s picture

Issue summary: View changes
Issue tags: -Needs reroll

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Thanks for working on this. Nice to see activity on such a low NID :)

  1. +++ b/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php
    @@ -65,6 +78,24 @@ public function onRespond(ResponseEvent $event) {
    +    if ($request->query->get('state') === 'loggedin' && $this->currentUser->isAnonymous()) {
    

    I think the name state is very very generic. It also implies that we're going to always track this state via the query which is not correct. I think adding a more indicative query string that is way less likely to clash with anything existing is a good idea. For example check_logged_in=1 would indicate more of what is going on than state.

    A cursory search of contrib shows this concern is real - http://codcontrib.hank.vps-private.net/search?text=query-%3Eget%28%27sta...

  2. +++ b/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php
    @@ -65,6 +78,24 @@ public function onRespond(ResponseEvent $event) {
    +      $domain = ini_get('session.cookie_domain') ? ltrim(ini_get('session.cookie_domain'), '.') : $request->server->get('HTTP_HOST');
    

    The $request->server->get('HTTP_HOST') can give the wrong answer. For example when you are using host forwarding. This should be $request->getHost()

  3. +++ b/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php
    @@ -65,6 +78,24 @@ public function onRespond(ResponseEvent $event) {
    +      $domain = ini_get('session.cookie_domain') ? ltrim(ini_get('session.cookie_domain'), '.') : $request->server->get('HTTP_HOST');
    +      $this->messenger->addMessage($this->t('To log in to this site, your browser must accept cookies from the domain %domain.', ['%domain' => $domain]), 'error');
    +    }
    

    This message is never tested. We can test by performing a request with the query string as the anonymous user.

  4. +++ b/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php
    @@ -76,6 +107,7 @@ public static function getSubscribedEvents() {
    +    $events[KernelEvents::REQUEST][] = ['onKernelCheckUserCookies'];
    

    Adding this to a class called AnonymousUserResponseSubscriber feels tricky because it about responses but this is about requests. The description for the class is * Response subscriber to handle finished responses for the anonymous user.. This change makes that not true.

    Fortunately I think there is a much place to put this. I think we can add this to \Drupal\user\Authentication\Provider\Cookie::applies() we can change the code there to make it do:

      public function applies(Request $request) {
        $applies = $request->hasSession() && $this->sessionConfiguration->hasSession($request);
        if (!$applies && $request->query->has('check_logged_in')) {
          $domain = ltrim(ini_get('session.cookie_domain'), '.') ?: $request->getHttpHost();
          $this->messenger->addMessage($this->t('To log in to this site, your browser must accept cookies from the domain %domain.', ['%domain' => $domain]), 'error');
        }
        return $applies;
      }
    

    I've tested this locally and it seems to work just great.

  5. +++ b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
    @@ -154,9 +154,20 @@ public function build() {
    +    // user_init().
    

    user_init() does not exist. This should @see to the event subscriber. The @see should be in the method docs because they actually works with IDEs and api.drupal.org better.

  6. +++ b/core/modules/user/tests/src/Functional/UserBlocksTest.php
    @@ -80,7 +80,7 @@ public function testUserLoginBlock() {
    -    $this->assertSession()->addressEquals(Url::fromRoute('user.admin_permissions'));
    +    $this->assertSession()->addressEquals(Url::fromRoute('user.admin_permissions', [], ['absolute' => TRUE, 'query' => ['state' => 'loggedin']]));
    

    This does not check parameter. See #3164686: WebAssert::addressEquals() and AssertLegacyTrait::assertUrl() fail to check the querystring

michaellenahan’s picture

Status: Needs work » Needs review
FileSize
12.46 KB
8.83 KB

Thanks for the review, I was not sure about points 5 and 6, but implemented the other points.

1. Querystring changed to ?check_logged_in=1

2. $request->getHost() ... done

3. Was not sure where to put the test, I put it in testUserLoginBlock() for now, even though it is not actually testing the login, but it is closely related to that.

4. Added code to \Drupal\user\Authentication\Provider\Cookie::applies() as suggested

5. Not sure what you meant by "This should @see to the event subscriber" ... so this is still to-do.

6. Also not sure what to do here ... so also still to-do.

The last submitted patch, 252: 2946-252.patch, failed testing. View results

xmacinfo’s picture

Status: Needs review » Needs work
alexpott’s picture

Status: Needs work » Needs review
FileSize
10.3 KB
10.38 KB

The patch attached tweaks the approach of where the query parameter is added and what causes it. user_login_finalize() sets something in session to tell the system we need to check that cookie login is going to work. Then in the same request the Cookie auth provider listens to responses and checks if a redirect is going to happen and adds the request param as necessary to the redirect url. This change means that all usages of user_login_finalize() will do the is cookie working check so log ins via the one time form will also be checked for this (and any contrib that uses user_login_finalize() too ftw).

Also I've added a proper test where cookies are disabled in the guzzle client that makes requests during tests.

I make the patch rather than doing review comments because I couldn't work out how to explain how to do this without actually doing it. And once i did that not posting a patch seemed silly.

michaellenahan’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
203.54 KB
224.69 KB

I make the patch rather than doing review comments because I couldn't work out how to explain how to do this without actually doing it. And once i did that not posting a patch seemed silly.

Absolutely. Thanks!

I tested the patch in a browser with cookies disabled.

Works as expected for a log in via user/login.
Works as expected for the one-time login.

Screenshots attached.

Leaving at Needs Review, I don't have enough knowledge to mark RTBC. But I learned a lot from reading your patch and your comment :)
https://www.drupal.org/docs/develop/issues/fields-and-other-parts-of-an-...

michaellenahan’s picture

Status: Reviewed & tested by the community » Needs review
xmacinfo’s picture

Status: Needs review » Reviewed & tested by the community

I queued a test run on PHP 8. Let's see green!

So far, based on the latest comments and code change by @alexpott, I mark this as RTBC.

ifrik’s picture

Status: Reviewed & tested by the community » Needs review

I've just tested it as well, and the error message shows up as expected.

ifrik’s picture

Status: Needs review » Reviewed & tested by the community
ifrik’s picture

Now how does this work with merge-requests?
I've made one which has patch #245 in it, but obviously that shouldn't be merged now. But I can't cancel that one, and I can't add a new merge request with a new patch.

larowlan’s picture

+++ b/core/modules/user/user.module
@@ -462,6 +463,7 @@ function user_login_finalize(UserInterface $account) {
   \Drupal::service('session')->migrate();
   \Drupal::service('session')->set('uid', $account->id());
+  \Drupal::service('session')->set('check_logged_in', TRUE);

now we're using this 3 times, should we use a local variable? Micro-optimisation but each call to \Drupal::service() adds some overhead

pity that these methods aren't chainable

raman.b made their first commit to this issue’s fork.

raman.b’s picture

Nice catch. Let's do that before this goes in

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/user/src/Authentication/Provider/Cookie.php
@@ -36,17 +52,25 @@ class Cookie implements AuthenticationProviderInterface {
-  public function __construct(SessionConfigurationInterface $session_configuration, Connection $connection) {
+  public function __construct(SessionConfigurationInterface $session_configuration, Connection $connection, MessengerInterface $messenger) {
     $this->sessionConfiguration = $session_configuration;
     $this->connection = $connection;
+    $this->messenger = $messenger;
   }

We need to trigger a constructor deprecation here... there's things on contrib that depend on the constructor...

See http://codcontrib.hank.vps-private.net/node/30896787 for example.

quietone made their first commit to this issue’s fork.

xmacinfo’s picture

Status: Needs work » Needs review
Lendude’s picture

Status: Needs review » Needs work

Other then the warning, we also need the parameter to be NULL by default and we need to fill it from \Drupal:: when it is NULL, I think that is still missing

See \Drupal\book\Form\BookAdminEditForm::__construct

quietone’s picture

Status: Needs work » Needs review

That is odd, I thought I had put that in. Fixed now.

sokru’s picture

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

Tested manually, looks good. Updated issue summary with current behavior on Drupal 9.2.x.

nod_’s picture

I know this is a very old issue, but when I read the issue summary and see the solution I'm wondering if a JS solution is not a better approach as far as UX is concerned, since this issue was mainly about the user experience of the login with cookies disabled.

We can detect the fact that a browser can store cookies or not with navigator.cookieEnabled and add a warning right on the form before the user submits it, or we could even prevent the form from being submitted. This would be a solution with what I would say is a better UX, that takes care of most users, then we would need to decide what to do for people with no JS and no cookies, is it worth adding this code for that amount of users?

(also it's interesting to see that 15 years later, we can find the same piece of code at the same URL for wordpress :)

alexpott’s picture

@nod_ it's possible there might be other auth providers that work without cookies. Having the check part of auth provider means that the logic is in the correct place. Also other forms of authentication can use the same method to check.

Also it means JS on every page of a site with a login block / form somewhere for anonymous users - atm without big_pipe installed there's no JS when installing standard... not true though if you change the theme to olivero...

larowlan’s picture

Status: Reviewed & tested by the community » Needs review

Also other forms of authentication can use the same method to check.

It looks like we're only touching Cookie in the current patch and the issue summary is specifically about cookies.

quietone’s picture

Issue summary: View changes
Status: Needs review » Needs work

Needs work for the unresolved comment.

alexpott’s picture

@larowlan the bit other auth providers can use is

  /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
  $session = \Drupal::service('session');
  $session->migrate();
  $session->set('uid', $account->id());
  $session->set('check_logged_in', TRUE);
  \Drupal::moduleHandler()->invokeAll('user_login', [$account]);

in user_login_finalise() - then they can use the session check_logged_in to ensure login as worked too.

quietone’s picture

Status: Needs work » Needs review

That fixes the point raised by larowlan.

dww’s picture

Status: Needs review » Reviewed & tested by the community

Feedback addressed, back to RTBC! Wonderful to see this finally getting fixed. Thanks to everyone who works on this over all the years. Huzzah!

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

I notice that the MR has not been tested since 24 March. Therefor I am making a patch and uploading it so that testing will happen every two days.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 279: 2946-279.patch, failed testing. View results

quietone’s picture

Failed on Field_ui.Drupal\Tests\field_ui\FunctionalJavascript\ManageDisplayTest, which is not listed in #2829040: [meta] Known intermittent, random, and environment-specific test failures.

However, since I've never been able to run FunctionalJavascript tests locally, starting a retest.

quietone’s picture

Status: Needs work » Reviewed & tested by the community

Back to RTBC

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 279: 2946-279.patch, failed testing. View results

quietone’s picture

Failed in Field_layout.Drupal\Tests\field_layout\FunctionalJavascript\FieldLayoutTest, #3099427: [random test failure] FieldLayoutTest::testEntityView(). retesting

quietone’s picture

Status: Needs work » Reviewed & tested by the community

Tests passing back to RTBC

smustgrave’s picture

Question. I just updated my local to 9.2.0 and appear to be getting an issue with logging in. Could this be why?

stopopol’s picture

I have the same issue after updating core to 9.2.0. Downgrading to 9.1.10 solves the issue.

alexpott’s picture

phenaproxima’s picture

Adding credit for comments 200 to 289.

pameeela’s picture

Added credits for comments 1-200.

pameeela’s picture

One more credit.

  • larowlan committed d5ee37a on 9.3.x
    Issue #2946 by chx, michaellenahan, jcnventura, quietone, ifrik, wengerk...
larowlan’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed
FileSize
71.79 KB

Manually tested this one more time.

Took me forever to work out how to even turn off cookies, its so rare to do so nowadays.

Works as it says on the box

🎉🐛🔨

To everyone involved in smashing this 4 digit nid core bug, thank you

xmacinfo’s picture

Amazing work everyone! Infinite thank you!

jcnventura’s picture

So happy this was committed. Just for historical context.. This was reported as a Critical bug for Drupal 4.2.0, 17.5 years ago. I first worked on this (#173) in one of the code sprints for Barcelona 2015. I was hoping we could have gotten this into Drupal core 8.0.0. And now, it will be in 9.3.0. When it gets released on that stable version next December, over 18 years will have passed.

So again, congratulations to all those who came before and after me to get this done. You all rock!!

Status: Fixed » Closed (fixed)

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

klonos’s picture

This applies to 7.x, yet I see no "needs backport" tag. Was a separate issue filed for D7 and I missed it somehow?

xmacinfo’s picture

@klonos: You need to create a new ticket for Drupal 7. There is probably an old patch above that would still apply for Drupal 7, minus tests.

izmeez’s picture

For D7 the patch in comment #76 #2946-76: Login fails and no warning is issued if cookies are not enabled appears to be the last one that worked but the issue of adding tests delayed it indefinitely. Also remember the related issue #791004: Installer does not warn the user that cookies must be enabled with the correct cookie domain (and fails when they aren't). A new issue for the D7 backport, if there is to be one, makes sense.

cosolom’s picture

I'm not sure that all works fine, because after logged out I get this message
And url have attached /?check_logged_in=1

izmeez’s picture

New issue created for D7 backport #3255713: [D7] Login fails and no warning is issued if cookies are not enabled with reference to patch in comment #76. That patch should probably be attached to the new issue for review.

Back From 7’s picture

This is why I despise Drupal. Very complicated, bloated and not reliable...

richard.e.morton’s picture

I appreciate all the hard work. But I'm sure everyone will agree that this is a hilarious timescale for this to be resolved. Just consider what has happened in the intervening (nearly) two decades...

Reporter: anders
Created: 20 Sep 2003 at 06:30 UTC
Updated: 6 Apr 2022 at 21:11 UTC

Eduardo Morales Alberti’s picture

I added redirection to the user login with a "hash" and I saw that the URL loses the URL fragment because the URL parser has the property fragment without hash but the Cookie class tries to access the property with hash.

On the method Cookie::addCheckToUrl() the option fragment is considered with hash, but on the UrlHelper is without Hash, so the response loses the fragment.

https://git.drupalcode.org/project/drupal/-/commit/d5ee37a05d0e43a93d280...

  public function addCheckToUrl(ResponseEvent $event) {
    $response = $event->getResponse();
...
        if (!empty($options['#fragment'])) {
          $url .= '#' . $options['#fragment'];
        }
        $response->setTargetUrl($url);

UrHelper::parse()
https://git.drupalcode.org/project/drupal/-/blob/d5ee37a05d0e43a93d28050...

public static function parse($url) {
....
      if (strpos($url, '#') !== FALSE) {
        list($url, $options['fragment']) = explode('#', $url, 2);
      }

I opened a new issue for this https://www.drupal.org/project/drupal/issues/3278692#comment-14504031 and a MR https://git.drupalcode.org/project/drupal/-/merge_requests/2221/diffs

patchak’s picture

Hi all, I have this exact same bug, it seems it's still in Drupal 10, I have been having issues regarding login and I now think this is because cookie are not set properly on the browser (as I never say any request for accepting cookies) and the login on new installs keeps failing.

I'm running on cloud ways PHP server, happy to provide more details...
thanks

xmacinfo’s picture

Please open a new ticket and relate this ticket to the new one.