Problem/Motivation
Third party implementations should be able to modify session options and therefore DrupalKernel::initializeCookieGlobals() needs to be replaced by a service. Regrettably #2331909: Move DrupalKernel::initializeCookieGlobals() into page cache kernel decorator encountered major road blocks, therefore let's try a different approach.
A couple of PHP ini-settings need to be set up correctly in order to ensure that sessions are safe and work seamlessly. In Drupal most of those values were enforced from within settings.php. However, the value of some of those ini-settings depend on a request object with reverse proxy headers already validated. It follows that those values cannot be set statically in a config file or as a container parameter but need to be determined at runtime. This applies for the session_name (in order to properly keep apart secure (HTTPS-only) session cookies from plain ones), but also for the cookie_domain.
The NativeSessionStorage class (the parent class of the Drupal SessionManager), accepts an array of ini-options as a constructor argument. It also can receive it through its setOptions method. However, Symfony does not support advanced use-cases like the ones outlined above out of the box.
Taking the best of both worlds, let's introduce the session.storage.options container parameter and augment those using a new session_configuration service just before a session is started.
It has been suggested elsewhere (#1934730-8: Alternative session handler implementation is not able to override session_name()) that the responsibility of setting the session name should be moved to the SessionManager. However, that would result in the session manager being instantiated including all of its dependencies when the page cache request policy desires to verify whether there is a session cookie on an incoming request. The session configuration service does not have any dependencies and therefore it is save to assume that its instantiation has less impact on the response time when pages are served from the cache.
Proposed resolution
Introduce a Drupal\Core\Session\SessionConfiguration service which is capable of choosing session ini-values on a per request basis. Sites and modules which need to modify session ini settings (like e.g. Secure Pages) may supply their own implementation of the session configuration service.
Note, this ensures that even though global $cookie_domain is replaced by a container parameter, it is still possible for the session configuration service to choose a different value for session.cookie_domain based on the request.
Remaining tasks
Review.
User interface changes
None.
API changes
- Replace the
global $cookie_domainby a container parameter. - Move session related ini settings from
settings.phpto a container parameter.
Beta phase evaluation
| Issue category | Bug because it is resolving #1934730: Alternative session handler implementation is not able to override session_name() |
|---|---|
| Issue priority | Major because it provides contrib with a clean way to implement mixed mode SSL support (Secure Pages). This resolves a temporary regression introduced by #2342593: Remove mixed SSL support from core. |
| Disruption | Moderately disruptive for existing sites because they might need to replicate the changes to site settings.php, services.yml |
Comments
Comment #1
znerol commentedComment #2
znerol commentedComment #4
znerol commentedunprefixedNameandcookieDomainfromSessionConfigurationclass, they are cheap to compute and they depend on the$request. Therefore the cache is technically incorrect.Request::getHost()method in fact throws an exception if the host-name contains unexpected characters as well as if it starts with a period. It also removes the port.Comment #5
znerol commentedUh, forgot to add
session.cookie_secure...Comment #9
znerol commentedComment #10
znerol commentedAnother option would be to use the a service configurator which consumes the request stack and then sets up the session manager appropriately. However, in that case the
hasSessionmethod would needs another new home.Comment #11
znerol commentedThis moves session configuration into container parameters and removes the
$cookie_domainglobal variable.Comment #12
znerol commentedComment #13
znerol commentedComment #14
znerol commentedComment #15
znerol commentedAdd unit tests and fix a little mistake in
SessionConfiguration::getCookieDomain()detected while adding unit tests.Comment #16
Crell commentedMost of this is out of my wheelhouse, so I cannot RTBC it. I didn't notice anything major from a read through, though. Just a few doc related comments below:
Can we also add a @see to the PHP documentation on what those ini settings are?
Please link to the RFC.
Although according to Wikipedia that RFC has been obsoleted for a long time, and there are multiple more recent RFCs to reference instead:
http://en.wikipedia.org/wiki/HTTP_cookie
Ooo...
Comment #17
znerol commentedRegrettably cookie domain implementations are a mess (and also the RFCs partially contradicting each other etc.). Citing from a random blog entry:
Let's just specify that the leading dot is required to maximize compatibility and the embedded dot is required because user agents will hopefully never accept cookies for top-level domains.
Comment #18
znerol commentedComment #20
znerol commentedReroll after #2338759: core/update.php is now just update.php.
Comment #21
znerol commentedComment #22
klausiHTTPS mixed mode has been removed.
Comment #23
znerol commentedComment #24
dawehnerThe IS has to describe that we change
global $cookie_domain;and converts it into a container parameter. I can't think of a usecase where this cookie domain has to be dynamic ... on top you probably rely on the host most of the time anyway.I wonder whether we can specify was potentially means.
Impressive test coverage!
seriously RFC!
Comment #25
znerol commentedFixed the issue summary, added upgrade path tag, fixed the docs.
Comment #26
andypostLooks great! +1 to RTBC
Comment #27
Crell commentedOnly one minor nit:
I don't think we ever list the mock object as a var possibility, do we? If it's a mock that should be transparent, and conform to that interface anyway, no?
Otherwise I am comfortable here.
Comment #28
znerol commentedMaybe I'm misunderstanding the comment here, but we use
@var \Drupal\Some\ClassInterface|\PHPUnit_Framework_MockObject_MockObjectall over the place.CR draft: https://www.drupal.org/node/2391871
Comment #29
Crell commentedWhy in the name of Zork are we doing that...?
(If we are, then that shouldn't block this issue but it's nonsensical for us to be doing in the first place, IMO.)
Comment #30
znerol commentedI guess that's for folks with IDEs. When specifying both types in
@varit is likely possible to autocomplete methods ofPHPUnit_Framework_MockObject_MockObject(e.g.expects()) in addition to those on the original class.Comment #31
Crell commented*sigh* Durpal.
Comment #32
dawehnerYeah, its a huge DX win for you, if you have documented the types.
Comment #37
berdirReroll, minor conflict in WebTestBase.
Comment #38
dawehnerThe question from crell got answered
Comment #39
alexpottCommitted 9a6582b and pushed to 8.0.x. Thanks!
Fixed some docblocks on commit.