Problem/Motivation
With page cache enabled and homepage properly cached, when a user logs in with a persistent session, closes and re-open the browser, the homepage is being server from the cache, also preventing the automatic re-login of the user.
This happens on the page cache middleware. Since the session cookie has been deleted when the browser was closed, the policy rules that are checked in order to determine the cacheability of a request do not prevent said caching.
Normally \Drupal\Core\PageCache\RequestPolicy\NoSessionOpen would skip the cache when the session cookie is present.
Proposed resolution
Create a policy rule similar to the above. This policy should check if the persistent login cookie is present and the session one is not. This would mean that the token wasn't yet validated, so we need to avoid caching in order to allow said validation and automatic relogging of the user.
If the token is valid, the session cookie will be created and the normal NoSession policy rule will start applying. If the token is not valid, it will be removed and caching will be again possible for the subsequent requests.
Remaining tasks
Provide tests. The bug was actually discovered running a Behat test on the project I'm working on (see here).
It should be possible to write a browser test with the same steps as this one.
User interface changes
None.
API changes
Moved the cookie name generation to a TokenHelper service because the request policy rule also needed it.
Data model changes
None
Comment | File | Size | Author |
---|---|---|---|
#13 | 2853553-13.patch | 15.89 KB | sardara |
| |||
#13 | 2853553-13-test_only.patch | 5 KB | sardara |
| |||
#13 | interdiff-10-13.txt | 3.61 KB | sardara |
#10 | interdiff.txt | 9.88 KB | pfrenssen |
#10 | 2853553-10-test_only.patch | 4.35 KB | pfrenssen |
|
Comments
Comment #2
sardara CreditAttribution: sardara at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commentedComment #3
claudiu.cristeaSeems that needs some tests :)
Comment #4
pfrenssenLet's make this sentence gender neutral, not all visitors are male.
Also "This should happen only" sounds quite strong, maybe just say "A common situation"?
It would sound better to say "..not applicable on _subsequent_ page loads."
Use third person verb.
When injecting services, it's good practice to provide an interface instead of a concrete implementation.
This is the actual bugfix. Let's add some documentation here why we are returning DENY if our cookie is present but there is no session.
Good idea to put these helper methods in a separate service. Let's add an interface for it so the methods can be swapped out with a custom implementation when needed.
Use a third person verb to start the summary of a class, interface, or method: "Instantiates a new...".
Use third person verb.
Use third person verb.
Comment #5
pfrenssenBumping this to major, since the main functionality of the module (staying logged in) is broken on websites that use the page cache, which I presume is the most common situation for sites that are in production.
Comment #6
gappleThank you @sardara for the detailed report and patch, and @pfrenssen for the review.
The name
TokenHelper
didn't indicate to me the need for a new class or its role before reading the code. Given its scope, I thinkCookieHelper
may be more appropriate.I generally agree with, but am less strict about having an interface for each service.
Comment #7
pfrenssenCookieHelper
sounds like a really good name for the service.Assigning to me, I'll address the remarks, and port the Behat test that is linked in the issue summary to
BrowserTestBase
. I very much like the way the Behat test is set up since it also covers the base functionality of the module.Comment #8
pfrenssenAddressed the remarks. Going to start on the test coverage now.
Comment #9
claudiu.cristeaComment #10
pfrenssenHere is the test + some renames that I missed in the previous patch.
Full credit for this work should go to @sardara, I shamelessly ripped off the code + general approach from the Behat test posted in the issue summary.
@gapple, can you enable the test coverage in the Automated Tests tab on the project homepage so we can see the test results?
Comment #11
pfrenssenAwaiting automated testing to be enabled for the projects, here are the test results from a local test run. The first test run passes with the patch applied, and the second test run is done on the 8.x-1.x branch without the patch, and this test fails. This indicates that the patch fixes the problem correctly.
Comment #12
sardara CreditAttribution: sardara at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commentedComment #13
sardara CreditAttribution: sardara at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commentedThe test was missing to mimic the setup required by the module, which is setting the cookie lifetime to 0.
I added that to the
setup()
, added a few assertion messages and improved a function comment which I wrote before and sounded a bit weird.Thanks for supplying the test @pfrenssen !
Comment #15
pfrenssenThanks @sardara, the cookie life time is critical for the functioning of the module. This is very useful to have added this to the test setup.
Missing comma at the end.
Missing comma at the end.
Comment #16
sardara CreditAttribution: sardara at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commentedOops!
I've found the missing commas.
Comment #18
pfrenssenThanks! Looks good now.
I have written the test in this patch, but this has been approved by @sardara in comment #13. I have reviewed the original fix. So seeing that all work has been reviewed properly I think it's fine to RTBC this :)
Comment #21
gappleThere was a related security report submitted.
If after a cache rebuild a user returns to the site with a persistent login token, the response is cached including their updated persistent login cookie. The next visitor to that url will also receive the cookie and may be authenticated as another user.
Since this patch turns off page cache behaviour for the entire request, it also excludes page cache from storing the response, resolving the issue. The only other change I've introduced is to mark the response as private if the persistent login cookie is set, updated, or cleared to ensure that no other intermediary caches attempt to store the response.
Since the module is still in alpha and did not support the page cache prior to this patch there won't be a security announcement, but I will tag the next alpha release as containing a security fix.