Problem/Motivation

There is still the static SessionManager::$enabled property which does not need to be static anymore after #2272987: Do not persist session manager landed. Also there is an implicit cyclic dependency between SessionManager and SessionHandler. After #2342593: Remove mixed SSL support from core landed, this dependency now can be resolved by introducing WriteCheckSessionHandler.

Proposed resolution

In the spirit of Symfonys WriteCheckSessionHandler, replace the $enabled property with a WriteBarrierSessionHandler wrapping the real session save handler.

Remaining tasks

Review.

User interface changes

None.

API changes

None.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Something between Bug and Task, circular dependency between SessionManager and SessionHandler might qualify as a design defect.
Issue priority Major because this helps removing complexity from SessionHandler and SessionManager and it introduces unit-tests for a mechanism which was not testable before in an easy way. (brittleness--).
Disruption No disruptive changes (no API change)

Comments

znerol’s picture

Title: [meta] Leverage Symfony Session components » Replace static SessionManager::$enabled property with WriteBarrierSessionHandler class
znerol’s picture

Status: Active » Needs review
StatusFileSize
new13.71 KB

Status: Needs review » Needs work

The last submitted patch, 2: 2338727-replace-static-enabled-property.diff, failed testing.

znerol’s picture

Status: Needs work » Needs review
StatusFileSize
new1.37 KB
new13.79 KB

