Skip to content
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

Session Creation Policy with Webflux Security #6552

Closed
tine2k opened this issue Feb 22, 2019 · 23 comments
Closed

Session Creation Policy with Webflux Security #6552

tine2k opened this issue Feb 22, 2019 · 23 comments
Labels
in: web An issue in web modules (web, webmvc)

Comments

@tine2k
Copy link

tine2k commented Feb 22, 2019

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.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 7, 2019
@Xarvalus
Copy link

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.

@rwinch
Copy link
Member

rwinch commented May 15, 2019

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 rwinch added status: waiting-for-feedback We need additional information before we can continue in: web An issue in web modules (web, webmvc) and removed status: waiting-for-triage An issue we've not yet triaged labels May 15, 2019
@Xarvalus
Copy link

@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.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels May 15, 2019
@rwinch
Copy link
Member

rwinch commented May 17, 2019

WebFlux works differently that the imperative equivalent. This means that JWT does not create a session on authentication by default.

@rwinch rwinch added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels May 17, 2019
@Xarvalus
Copy link

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.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels May 17, 2019
@rwinch
Copy link
Member

rwinch commented May 20, 2019

Can you please provide a sample that reproduces the issue?

@rwinch rwinch added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels May 20, 2019
@spring-projects-issues
Copy link

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.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label May 27, 2019
@spring-projects-issues
Copy link

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.

@spring-projects-issues spring-projects-issues removed status: waiting-for-feedback We need additional information before we can continue status: feedback-reminder We've sent a reminder that we need additional information before we can continue labels Jun 3, 2019
@msassak
Copy link

msassak commented Jul 23, 2019

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

@rwinch
Copy link
Member

rwinch commented Jul 23, 2019

What makes you believe this is a Spring Security issue vs WebSessionManager (Spring issue) or a Gateway issue?

@msassak
Copy link

msassak commented Jul 23, 2019

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.

gateway-webflux-session-2.zip

@rwinch
Copy link
Member

rwinch commented Jul 26, 2019

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:

  • 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());

@msassak
Copy link

msassak commented Aug 7, 2019

Thanks @rwinch! This solves the issue for me.

@DarrenJiang1990
Copy link

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

@lyoumi
Copy link

lyoumi commented Oct 4, 2019

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.

@sanjayobsidiam
Copy link

Is this the reason behind my all requests are getting unauthorized response only the first request is fine?

@cash1981
Copy link

@spring-issuemaster Enough information has been issued imo to reopen this

@borisgalitsky
Copy link

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?

@rwinch
Copy link
Member

rwinch commented Mar 4, 2020

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).

@dgempiuc
Copy link

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.

@luqmanulkhair
Copy link

@DarrenJiang1990 Does this mechanism also works with oauth2login()?

@DarrenJiang1990
Copy link

@DarrenJiang1990 Does this mechanism also works with oauth2login()?

no, token must be stored in oauth2 server

@svankamamidi
Copy link

svankamamidi commented Mar 19, 2024

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:

  • 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();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web An issue in web modules (web, webmvc)
Projects
None yet
Development

No branches or pull requests