-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
Stateless SessionPolicy not applied to SecurityFilterChain when used with CustomDsl #13840
Comments
@bwgjoseph thanks for the report. However, it's somewhat difficult to tell whether your report is simply a mis-configuration, a misunderstanding, or a bug. The For that reason, it feels like this is a question that would be better suited to Stack Overflow. We prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add a minimal sample that reproduces this issue if you feel this is a genuine bug. Having said that, please see this comment for some context. I'm going to close this issue for now. However, if you can provide a sample that points to an issue with configuring a custom DSL specifically (and not a mis-configuration), we can re-open. |
Hi @sjohnr, thanks for the response. I do believe it is a bug, so I took some time to make the reproduce repo. As I am seeing differing behavior when used (stateless session management) with and without custom dsl. Also, I'm not sure if I fully understand (as I'm still new to spring-security) what you explained in here, and I do think it might be a different issue. But I like to say that this has nothing to do with In my custom dsl, I have the following configuration public class DummyDsl extends AbstractHttpConfigurer<DummyDsl, HttpSecurity> {
@Override
public void init(HttpSecurity http) throws Exception {
http
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
}
public static DummyDsl dummyDsl() {
return new DummyDsl();
}
public HttpSecurity build() {
return super.getBuilder();
}
} Which is configured in public class WebSecurityConfig {
@Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http, RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter) throws Exception {
return http
.addFilter(requestHeaderAuthenticationFilter)
.build();
}
} I do expect that the configuration for Scenario 1When I run using the above configuration, this is the logs
click to view logs
It's the first time running, so it is attempting authentication, then it stores into If I were to run the same request again
Can see that it's not authenticating again, but retrieved from the context. Scenario 2The only delta here is that I am also configuring the public class WebSecurityConfig {
@Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http, RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter) throws Exception {
return http
.addFilter(requestHeaderAuthenticationFilter)
// i'm expecting that i should not need to add this line as it is configured in custom dsl
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}
} With the above configuration, I ran the same http call click to view logs
So this authenticates, and also stores into context which seem correct to me But, if I were to run the http call again. It will attempt to authenticate again, instead of retrieving from the store.
Again, this could be my limited understading on spring-security. So do point out if I am missing something obvious. Am also happy to provide more information / clarification if necessary. Thank you for looking into this! update: wanted to add on this Based on the session-management-docs, it states that using public class DummyDsl extends AbstractHttpConfigurer<DummyDsl, HttpSecurity> {
@Override
public void init(HttpSecurity http) throws Exception {
http
.securityContext(context -> context.securityContextRepository(new NullSecurityContextRepository));
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
}
// omitted
} If I define |
@bwgjoseph thanks for following up with the sample. I have reviewed your sample, and I do see that the behavior is slightly different when applying the The reason it's difficult to spot any obvious bugs in that your configuration and expectations around session management seem incorrect, and don't take into account what I discussed in the linked comment:
In the case of My best guess as to what you should be doing instead is:
This configuration is simpler, avoids use of One final note: As I mentioned in the other issue, I do believe updates to the documentation are needed here, so that ticket will remain open. |
Thanks for the explanation, I think I'm having a better idea w.r.t I went into 023-10-04T00:50:00.282+08:00 TRACE 7204 --- [nio-9999-exec-1] o.s.s.authentication.ProviderManager : Authenticating request with MyPreAuthenticationProvider (1/1)
2023-10-04T00:50:00.285+08:00 DEBUG 7204 --- [nio-9999-exec-1] .w.a.p.RequestHeaderAuthenticationFilter : Authentication success: PreAuthenticatedAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=bwgjoseph, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[RW]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[RW]]
2023-10-04T00:50:00.438+08:00 WARN 7204 --- [nio-9999-exec-1] o.a.c.util.SessionIdGeneratorBase : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [140] milliseconds.
2023-10-04T00:50:00.468+08:00 INFO 7204 --- [nio-9999-exec-1] Spring Security Debugger :
************************************************************
New HTTP session created: EC039CCFFC3DBF8EBADEE88F08B08ECA
Call stack:
at org.springframework.security.web.debug.Logger.info(Logger.java:46)
at org.springframework.security.web.debug.DebugFilter$DebugRequestWrapper.getSession(DebugFilter.java:171)
at org.springframework.security.web.debug.DebugFilter$DebugRequestWrapper.getSession(DebugFilter.java:181)
at jakarta.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:221)
at jakarta.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:221)
at org.springframework.security.web.context.HttpSessionSecurityContextRepository.saveContextInHttpSession(HttpSessionSecurityContextRepository.java:169)
at org.springframework.security.web.context.HttpSessionSecurityContextRepository.saveContext(HttpSessionSecurityContextRepository.java:152)
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.successfulAuthentication(AbstractPreAuthenticatedProcessingFilter.java:221)
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doAuthenticate(AbstractPreAuthenticatedProcessingFilter.java:201)
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:142)
// omitted
2023-10-04T00:50:00.478+08:00 DEBUG 7204 --- [nio-9999-exec-1] w.c.HttpSessionSecurityContextRepository : Stored SecurityContextImpl [Authentication=PreAuthenticatedAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=bwgjoseph, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[RW]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[RW]]] to HttpSession [org.apache.catalina.session.StandardSessionFacade@2368adaa]
2023-10-04T00:50:00.481+08:00 TRACE 7204 --- [nio-9999-exec-1] o.s.security.web.FilterChainProxy : Invoking RequestCacheAwareFilter (8/11) Is this expected?
Thanks for showing this, and I do agree that this configuration is better. However, for my case, I'm not sure if the correct approach is to make custom dsl configurable from the consumer (like provide the class to custom dsl) For example, my
// example
@Bean
@ConditionalOnMissingBean
public AuthenticationManager authenticationManager(AuthenticationProvider authenticationProvider) {
return new ProviderManager(authenticationProvider);
}
@Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
requestHeaderAuthenticationFilter.setPrincipalRequestHeader("X-User");
requestHeaderAuthenticationFilter.setExceptionIfHeaderMissing(true);
requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager);
requestHeaderAuthenticationFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
RequestAttributeSecurityContextRepository securityContextRepository =
new RequestAttributeSecurityContextRepository();
requestHeaderAuthenticationFilter.setSecurityContextRepository(securityContextRepository);
return requestHeaderAuthenticationFilter;
} In this case, if I were to define public class DummyDsl extends AbstractHttpConfigurer<DummyDsl, HttpSecurity> {
@Override
public void init(HttpSecurity http) throws Exception {
http.formLogin(AbstractHttpConfigurer::disable);
// so is it ok to use this way to grab the correct bean, to set to authenticationManager?
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
AuthenticationManager authenticationManager = context.getBean(AuthenticationManager.class);
// actually i'm not sure how to grab generic type of bean from context correctly
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = context.getBean(AuthenticationDetailsSource.class);
RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
requestHeaderAuthenticationFilter.setPrincipalRequestHeader("X-User");
requestHeaderAuthenticationFilter.setExceptionIfHeaderMissing(true);
requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager);
requestHeaderAuthenticationFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
RequestAttributeSecurityContextRepository securityContextRepository =
new RequestAttributeSecurityContextRepository();
requestHeaderAuthenticationFilter.setSecurityContextRepository(securityContextRepository);
}
// omitted
}
public class WebSecurityConfig {
@Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http, RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter) throws Exception {
return http
// Authorization is added to make it clear what's intended by this filter chain
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.build();
}
// omitted
} This way, I'm still allowing users to create their own
You mentioned this, but from my perspective, if the behavior differs, wouldn't it be considered as bug, or rather requires deeper investigation (as you have pointed out it could be Hope I'm not making it more confusing, and thanks for your patience! |
If you believe you have found a bug (I currently do not), please provide a minimal sample that reproduces it. In this case, I would suggest removing anything with custom authentication, and then point to what is broken when you use the filter chain bean vs the custom DSL. Regarding all other questions, please go to stackoverflow for this. I am happy to answer questions, but this is not the place for that as I have mentioned already. |
I just ran another round of testing, and it does seem that it is a lack of understanding on my end, rather than a bug as suspected initially. Just to close it off, and hope that I got it right. It seems like the misunderstanding here (or cause of confusion) is the usage of |
Describe the bug
I can't be 100% sure, but it seems to be a bug or misconfiguration to me. I can work to try to have a reproduce if required.
I suspect that somehow if I configure
sessionManagement
in usingCustomDsl
and applied to anySecurityFilterChain
, it does not seem to have any effect.So what happens was that when I try to run any HTTP request, it seems to use
HttpSession
cache, rather than re-authenticating on per request.To Reproduce
Given the following
I have exported
DummyDsl
throughspring.factories
which is used inproject-a
, hence, all the configuration should apply, and it does (as far as I can tell for all except session). When I try any HTTP request, the logs looks likeThis is the logs when "bypassing" the authentication
So the request went through, using the previous session? I tried to change my headers, but it didn't also seem to re-authenticate.
What I have tried
Based on the docs, I could provide a
NullSecurityContextRepository
even though I think I don't have to cause I already defined usingSTATELESS
But, after setting this, it works. Now, every request does re-authenticate and doesn't use
HttpSession
(it seem).What I have also tried
Re-define
STATELESS
policy inproject-a
, and did not setsecurityContext
This also seem to work based on what I have tried
I also wanted to try
I wanted to try to setAllowSessionCreation to false (over using
NullSecurityContextRepository
), but not quite sure how to define it.Expected behavior
The expected behavior should always authenticate per request, and the logs I expect to see should be something along
Sample
I can try to submit a reproduce if required. I'm hoping that it's a rather straight-forward case of me not understanding enough, or having misconfiguration on my end than it is a bug. Please do let me know if more information is required as well.
Thanks!
The text was updated successfully, but these errors were encountered: