spring-projects / spring-projects/spring-security

feature: improve Spring Session and SecurityContextHolder ingration by exposing SecurityContextRepository as a bean

Open
#17,784 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage type: enhancement
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.