Conversation
knstvk
marked this pull request as draft
September 21, 2026 10:47
- Preserve enclosing authentication scopes when replacing contexts - Install recipient authentication inside queued UI callbacks - Clear unused worker contexts after asynchronous tasks - Add regression tests for nested wrappers and thread cleanup
glebfox
approved these changes
Sep 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a privilege escalation in
SystemAuthenticator:begin()/end()modified theSecurityContextinstance shared by all threads of an HTTP session, so awithSystemblock in a background task made concurrent UI requests of the same session run assystem, and two overlapping blocks could leave the session assystemuntil logout. Authentication switches now affect the current thread only. Closes #5693.What was done
SystemAuthenticator.begin()now installs a newSecurityContextfor the current thread andend()reinstalls the previous instance. The previously current context is never modified (modulecore).ThreadSecurityContextOverride, an optional capability of aSecurityContextHolderStrategythat letsSystemAuthenticatorpush a context that takes precedence for the current thread (modulecore), andSecurityContextHelper.installContext()/restoreContext()as the shared way to switch and restore a thread's context.JmixSecurityContextHolderStrategy(moduleflowui), which wraps Vaadin'sVaadinAwareSecurityContextHolderStrategyand implements the override. It is registered byFlowuiAutoConfigurationas theSecurityContextHolderStrategybean, so Vaadin's own bean backs off and Vaadin's initializer installs the Jmix one.UiAsyncTaskswrappers (DelegatingSecurityRunnable,DelegatingSecuritySupplier),BackgroundWorkerImplandJmixOfficeIntegrationno longer share or modify the session's context instance. Background task progress and done handlers always run under the authentication the task was started with.UiEventPublisherruns handlers in a recipient's session under the security context stored in that session, resolved when the queuedsession.access()command actually runs, and falls back torunWithUseronly when no context is stored.How it works
Vaadin's strategy returns the HTTP session's
SecurityContextwhenever a Vaadin session is current, and ignoressetContext(), so a plain thread-local swap would makewithSystema no-op on UI threads. The Jmix strategy keeps a per-thread stack of override contexts:getContext()returns the top of the stack when it is non-empty and delegates to Vaadin otherwise.begin()pushes a fresh context with the system or user authentication,end()pops it.setContext()inside an override replaces the top entry, so inline security wrappers keep the enclosingwithSystemscope intact, andclearContext()drops the whole stack, so the request filter and the async wrappers cannot leak an unbalancedbegin()to the next unit of work on a pooled thread. Without the Jmix strategy, for example in REST-only applications,SystemAuthenticatorfalls back tosetContext(), which is sufficient for the default thread-local strategy.How to use
No changes are required in applications.
SystemAuthenticator.withSystem(),withUser(),begin()andend()keep their API and now behave as documented, affecting the current thread only.Compatibility
Existing applications are not affected unless they define their own
SecurityContextHolderStrategybean, in which case the Jmix bean is not registered (@ConditionalOnMissingBean) andSystemAuthenticatorfalls back to plainsetContext().SecurityContextHelper.setAuthentication()still modifies the current context instance for its existing callers; its javadoc now warns about that and points toSystemAuthenticator.