Skip to content

Fail fast when spring-security-access is missing - #19460

Merged
jzheaux merged 2 commits into
spring-projects:7.0.xfrom
jyx-07:gh-19441
Jul 31, 2026
Merged

Fail fast when spring-security-access is missing#19460
jzheaux merged 2 commits into
spring-projects:7.0.xfrom
jyx-07:gh-19441

Conversation

@jyx-07

@jyx-07 jyx-07 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #19441.

spring-security-config's deprecated legacy method-security support throws a raw NoClassDefFoundError at startup instead of a clear error when spring-security-access isn't on the classpath.

Root cause

#17847 moved MethodSecurityMetadataSourceAdvisor and MethodSecurityInterceptor from spring-security-core (a mandatory dependency of spring-security-config) into the new spring-security-access module, which spring-security-config only depends on optionally. Several deprecated method-security paths still construct these types unconditionally:

  • GlobalMethodSecuritySelectorMethodSecurityMetadataSourceAdvisorRegistrar (proxy mode) and GlobalMethodSecurityConfiguration (imported for both proxy and aspectj mode)
  • ReactiveMethodSecuritySelectorReactiveMethodSecurityConfiguration (@EnableReactiveMethodSecurity(useAuthorizationManager = false))

@EnableMethodSecurity and @EnableReactiveMethodSecurity's default mode — the non-deprecated replacements — never reference these classes and are unaffected.

Fix

Added a ClassUtils.isPresent(...) guard (the same pattern already used for other optional dependencies in these selectors) so the legacy paths fail fast with a clear IllegalStateException naming the missing dependency, instead of a NoClassDefFoundError deep in Spring's configuration-processing machinery.

Chose this over making spring-security-access mandatory again, since that would silently reintroduce the footprint #17847 removed for the majority of apps using @EnableMethodSecurity. @EnableGlobalMethodSecurity stays deprecated; this adds no new investment in it beyond a clear diagnostic.

Testing

Added Gh19441Tests, using the existing @ClassPathExclusions harness to simulate spring-security-access being absent:

  • @EnableMethodSecurity and @EnableReactiveMethodSecurity default mode start cleanly (locks in that the modern paths are unaffected).
  • @EnableGlobalMethodSecurity in proxy mode, aspectj mode, and @EnableReactiveMethodSecurity(useAuthorizationManager = false) all now fail with the clear message instead of NoClassDefFoundError/ClassNotFoundException.

Full spring-security-config suite passes (3640 tests; the only 3 failures are pre-existing, locale-related, and unrelated to this change). ./gradlew :spring-security-config:check passes.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 20, 2026
@jyx-07 jyx-07 changed the title Guard legacy method security for missing access Fail fast when spring-security-access is missing Jul 20, 2026
jyx-07 and others added 2 commits July 31, 2026 14:36
The "Move Core Access API" refactoring (spring-projectsgh-17847) relocated
MethodSecurityMetadataSourceAdvisor and MethodSecurityInterceptor
from spring-security-core, a mandatory dependency of
spring-security-config, into the new spring-security-access module,
which spring-security-config only depends on optionally.

GlobalMethodSecuritySelector (backing the deprecated
@EnableGlobalMethodSecurity) and ReactiveMethodSecuritySelector
(backing @EnableReactiveMethodSecurity(useAuthorizationManager =
false)) still unconditionally import configuration that constructs
those classes: MethodSecurityMetadataSourceAdvisorRegistrar in proxy
mode, GlobalMethodSecurityConfiguration in both proxy and aspectj
mode, and ReactiveMethodSecurityConfiguration for the legacy reactive
path. Applications that use any of these deprecated configuration
paths without explicitly adding spring-security-access now fail at
startup with a confusing NoClassDefFoundError deep inside Spring's
configuration-processing machinery, instead of an actionable message.

@EnableMethodSecurity and @EnableReactiveMethodSecurity's default
(AuthorizationManager-based) mode, the non-deprecated replacements,
never reference these classes and are unaffected either way.

Add a ClassUtils.isPresent check to both selectors so that, whenever
a legacy configuration path that needs it is chosen (proxy mode,
aspectj mode, or the legacy reactive interceptor), a missing
spring-security-access dependency now fails fast with a clear
IllegalStateException that names the missing dependency and points
to the supported alternative, rather than a NoClassDefFoundError.

This preserves spring-projectsgh-17847's footprint-reduction intent: the check only
runs for the deprecated legacy annotations, so the majority of
applications using @EnableMethodSecurity see no change in behavior or
dependencies. @EnableGlobalMethodSecurity remains deprecated; this
change adds no new investment in it beyond giving existing users of
it a clear diagnostic instead of a confusing crash.

Closes spring-projectsgh-19441

Signed-off-by: jyx-07 <s25069@gsm.hs.kr>
This commit adds an IllegalStateException guard when spring-security-access
is missing and the application is using @EnableGlobalMethodSecurity with
jsr250Enabled.

Issue spring-projectsgh-19441

Signed-off-by: Josh Cummings <3627351+jzheaux@users.noreply.github.com>
@jzheaux jzheaux added this to the 7.0.7 milestone Jul 31, 2026
@jzheaux
jzheaux changed the base branch from main to 7.0.x July 31, 2026 21:36
@jzheaux

jzheaux commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the contribution, @jyx-07!

Note I've rebased this onto 7.0.x since I've confirmed the bug there as well.

Regarding the solution, the IllegalStateException is an improvement, thank you. I've adjusted the PR to place the checks closer to the problematic code itself. The reason is that the boolean logic originally proposed was missing a check for jsr250Enabled, something else that also requires spring-security-access — which is a hint that we should reuse the existing boolean logic instead of replicating it. I've also removed the comment, since moving the behavior into a separate method makes the code self-documenting. I also moved the ClassUtils check in order to play nicely with Framework's AOT support. I also added a test for jsr250Enabled to make sure we have that covered.

@jzheaux
jzheaux merged commit 1eef373 into spring-projects:7.0.x Jul 31, 2026
7 checks passed
@jzheaux

jzheaux commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Thanks, @jyx-07, for the PR! This is now merged into 7.0.x and main and will go out in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NoClassDefFoundError: MethodSecurityMetadataSourceAdvisor missing from spring-security-core 7.1.0 but still referenced by spring-security-config

3 participants