Fix double-return in [en|dis]able() and usage of wrong save-handler in __construct().

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/Session/SessionManager.php
    @@ -65,15 +65,15 @@ class SessionManager extends NativeSessionStorage implements SessionManagerInter
    @@ -96,9 +96,9 @@ public function __construct(RequestStack $request_stack, Connection $connection,
    
    @@ -96,9 +96,9 @@ public function __construct(RequestStack $request_stack, Connection $connection,
    +    $this->writeBarrierHandler = new WriteBarrierSessionHandler($write_check_handler);
    ...
    +    parent::__construct($options, $this->writeBarrierHandler, $metadata_bag);
    

    I wonder whether we could add an optional dependency already, just to be clear that we actually want to get in the dependency from outside?

  2. +++ b/core/lib/Drupal/Core/Session/WriteBarrierSessionHandler.php
    @@ -0,0 +1,100 @@
    +<?php
    +/**
    

    Missing empty line.

  3. +++ b/core/lib/Drupal/Core/Session/WriteBarrierSessionHandler.php
    @@ -0,0 +1,100 @@
    +  /**
    +   * @var \SessionHandlerInterface
    +   */
    +  private $wrappedSessionHandler;
    +
    +  /**
    +   * Whether or not the write barrier is enabled.
    +   *
    +   * @var bool
    +   */
    +  private $sessionWritable;
    +
    

    I really don't like the fact that we introduce privates here.

znerol’s picture

Status: Needs review » Postponed

Rerolled, and fixed code style issues. Ultimately enable(), disable() and isEnabled() should be removed from SessionManager entirely. This can be done as soon as all database queries are eliminated from it. Therefore let's postpone this issue until that happens.

znerol’s picture

StatusFileSize
new13.75 KB
new824 bytes
cosmicdreams’s picture

Is there an issue where the queries are being eliminated?

znerol’s picture

znerol’s picture

Status: Postponed » Needs review
StatusFileSize
new14.44 KB
new2.15 KB

#2342593: Remove mixed SSL support from core is in, now this patch finally makes it possible to break the (hidden) circular dependency between session handler and session manager.

znerol’s picture

Title: Replace static SessionManager::$enabled property with WriteBarrierSessionHandler class » Replace static SessionManager::$enabled property with WriteBarrierSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler
Priority: Normal » Major
Issue summary: View changes

Rising the priority to major because this helps removing complexity from SessionHandler and SessionManager and it introduces unit-tests for a mechanism which was not testable before in an easy way. (brittleness--).

Also this will help us to introduce #2372389: Expose session handler in container with proper constructor injection instead of the setter-injection implemented there as a temporary workaround.

joelpittet’s picture

Issue summary: View changes

@znerol this looks great in terms of brittleness removal! I've added the beta evaluation table to the IS and added your note to move to Major into it, if you can fill out any of the other commented out rows that could help.

znerol’s picture

Issue summary: View changes
StatusFileSize
new15.63 KB
new2.48 KB

Add WriteBarrierInterface. A service implementing this interface should be consumed by AccountSwitcher instead of the session manager as soon as the WriteBarrierSessionHandler can be exposed as a container service (#2338727).

Status: Needs review » Needs work

The last submitted patch, 13: 2338727-replace-static-enabled-property-12.diff, failed testing.

znerol’s picture

Issue summary: View changes

znerol’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 13: 2338727-replace-static-enabled-property-12.diff, failed testing.

The last submitted patch, 7: 2338727-replace-static-enabled-property-6.diff, failed testing.

znerol’s picture

Status: Needs work » Needs review
dawehner’s picture

As said on IRC, I really don't get why we need this additional layer of abstraction. Why can't we just make SessionManager::$enabled a normal property and accept that a SessionHandler
needs the SessionManager ? Its a dependency we are aware of, and solve (which we do already).

cpj’s picture

I see what the code does, but I'm also unclear what problem we're trying to solve here. How can we decide if this is needed or not ?

znerol’s picture

From the IS:

there is an implicit cyclic dependency between SessionManager and SessionHandler.

We should work towards restricting the responsibility of SessionHandler to accessing storage exclusively such that contrib/custom handlers (memcache, redis, ...) can be implemented easily and (as a result) more safely.

At the moment if anyone intends to replace session storage, she also needs to swap out the SessionManager because of the close coupling. This issue does not completely solve the problem but is one important step into the direction of decoupling SessionHandler (storage) from the SessionManager (logic).

cpj’s picture

Thanks @znerol - that makes sense. I've reviewed the code and have tested the code in our environment. I've stepped through the code in my IDE's debugger and it all works as expected. However, I haven't tested this as part of an environment that swaps out the SessionHandler but I can see that the tests go some way to simulate this. Therefore if there are no objections, I'm going to mark this as "Reviewed & tested by the community" (= me).

cpj’s picture

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

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Session/WriteBarrierSessionHandler.php
@@ -0,0 +1,101 @@
+/**
+ * Wraps another SessionHandlerInterface to prevent writes during dangerous operations.
+ */
+class WriteBarrierSessionHandler implements \SessionHandlerInterface {

The name of the class - barrier seems strange. Also comment is longer than 80 chars. How about WriteSafeSessionHandler?

cpj’s picture

The Interface defined functions only say that the Class allows you to enable/disable writing and check the status, so it doesn't really define a "Safe" session handler. So how about WriteCheckSessionHandler ?

znerol’s picture

Symfony already provides a WriteCheckSessionHandler (and we are even using it). How about ReadOnlySessionHandler?

almaudoh’s picture

How about ReadOnlySessionHandler?

+1.

cpj’s picture

How about ReadOnlySessionHandler?

+1 from me too...

almaudoh’s picture

@znerol, @cpj: now that I look at the patch closely, I don't think ReadOnlySessionHandler is a very good name, because there is the option in this class to make the session writable (which implies that it is not read only).

So thinking through, @alexpott's WriteSafeSessionHandler actually sounds most appropriate, or maybe SafeWriteSessionHandler. If we're going with ReadOnlySessionHandler, then we have to get rid of setSessionWritable() and isSessionWritable()

almaudoh’s picture

Status: Needs work » Needs review
StatusFileSize
new15.66 KB
new8.98 KB

We can't get rid of setSessionWritable() / isSessionWritable(), so...here's the rename.

cpj’s picture

@almaudoh - OK, I agree. Either are fine by me but SafeWrite*** seems slightly better to me than WriteSafe***

cpj’s picture

+++ b/core/lib/Drupal/Core/Session/SessionManager.php
@@ -63,16 +63,16 @@ class SessionManager extends NativeSessionStorage implements SessionManagerInter
+   * @var \Drupal\Core\Session\WriteSafeInterface

Isn't this now a WriteSafeSessionHandlerInterface ?

almaudoh’s picture

StatusFileSize
new16.06 KB
new3.05 KB

Thanks @cpj and also some minor clean ups.

almaudoh’s picture

Title: Replace static SessionManager::$enabled property with WriteBarrierSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler » Replace static SessionManager::$enabled property with WriteSafeSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler
cpj’s picture

Looks great to me so I'm gonna change this to RTBC (again...)

cpj’s picture

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

Status: Reviewed & tested by the community » Fixed

Committed 6faa686 and pushed to 8.0.x. Thanks!

Thanks for adding the beta evaluation to the issue summary.

almaudoh’s picture

Status: Fixed » Reviewed & tested by the community

Looks like it wasn't committed. Can't find it on cgit.drupalcode.org or my local git clone.

  • alexpott committed 6faa686 on 8.0.x
    Issue #2338727 by znerol, almaudoh: Replace static SessionManager::$...
alexpott’s picture

Status: Reviewed & tested by the community » Fixed
almaudoh’s picture

Thanks @alexpott. Now on to #2372389: Expose session handler in container which was blocked on this issue.

Status: Fixed » Closed (fixed)

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