Problem/Motivation
In order to move towards #1858196: [meta] Leverage Symfony Session components it is necessary that SessionHandler
introduced in #2228341: Objectify session management functions + remove session.inc implements the Symfony SessionStorageInterface. A service implementing SessionStorageInterface
is a requirement for the introduction of the Symfony Session. In Symfony applications an instance of this class is accessible through Request::getSession()
. This is the preferred way of accessing session data, especially because this will lazy load the session on access.
There are two possible options to reach that goal:
- Make
SessionHandler
a subclass ofNativeSessionStorage
. - Implement all methods declared by
SessionStorageInterface
directly inSessionHandler
.
Please note that despite the quite confusing name NativeSessionStorage
in fact corresponds directly to Drupal SessionManager
. The session system changed a lot since Symfony 2.0. The storage-part of the NativeSessionStorage
class was subsequently extracted into NativeSessionHandler
. At the same time it shifted from the simple storage-class to the current manager-class but unfortunately the name was not changed.
Proposed resolution
The NativeSessionStorage
class already implements all of SessionStorageInterface
. Thus let's reuse as much as possible from NativeSessionStorage
by rebasing SessionHandler
onto NativeSessionStorage
and gradually remove redundant code from SessionHandler
.
Remaining tasks
- review
User interface changes
API changes
Related Issues
- this issue will help clean up an ugly work around being introduced in #2245003: Use a random seed instead of the session_id for CSRF token generation
Follow-ups
Comment | File | Size | Author |
---|---|---|---|
#44 | 2238087-rebase-session-manager-44.patch | 23.49 KB | znerol |
#44 | interdiff.txt | 1.23 KB | znerol |
#44 | interdiff.txt | 1.23 KB | znerol |
#38 | 2238087-rebase-session-manager-38.patch | 22.65 KB | YesCT |
#38 | interdiff-2238087-37-38.txt | 1.67 KB | YesCT |
Comments
Comment #1
znerol CreditAttribution: znerol commentedComment #2
cosmicdreams CreditAttribution: cosmicdreams commentedOMG What? It's that simple? Well I'm happy it passes.
However, I'm not sure we have enough tests. Can we Unit Test the SessionManager?
Why are we renaming these variables?
Awesome
Freaking Awesome
Comment #3
znerol CreditAttribution: znerol commentedThe simpletest-coverage inherited from D7 is pretty comprehensive. In fact I spent a considerable amount of time in the debugger examining test failures before I did understand the new interactions with e.g.
MetadataBag::$updateThreshold
.Neither SessionManager nor SessionHandler are unit-testable (i.e. PHPUnit) at the moment because they call the built-in PHP session and cookie functions directly.
Because
NativeSessionStorage
already has a private non-static attribute with the name$started
.Comment #4
znerol CreditAttribution: znerol commentedReplaced all calls to
session_name()
with$this->getName()
and$this->setName()
. Replaced all but one call tosession_id()
with$this->getId()
and$this->setId()
. The problem with the remaining invocation inSessionManager::regenerate()
is that[...]\HttpFoundation\Session\Storage\Proxy\AbstractProxy::setId()
throws an exception when it is called after a session has been started. Symfony uses the standard PHP session id, so let's figure out whether it is acceptable for Drupal to throw overboard the custom session-id code: #2238561: Use the default PHP session ID instead of generating a custom one.Also removed the comment about "less random sessions" which does not apply anymore after Drupal 7.24.
Comment #5
znerol CreditAttribution: znerol commentedNot so sure whether this is still in scope: Use
..\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler
instead of the custom access check to implement thesession_write_interval
setting as well as the write-barrier when no session data changes.Also extend
[...]\HttpFoundation\Session\Storage\MetadataBag
such that it can be configured viasettings.php
. I plan to add more methods to this class in order to be able to transport the Drupal-specificuid
andhostname
properties betweenSessionHandler
and the cookie authentication provider. This will help with extracting everything related to$user
fromSessionManager
andSessionHandler
.Comment #7
sunPerhaps we should rename the internal/protected static property name to
$locked
now?We'd just negate its value then (and keep the existing methods).
Just an idea. Not sure.
...The concept is a bit flawed anyway... When session saving is disabled and re-enabled, then we are still saving potentially unsecure data, because the original session (from the time at which session saving was disabled) has not been cloned/retained as a separate copy (which could then be restored).
Somehow I've the impression this code could be vastly simplified by using
array_diff_key()
?Comment #8
znerol CreditAttribution: znerol commentedReupload of 5, this time including the
\Drupal\Core\Session\MetadataBag
. Interdiff is from #4.Comment #10
pwolanin CreditAttribution: pwolanin commentedCan you explain in the summery in more detail the motivation for using the symfony code here?
Comment #11
znerol CreditAttribution: znerol commented8: 2238087-rebase-session-manager-8.diff queued for re-testing.
Comment #12
znerol CreditAttribution: znerol commentedComment #13
znerol CreditAttribution: znerol commentedComment #14
znerol CreditAttribution: znerol commentedComment #15
sun#7 wasn't addressed yet.
Additionally reviewed the latest patch:
1) Can we move this definition below session_manager? (as it's more specific)
2) Could we rename the service ID to just
session_metadata
? → That would inherently make the Settings name consistent withi that.Is there any sensible use-case for overriding this key?
If so, it would be good to add an inline comment that states so accordingly; i.e.:
// Allow ... to ... in case ...
If not, then we could consider to remove this setting?
Is there actually a difference between the two, aside from ours being static?
If there is no difference, then I think it would be time to figure out how we can get rid of this static. — Perhaps we should attempt that in a separate sister issue first?
Created #2239181: SessionManager::isStarted() returns TRUE even after session_write_close() has been called
Comment #16
znerol CreditAttribution: znerol commentedAddressed #7 and #15.
I still need to hammer a bit on
SessionManager::isEmptySession
. Perhaps it gets better when I remove the early returns.Maybe the static
$started
property better translates to AbstractProxy::isActive(), let's see whether #2239181-5: SessionManager::isStarted() returns TRUE even after session_write_close() has been called returns green.Comment #17
thelmer CreditAttribution: thelmer commentedWhen the SessionManager::regenerate() is called by eg. user_login_finalize($this->user) the session id invalid:
Warning: session_start(): The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in Drupal\Core\Session\SessionManager->start() (line 129 of /sites/drupal8/core/lib/Drupal/Core/Session/SessionManager.php).
( fresh git checkout )
Comment #18
znerol CreditAttribution: znerol commented@thelmer: This patch is not yet committed, therefore the problem you are experiencing cannot possibly be related the work being done here. Please open a new bug-report.
Comment #19
znerol CreditAttribution: znerol commentedRemoved most static calls to
Settings::get()
. We need to find another place for the one which remains inSessionHandler::write()
anyway, a session save handler is not supposed to write into theusers
table in the first place. However untangling the user and the session code is out of scope here.Comment #20
znerol CreditAttribution: znerol commentedThen finally reindent the chunk of code in
SessionHandler::write()
where we removed the write-check condition (see #5).I consider this is ready for the moment. Together with #2239181: SessionManager::isStarted() returns TRUE even after session_write_close() has been called this will bring us one step closer to #1858196: [meta] Leverage Symfony Session components.
Comment #21
znerol CreditAttribution: znerol commentedInterdiff for #20.
Comment #22
znerol CreditAttribution: znerol commentedReroll after #2239181: SessionManager::isStarted() returns TRUE even after session_write_close() has been called. Also remove
SessionManager::isStarted()
(delegate to base class).Comment #23
YesCT CreditAttribution: YesCT commentedadding #2245003: Use a random seed instead of the session_id for CSRF token generation to the issue summary, because this issue is not "blocking" that one (yet) but getting this in would help there.
Comment #24
cosmicdreams CreditAttribution: cosmicdreams commentedSo it seems as if this is ready to go. It just needs some serious reviews. I tried to review this with dreditor but I think I need to apply the patch and review this in context of the rest of the code.
Comment #25
YesCT CreditAttribution: YesCT commentedmostly just nits. still needs a good read through.
missing period at end of sentence.
https://drupal.org/coding-standards/docs#classes
"Use a third person verb to start the summary of a class, interface, or method. For example: "Represents a ..." or "Provides..."."
Tried to figure out what a 'Bag' does...
"A bag contains variables or parameters. http://stackoverflow.com/questions/19798108/in-symfony-what-is-a-bag"
similar. Constructs
there is no such class. :)
Core -> Component
reformatting (https://drupal.org/coding-standards/docs#todo),
and adding the link to the actual issue #2229145: Register symfony session components in the DIC and inject the session service into the request object
But maybe this todo actually needs it's own issue which would be a follow-up of 2229145.
Third person verb again.
adding @param
Is it an array of sessions, or.. an array of info that describes a session?
Looked at the usages, and both calls do not pass in an argument. So I'm not sure what $session might be.
changing the doc to Enables or disables.
But, question: should this also return $this; ?
I think that's a common pattern for set methods so that we can do chaining.
adding a @return
https://drupal.org/coding-standards/docs#return
(and the newline before the class end } )
"Leave an empty line between end of method and end of class definition:"
https://drupal.org/node/608152#indenting
Comment #26
YesCT CreditAttribution: YesCT commentedthis made my head spin. I think I read it 5 time.
we had a save handler, then we got a write_check handler, then we set the save handler to the write_check handler. maybe this makes sense to people who know about sessions?
ah, I see, the setting the insecure name was moved up before the if, out of the else part, since it was used in the condition up there anyway.
why did we delete this comment. was it incorrect?
it might have been explaining why we use 64 instead of something else? i'm not sure what it is less random than.
Comment #27
znerol CreditAttribution: znerol commentedThanks for the cleanup in #25, regarding #26:
Comment #28
YesCT CreditAttribution: YesCT commentedOh, I think the issue summary was updated after #10 asked for it. removing that tag.
Updating remaining tasks.
Comment #29
znerol CreditAttribution: znerol commentedReroll of #25 after #2208475: Move Settings into Drupal\Core\Site\Settings.
Comment #31
znerol CreditAttribution: znerol commentedForgot
MetadataBag
when adapting for changedSettings
namespace. Also attaching the interdiff against #25.
Comment #32
YesCT CreditAttribution: YesCT commentedComment #33
znerol CreditAttribution: znerol commentedReroll after #2245003: Use a random seed instead of the session_id for CSRF token generation. I did not manage to generate a proper interdiff because of a merge conflict. The affected method is
SessionManager::isEmptySession()
(patch) which was introduced asSessionManager::isSessionObsolete()
into HEAD by #2245003. Also introducedSessionManager::getSessionDataMask()
, which helps with implementingSessionManager::isSessionObsolete()
in a way which hopefully makes better sense (re @sun #7.2).I think moving the csrf token seed to the metadata bag should be done in a follow-up. Therefore I consider this finished provided that the patch comes back green.
Comment #34
znerol CreditAttribution: znerol commentedComment #35
YesCT CreditAttribution: YesCT commentedthis isn't a true interdiff. it's just a diff of the last two patches with some noise removed.
Comment #36
YesCT CreditAttribution: YesCT commentedhm.
http://www.php.net/manual/en/function.array-filter.php
If no callback is supplied, all entries of array equal to FALSE (see converting to boolean) will be removed.
so isSessionObsolete() removes any keys that evaluate to false, and then checks if it's empty, and if it is, it is obsolete.
Are the docs on this method still ok? I looked and I think they are ok still.
Comment #37
YesCT CreditAttribution: YesCT commentedtiniest nit. just fixed it. (https://drupal.org/node/1354#functions third person verb, Returns instead of Return)
Next:
I'll open the followups.
Comment #38
YesCT CreditAttribution: YesCT commentedI created #2256257: Move token seed in SessionManager in isSessionObsolete() and regenerate() to the MetadataBag. removing the needs follow-up tag.
Seems like the two @todos that reference this issue (2238087) were the only two. And that they should be done in the same issue. (If not, please explain/create the other issue.)
Comment #39
YesCT CreditAttribution: YesCT commentedComment #40
cosmicdreams CreditAttribution: cosmicdreams commentedLooks good to me
Comment #41
catchThe title/issue summary confuses me a bit - given we don't actually want to use NativeSession Storage.
Is implementing the interface directly that bad?
If it is, then that seems like a good case for adding a BaseSessionStorage abstract class upstream, rather than extending a specific implementation.
Comment #42
sun@catch: This issue is just one more "baby step" of the parent issue. The ultimate end goal is still to use all of Symfony's Session handling natively.
Comment #43
znerol CreditAttribution: znerol commentedComment #44
znerol CreditAttribution: znerol commentedAs discussed with @catch on IRC add documentation and @todo for the class.
Comment #45
cosmicdreams CreditAttribution: cosmicdreams commentedGreat comment, Still Good.
Comment #46
catchThanks! That makes it a lot more obvious what's going on.
Committed/pushed to 8.x.