Skip to content

Conversation

@heruan
Copy link
Member

@heruan heruan commented Jun 6, 2025

This fixes #21401 by providing a SecurityContextHolderStrategy bean as part of Spring Security auto-configuration and replaces static invocations of SecurityContextHolder.getContext() by using the strategy bean instead.

  • Provide SecurityContextHolderStrategy in SpringSecurityAutoConfiguration
  • Remove conflicting VaadinAwareSecurityContextHolderStrategyConfiguration
  • Set the strategy on filters during VaadinSecurityConfigurer build lifecycle
  • Set the strategy statically when using VaadinWebSecurity for backwards compatibility
  • Inject the strategy bean in AuthenticationContext and SpringAccessPathChecker
  • Deprecate constructors that obtain the strategy statically
  • Avoid static access in AuthenticationUtil methods
  • Update tests

Breaking changes

  • VaadinAwareSecurityContextHolderStrategyConfiguration has been removed — mild since it was purely for internal use
  • SpringSecurityAutoConfiguration::accessPatchChecker signature has changed to include the strategy parameter — mild since this class shouldn't be extended (better have package-private bean methods)
  • Applications that have set a custom strategy statically after VaadinAwareSecurityContextHolderStrategyConfiguration might expect that custom strategy to be used by Flow, instead of the bean — those apps should now provide the custom strategy as a bean (if they expect Flow to use it)

DRAFT Tests setting the strategy statically must be updated (some already are)

@heruan heruan self-assigned this Jun 6, 2025
@github-actions
Copy link

github-actions bot commented Jun 6, 2025

Test Results

1 281 files  ± 0  1 281 suites  ±0   1h 17m 14s ⏱️ -1s
8 877 tests + 1  8 810 ✅ + 1  67 💤 ±0  0 ❌ ±0 
9 322 runs   - 12  9 247 ✅  - 10  75 💤  - 2  0 ❌ ±0 

Results for commit 0e328e8. ± Comparison against base commit ee5139e.

♻️ This comment has been updated with latest results.

@mshabarov mshabarov requested a review from mcollovati June 9, 2025 11:35
@mcollovati mcollovati force-pushed the feat/security-context-strategy-bean branch from 95f2ac4 to 06f63c2 Compare June 17, 2025 06:17
@sonarqubecloud
Copy link

* @param evaluator
* evaluator to check path permissions.
* @deprecated Use
* {@link #SpringAccessPathChecker(WebInvocationPrivilegeEvaluator, String)}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* {@link #SpringAccessPathChecker(WebInvocationPrivilegeEvaluator, String)}
* {@link #SpringAccessPathChecker(SecurityContextHolderStrategy, WebInvocationPrivilegeEvaluator)}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add a note mentioning usage of SecurityContextHolder#getContextHolderStrategy() in the deprecated constructors to explain the deprecation (similar to AuthenticationContext)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should just remove the @Configuration annotation and deprecate the class for 24.8

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that would be better. I initially removed the class to see what failed without it, but we can keep it and deprecate before complete removal.

@mcollovati mcollovati force-pushed the feat/security-context-strategy-bean branch from 06f63c2 to 5eb99f8 Compare October 6, 2025 08:38
@mcollovati mcollovati changed the title Obtain SecurityContext from the SecurityContextHolderStrategy bean refactor: Obtain SecurityContext from the SecurityContextHolderStrategy bean Oct 8, 2025
@mcollovati mcollovati force-pushed the feat/security-context-strategy-bean branch from 9d38154 to 4d566a5 Compare October 8, 2025 05:49
@mcollovati
Copy link
Collaborator

One missing part: restore and deprecate VaadinAwareSecurityContextHolderStrategyConfiguration
This PR can be revised after VaadinWebSecurity removal gets merged.

@CLAassistant
Copy link

CLAassistant commented Oct 22, 2025

CLA assistant check
All committers have signed the CLA.

@sonarqubecloud
Copy link

Comment on lines +217 to +225
// Ensure AuthenticationUtil is wired to whichever
// SecurityContextHolderStrategy bean is in use,
// even if a custom one is provided by the application.
@Bean
SmartInitializingSingleton securityContextHolderStrategyInitializer(
SecurityContextHolderStrategy securityContextHolderStrategy) {
return () -> AuthenticationUtil.setSecurityContextSupplier(
securityContextHolderStrategy::getContext);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This defeats the purpose of having the strategy as a bean. This PR makes sense only by removing all static methods for security.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strategy bean enables to have a different strategies for different scopes (in the same thread). Setting a static accessor opens to the risk of using the wrong strategy if the method is called on a scope where the expected strategy is different.

To keep backwards compatibility, apps that want to use static access could still use SecurityContextHolder.getContext() by explicitly setting the strategy statically.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand your point. AuthenticationUtil takes a Supplier<SecurityContext> so any time this is used it should call securityContextHolderStrategy.getContext(), where securityContextHolderStrategy is the defined bean.
What am I missing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is that the bean instance could be different during runtime, while here we statically set that specific securityContextHolderStrategy bean instance. This is equivalent to

SecurityContextHolder.setContextHolderStrategy(securityContextHolderStrategy)

and then obtain the context statically with SecurityContextHolder.getContext().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is SmartInitializingSingleton evaluated every time based on the current context?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SecurityContextHolder.setContextHolderStrategy(securityContextHolderStrategy)

And how is this different from new AuthenticationContext(securityContextHolderStrategy) or new SpringAccessPathChecker(securityContextHolderStrategy, evaluator, vaadinProperties.getUrlMapping())?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those other beans are created explicitly with that instance: if the developer wants to provide their own bean, they explicitly pass the strategy they need.

The problem with static methods is that you don't have much control of what they return and using them in different contexts/scopes might result in unexpected instances.

If we want to keep support for static access to the security context, then better stick with

SecurityContextHolder.setContextHolderStrategy(securityContextHolderStrategy)

called somewhere, but I think that should be a choice on the app side.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, but I'm not sure if we can completely get rid of static methods in AuthenticationUtil.
What about a temporary workaround, like:

  • add a constructor to AuthenticationUtil that gets SecurityContextHolderStrategy and sets it to the static field
  • expose AuthenticationUtil as a bean with @ConditionalOnMissingBean
  • if the developer needs, it can override the bean provide the required strategy

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't introduce a temporary workaround at this point. Let's split this change in multiple steps, maybe removing the separate configuration for the strategy bean and set it statically allowing the user to provide their own.

@heruan
Copy link
Member Author

heruan commented Nov 14, 2025

Closing this in favor of an incremental approach and a proper deprecation cycle of the static accessor to the holder strategy, with #22745 as a starting point.

@heruan heruan closed this Nov 14, 2025
@github-project-automation github-project-automation bot moved this from 🔎Iteration reviews to Done in Vaadin Flow | Hilla | Kits ongoing work Nov 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Development

Successfully merging this pull request may close these issues.

Refactor Spring utilities to avoid static access to SecurityContextHolder

5 participants