Closed tine2k closed 5 years ago
While seeking for currently possible solution there are some workarounds posted on StackOverflow: Disable WebSession creation when using spring-security with spring-webflux.
Involving WebSessionManager
methods overriding & manual SecurityWebFilterChain
functionality disabling.
Would be very useful to provide the similar solution based on Spring MVC's one.
Can you describe in more detail what you are trying to do (i.e. what is creating the session, if it is authentication how are you authenticating, etc) and why (i.e. why disable sessions)?
@rwinch you have detailed information on the request from @tine2k comment & from mentioned SO question link
Common scenario in Spring is to disable session creation with SessionCreationPolicy.STATELESS
when the app is using JWT.
We would love to see that possibility in Spring Webflux too, without unnecessary workarounds.
WebFlux works differently that the imperative equivalent. This means that JWT does not create a session on authentication by default.
According to OP of the SO question linkebon ~ Disable WebSession creation when using spring-security with spring-webflux it seems to not be disabled by default. Feel free to post your solution up there.
Can you please provide a sample that reproduces the issue?
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
I believe I just ran into the same issue. I was able to work around it with the info in the SO post linked from here, but I've also created a sample demonstrating what I am seeing in the hopes that we can get a fix for this (or just some enlightenment about a better solution).
The problem seems to occur when Spring Security is enabled in Spring Cloud Gateway, and a client sends a cookie named SESSION
to a service behind Cloud Gateway. The gateway forwards the session cookie as expected but Spring Security also adds a session cookie expiration header to the response, presumably because the cookie on the request is not recognized by it.
Implementing a null WebSessionManager
fixes this, but it does seem like a setting is missing, perhaps in ServerHttpSecurity
.
I've attached a zip file containing a minimal configuration for reproducing. It contains Spring Cloud Gateway with a single route that forwards requests to httpbin.org.
$ unzip gateway-webflux-session.zip
$ cd gateway-webflux-session
$ ./mvnw spring-boot:run
In another terminal, first send a request directly to httpbin:
$ curl -v -b 'SESSION=sessionid' https://httpbin.org/get?foo=bar
Note the absence of a set-cookie header in the response. Now send the identical request through the gateway:
$ curl -v -b 'SESSION=sessionid' http://localhost:8080/get?foo=bar
The response from the gateway will include this header:
set-cookie: SESSION=; Max-Age=0; Expires=Tue, 23 Jul 2019 21:55:28 GMT; Path=/; HTTPOnly
Which causes the browser to incorrectly expire the cookie.
So far as I can tell, this only occurs when the cookie is named SESSION
.
gateway-webflux-session.zip
What makes you believe this is a Spring Security issue vs WebSessionManager (Spring issue) or a Gateway issue?
Good question. I realized when you asked that I wasn't sure myself, so I took the example from my original response and removed all the dependencies on Spring Security. Sure enough, the erroneous set-cookie
header is no longer present when Spring Security has been removed. That's not proof, but it is evidence that this is caused, at least in part, by Spring Security. Of course if you believe there is a better project to file this against I will be happy to do so, and I would appreciate any pointers in that regard.
Thanks for the additional details.
The reason is that enabling Spring Security causes the WebSession
to be read. When Spring WebFlux tries to resolve the WebSession
it looks in the SESSION cookie for the id to resolve and finds that the session id is invalid. Since the session id is invalid, Spring WebFlux invalidates the SESSION cookie.
Your question might be...why is Spring Security trying to read the WebSession? First it can be helpful to understand the request cache. The request cache:
The problem is that the request cache is being invoked for every request to see if there is a value saved to replay and thus the WebSession is being looked up for every request. Since the WebSession is being looked up with an invalid session id, Spring WebFlux invalidates the SESSION cookie as described above.
I created gh-7157 to limit when the request cache is being accessed (and thus the WebSession). In the meantime if you don't need the request cache, you can disable it using:
http
.requestCache()
.requestCache(NoOpServerRequestCache.getInstance());
Thanks @rwinch! This solves the issue for me.
a final solution for session stateless (spring security with webflux) :
.and().securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
explanation: The security context in a WebFlux application is stored in a ServerSecurityContextRepository. Its WebSessionServerSecurityContextRepository implementation, which is used by default, stores the context in session. Configuring a NoOpServerSecurityContextRepository instead would make our application stateless
If I'm correct in this case spring using InMemoryWebSessionStore by default and no-one suggested solution is not fix it. I tried to apply each suggested solution, but I still have exception when sessions are more than 1000. And 1000 is hardcoded in the InMemoryWebSessionStore and you have to manually set max count instead of changing corresponding property (in the application.yaml for example). I'd don't like to write custom implementation for the WebSessionStore or WebSessionManager, so I believe that spring-team will reopen this issue and add the possibility to disable sessions.
Is this the reason behind my all requests are getting unauthorized response only the first request is fine?
@spring-issuemaster Enough information has been issued imo to reopen this
Issue is still actual. Once you handle "java.lang.IllegalStateException: Max sessions limit reached: 10000", you want to switch off sessions at all. How to do it?
These issues are different from the originally posted problem. Please create new tickets for new issues.
NOTE: If you need to scale up the number of sessions, you need to either reduce the size of your sessions or persist them in an eternal data store (i.e. using Spring Session).
i have same issue now. i delegate authentication to oauth2 server in spring cloud gateway (which uses webflux). when i login at oauth2, it returns jwt token to gateway and it is stored as session in there. but gateway must be stateless. browser request to gateway with session and gateway finds jwt according to session. it is anormal behavior.
@DarrenJiang1990 Does this mechanism also works with oauth2login()?
@DarrenJiang1990 Does this mechanism also works with oauth2login()?
no, token must be stored in oauth2 server
Thanks for the additional details.
The reason is that enabling Spring Security causes the
WebSession
to be read. When Spring WebFlux tries to resolve theWebSession
it looks in the SESSION cookie for the id to resolve and finds that the session id is invalid. Since the session id is invalid, Spring WebFlux invalidates the SESSION cookie.Your question might be...why is Spring Security trying to read the WebSession? First it can be helpful to understand the request cache. The request cache:
- When an unauthenticated user requests a page that requires authentication, the request cache saves the request (URL, HTTP Method, Headers, etc) in session
- After the user is authenticated the cache is looked up and then they are redirected to the original URL
- Every request that comes in Spring Security inspects the request cache to see if there is a value in the request cache and if the URL matches the original URL if so it replays that request (URL, HTTP Method, Headers, etc)
The problem is that the request cache is being invoked for every request to see if there is a value saved to replay and thus the WebSession is being looked up for every request. Since the WebSession is being looked up with an invalid session id, Spring WebFlux invalidates the SESSION cookie as described above.
I created gh-7157 to limit when the request cache is being accessed (and thus the WebSession). In the meantime if you don't need the request cache, you can disable it using:
http .requestCache() .requestCache(NoOpServerRequestCache.getInstance());
@rwinch above given is not working with Spring boot 3.2.3 (Spring 6) I am trying with below code. Still I see session entry created in redis cache. Am I missing anything.
public SecurityWebFilterChain configure(ServerHttpSecurity http) throws Exception {
http
.requestCache().disable()
.oauth2ResourceServer().jwt();
return http.build();
}
I am developing a reactive Spring Boot application with Spring Cloud Gateway and Spring Security using only Webflux and no Spring MVC (SB 2.1.3 and Greenwich.RELEASE).
I want my application NOT to create any session cookies. In a Spring MVC application this is achievable with
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
Is there an equivalent for Webflux Security?
ServerHttpSecurity
does not seem to offer this.