Skip to content

[HttpFoundation] Make SessionHandlerProxy implement SessionIdInterface #50626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

MatTheCat
Copy link
Contributor

Q A
Branch? 6.4
Bug fix? no
New feature? yes
Deprecations? no
Tickets Fix #45186 and #50583
License MIT
Doc PR Not yet

Supersedes #47071

It is currently not easy to provide its own session ids because even if your handler implements SessionIdInterface, it will be wrapped in a SessionHandlerProxy which does not, so your create_sid method won’t be called.

@MatTheCat MatTheCat force-pushed the session_id_interface branch from 9277bc2 to 06b6e73 Compare June 12, 2023 11:37
@deepsidhu1313
Copy link

Does this suppose to help setting the a custom session id using setId($some_id) function of Symfony\Component\HttpFoundation\Session\Session ??

@nicolas-grekas
Copy link
Member

I think all decorators should implement this, isn't it?

@MatTheCat MatTheCat force-pushed the session_id_interface branch from 06b6e73 to 615fd49 Compare June 26, 2023 08:10
nicolas-grekas
nicolas-grekas previously approved these changes Jun 27, 2023
@MatTheCat
Copy link
Contributor Author

Woops missed your comment.

I think all decorators should implement this, isn't it?

I guess they could 🤔 else you’re required to put your SessionIdInterface on top of the stack. I guess this isn’t an issue since you approved this PR?

@MatTheCat
Copy link
Contributor Author

Eeer after reading https://symfony.com/doc/current/session.html#session-proxies I wonder if this PR makes sense as you’re supposed to extend SessionHandlerProxy rather than decorate the inner handler.

@MatTheCat
Copy link
Contributor Author

MatTheCat commented Jun 28, 2023

Okay, just tried to do that and I got a ServiceCircularReferenceException… Does the issue come from Symfony or the documentation?

@nicolas-grekas
Copy link
Member

I'm a bit lost between the handler, the proxy, etc. I'll let you investigate if you don't mind :)

@MatTheCat
Copy link
Contributor Author

I’m still lost but I have some leads: session proxies purpose was originally to ease the migration from PHP 5.3 where SessionHandlerInterface did not exist. They were deprecated then removed, but AbstractProxy and SessionHandlerProxy escaped death thanks to #24523 because the latter would turns any handler into an instance of AbstractSessionHandler. As it doesn’t seem to be the case maybe I’m misunderstanding something 🤔

The SessionHandlerProxy always has been documented as an extension point (like in https://symfony.com/doc/current/session.html#session-proxies). I don’t know if it used to work at some point, but now doing as documented results in a ServiceCircularReferenceException because the framework.session.handler_id service is aliased by session.handler, which is aliased by SessionHandlerInterface (you can fix this issue by wiring your wrapped handler yourself though). Also by doing this you couldn’t use decorators like the MarshallingSessionHandler.

That’s why I thought you were supposed to decorate session.handler instead, which requires less configuration but more boilerplate code to proxy all of SessionHandlerInterface, SessionUpdateTimestampHandlerInterface (and SessionIdInterface?) methods.

@nicolas-grekas nicolas-grekas added ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" and removed ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" labels Oct 16, 2023
@nicolas-grekas nicolas-grekas dismissed their stale review October 20, 2023 07:14

discussion still open

@MatTheCat MatTheCat force-pushed the session_id_interface branch from 615fd49 to 2aef7e6 Compare November 7, 2023 15:07
@nicolas-grekas nicolas-grekas modified the milestones: 6.4, 7.1 Nov 15, 2023
@MatTheCat
Copy link
Contributor Author

Closing, since there already is a way to configure a SessionIdInterface handler.

@MatTheCat MatTheCat closed this Feb 2, 2024
@MatTheCat MatTheCat deleted the session_id_interface branch February 2, 2024 18:32
@jdevinemt
Copy link

I have been struggling for most of the day trying to figure out why the create_sid() method was never being called from my custom session handler. I finally found it was because even though I am specifying a class that implements \SessionHandlerInterface, \SessionIdInterface, \SessionUpdateTimestampHandlerInterface as the framework.session.handler_id value, it is being replaced/proxied by the \Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy class. Which, as mentioned in this PR does not implement the \SessionIdInterface.

I think it would be beneficial to reconsider implementing this.

@MatTheCat Is right that you can decorate the SessionHandlerProxy to implement \SessionIdInterface. But I think it is more straightforward to have the \SessionIdInterface implemented in SessionHandlerProxy as initially submitted in this PR. Then we have an implementation of SessionHandlerProxy that handles all possible PHP session interfaces, which could help prevent the assumptions that having a handler with \SessionIdInterface being wrong.

If it is decided that it's best not to implement this, we may want to consider deprecating passing a service that does not extend SessionHandlerProxy as a value to framework.session.handler_id , or at least update the documentation to discourage using a handler that isn't an instance of that class.

@jdevinemt
Copy link

The SessionHandlerProxy always has been documented as an extension point (like in https://symfony.com/doc/current/session.html#session-proxies). I don’t know if it used to work at some point, but now doing as documented results in a ServiceCircularReferenceException because the framework.session.handler_id service is aliased by session.handler, which is aliased by SessionHandlerInterface (you can fix this issue by wiring your wrapped handler yourself though). Also by doing this you couldn’t use decorators like the MarshallingSessionHandler.

This is another big reason that this PR should be reconsidered. It's awkward to work around the current implementation due to the circular dependency @MatTheCat mentioned above. You have to either have two classes, one for the majority of the custom handler implementation that implements \SessionHandlerInterface and \SessionUpdateTimestampHandlerInterface. And another class that extends SessionHandlerProxy and implements \SessionIdInterface. Then you have to explicitly wire the main handler to the proxied handler doing something like this:

framework:
  session:
    enabled: true
    storage_factory_id: session.storage.factory.native
    handler_id: App\SessionHandlerProxy

services:
  App\SessionHandlerProxy:
    arguments:
      $handler: App\SessionHandler

You could implement all the handler functionality to the App\SessionHandlerProxy, but it still needs a \SessionHandlerInterface in it's constructor. You could pass something like the native handler, but then if you forget to override on of the session handler methods, it would defer to that handler, which just adds confusion and may cause unexpected behavior.

@MatTheCat
Copy link
Contributor Author

Hey @jdevinemt 👋

Glad to see you concerned, but closed PRs don't usually generate traction; opening an issue may be better.

@jdevinemt
Copy link

Thanks @MatTheCat. I had a feeling that might be the case. I just finished my implementation to work around this restriction in my current project. I'm working through writing tests to cover my handler and handler proxy services. Once I'm done with that I'll open a new issue and create a PR if I can figure out the best way to implement this interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Symfony Session Handlers should implement SessionIdInterface interface
6 participants