spring-projects / spring-projects/spring-security
feature: improve Spring Session and SecurityContextHolder ingration by exposing SecurityContextRepository as a bean
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.6k
- Forks
- 6.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 52
Description
Expected Behavior
I want to be able to save the security context to the session reliably (meaning - the same way it is being read, so i dont have to keep two things manually in sync).
Current Behavior
you have several options on how to do this, one is deprecated:
http.securityContext(s -> s.requireExplicitSave(false));
this is bad because it relies on a deprecated class SecurityContextPersistenceFilter, which seems to be explained why it is deprecated in the new class: SecurityContextHolderFilter: "This improves the efficiency and provides better flexibility by allowing different authentication mechanisms to choose individually if authentication should be persisted."
Sure, lets lean into this motivation and really provide better flexibility.
Ok, so i want to pull the same SecurityContextRepository into my controller as is used by spring security. it is created in org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer#init, where we have HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository(); where it is wrapped in a delegating implementation of that interface and then set as a shared object on the HttpSecurityBuilder: http.setSharedObject(SecurityContextRepository.class, defaultRepository);
then we go from SessionManagementConfigurer to SecurityContextConfigurer, and we see this code:
SecurityContextRepository getSecurityContextRepository() {
SecurityContextRepository securityContextRepository = getBuilder()
.getSharedObject(SecurityContextRepository.class);
if (securityContextRepository == null) {
securityContextRepository = new DelegatingSecurityContextRepository(
new RequestAttributeSecurityContextRepository(), new HttpSessionSecurityContextRepository());
}
return securityContextRepository;
}
which will create an uncustomized HttpSessionSecurityContextRepository (at least not the way it would be customized in the SessionManagementConfigurer) and it is not saved anywhere.
From the perspective of someone trying to get a correctly/consistently configured SecurityContextRepository (well, in my case - i wanted it to be a session based one, since i have spring-session on my classpath for this project, this is a small nightmare.
What is the framework's intended way forward here?
rant...
hopefully it is not to create a custom filter and just stay away from spring security? I've only ever used it for basic stuff like jwt auth and pure client side spa, i'm trying to do something relatively advanced (basic session reading and writing with SecurityContextHolder) - learning maybe spring security not as useful/mature as i thought.Context
here is the session management configurer:
@Override
public void init(H http) {
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
boolean stateless = isStateless();
if (securityContextRepository == null) {
if (stateless) {
http.setSharedObject(SecurityContextRepository.class, new RequestAttributeSecurityContextRepository());
this.sessionManagementSecurityContextRepository = new NullSecurityContextRepository();
}
else {
HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository();
httpSecurityRepository.setDisableUrlRewriting(!this.enableSessionUrlRewriting);
httpSecurityRepository.setAllowSessionCreation(isAllowSessionCreation());
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
httpSecurityRepository.setTrustResolver(trustResolver);
}
this.sessionManagementSecurityContextRepository = httpSecurityRepository;
DelegatingSecurityContextRepository defaultRepository = new DelegatingSecurityContextRepository(
httpSecurityRepository, new RequestAttributeSecurityContextRepository());
http.setSharedObject(SecurityContextRepository.class, defaultRepository);
}
}
else {
this.sessionManagementSecurityContextRepository = securityContextRepository;
}
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache == null) {
if (stateless) {
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
}
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy(http));
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read SessionManagementConfigurer.init and SecurityContextConfigurer.getSecurityContextRepository first, comparing their shared-object setup and fallback behavior. Done should be a clearly specified, consistently configured SecurityContextRepository available to application code without manual synchronization, with session and stateless paths behaving consistently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- authentication, backend, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100