Skip to content

Auto-exclude conflicting Spring Boot security auto-configurations#1205

Open
jamesfredley wants to merge 5 commits intoapache:7.0.xfrom
jamesfredley:fix/auto-exclude-security-autoconfig
Open

Auto-exclude conflicting Spring Boot security auto-configurations#1205
jamesfredley wants to merge 5 commits intoapache:7.0.xfrom
jamesfredley:fix/auto-exclude-security-autoconfig

Conversation

@jamesfredley
Copy link
Contributor

@jamesfredley jamesfredley commented Feb 17, 2026

Summary

Adds SecurityAutoConfigurationExcluder implementing AutoConfigurationImportFilter to automatically exclude 7 Spring Boot security auto-configuration classes that conflict with the Grails Spring Security plugin. This eliminates the manual spring.autoconfigure.exclude entries that every Grails 7 user currently must add to application.yml.

Feature Description

The plugin README documents that Grails 7 requires 7 manual spring.autoconfigure.exclude entries:

spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
      - org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
      - org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
      - org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration
      - org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration
      - org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
      - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration

These exclusions are always required — not conditional or environment-specific. This boilerplate is easy to miss, hard to debug when forgotten, and should be handled automatically by the plugin.

Implementation

Approach: AutoConfigurationImportFilter SPI (stable since Spring Boot 1.5.0, used in 3.x)

Why AutoConfigurationImportFilter over alternatives

Approach Drawback
EnvironmentPostProcessor spring.autoconfigure.exclude is a List — property sources cannot merge lists reliably (Spring Boot #41669). User's own exclusions would be overwritten.
@EnableAutoConfiguration(exclude=...) on plugin class Plugin uses @Grails annotation, can't also use @EnableAutoConfiguration
Documentation-only (current approach) Every user must copy 7 YAML lines; easy to miss
AutoConfigurationImportFilter ✓ Runs before bytecode is loaded (faster)
✓ Opt-out via excludeSpringSecurityAutoConfiguration: false
✓ No property merging issues
✓ Used by established libraries (Redis OM Spring, TCC Transaction)

Files Changed

File Change
SecurityAutoConfigurationExcluder.groovy NEWAutoConfigurationImportFilter implementation that returns false for the 7 conflicting auto-configurations
META-INF/spring.factories NEW — Registers the filter via SPI (filters still use spring.factories in Spring Boot 3.x, not .imports)
build.gradle Added compileOnly 'org.springframework.boot:spring-boot-autoconfigure' — always available at runtime in any Grails app
SecurityAutoConfigurationExcluderSpec.groovy NEW — 18 Spock tests covering all exclusions, preservation of non-security configs, mixed arrays, edge cases, and spring.factories registration

Test Coverage (18 tests, all pass)

  • 7 data-driven tests: each excluded auto-configuration is filtered out
  • 5 data-driven tests: non-security auto-configurations pass through
  • 1 test: mixed array of included/excluded classes
  • 1 test: empty array
  • 1 test: null metadata parameter
  • 1 test: all 7 known classes present in the exclusion set
  • 1 test: exclusion set is unmodifiable
  • 1 test: spring.factories registration is correct

Backward Compatibility

  • Users who already have manual exclusions in their application.yml are unaffected — the filter and manual exclusions are independent mechanisms
  • No behavioral change for existing functionality
  • spring-boot-autoconfigure is added as compileOnly only — no new runtime dependency (it's always already present via Spring Boot starter)

Example Application

https://github.com/jamesfredley/grails-spring-security-autoconfig-exclusion

A minimal Grails 7.0.7 app with spring-security configured (User/Role/UserRole domains, annotation-based security) that intentionally does NOT include the manual exclusions. The /bugDemo/index endpoint shows which auto-configuration classes are on the classpath and which beans are registered.

Environment Information

  • Grails: 7.0.7
  • Spring Boot: 3.5.10
  • Groovy: 4.0.30
  • JDK: 17

Version

7.0.x

Opt-Out

Users can disable the automatic exclusion by setting the following property in application.yml:

grails:
  plugin:
    springsecurity:
      excludeSpringSecurityAutoConfiguration: false

This allows Spring Boot's security auto-configurations to run normally, for users who want to override or use Spring Boot's security setup directly. The filter implements EnvironmentAware to read this property during the auto-configuration discovery phase.

Copilot AI review requested due to automatic review settings February 17, 2026 13:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an AutoConfigurationImportFilter to the plugin so Spring Boot security auto-configurations that conflict with the Grails Spring Security plugin are automatically excluded, removing the need for users to manually maintain spring.autoconfigure.exclude entries.

Changes:

  • Introduces SecurityAutoConfigurationExcluder implementing AutoConfigurationImportFilter to filter 7 known conflicting Spring Boot auto-configurations.
  • Registers the filter via META-INF/spring.factories.
  • Adds Spock coverage for exclusion behavior and filter registration; adds spring-boot-autoconfigure as compileOnly for the SPI type.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
plugin-core/plugin/src/main/groovy/grails/plugin/springsecurity/SecurityAutoConfigurationExcluder.groovy New import filter that excludes conflicting Spring Boot security auto-configurations.
plugin-core/plugin/src/main/resources/META-INF/spring.factories SPI registration for the new auto-config import filter.
plugin-core/plugin/build.gradle Adds spring-boot-autoconfigure as compileOnly to compile against the SPI.
plugin-core/plugin/src/test/groovy/grails/plugin/springsecurity/SecurityAutoConfigurationExcluderSpec.groovy New Spock spec validating filtering behavior and SPI registration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add SecurityAutoConfigurationExcluder implementing AutoConfigurationImportFilter
to automatically exclude 7 Spring Boot security auto-configuration classes that
conflict with the Grails Spring Security plugin.

Previously, every Grails 7 user had to manually add spring.autoconfigure.exclude
entries to application.yml (documented in README). This filter eliminates that
requirement by filtering them out during Spring Boot's auto-configuration
discovery phase, before bytecode is loaded.

Excluded auto-configurations:
- SecurityAutoConfiguration
- SecurityFilterAutoConfiguration
- UserDetailsServiceAutoConfiguration
- OAuth2ClientAutoConfiguration (2 packages)
- OAuth2ResourceServerAutoConfiguration
- ManagementWebSecurityAutoConfiguration

Implementation:
- SecurityAutoConfigurationExcluder.groovy — the filter
- META-INF/spring.factories — SPI registration
- build.gradle — compileOnly spring-boot-autoconfigure
- SecurityAutoConfigurationExcluderSpec — 18 Spock tests
@jamesfredley jamesfredley force-pushed the fix/auto-exclude-security-autoconfig branch from 5dc44fb to a783a42 Compare February 17, 2026 14:38
@jamesfredley jamesfredley self-assigned this Feb 19, 2026
@jamesfredley jamesfredley moved this to In Progress in Apache Grails Feb 19, 2026
@jamesfredley
Copy link
Contributor Author

related to apache/grails-core#15405, which needs exclusions also

Copy link
Contributor

@jdaugherty jdaugherty left a comment

Choose a reason for hiding this comment

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

How do you opt out of this? What if you want to override it?

Users can now disable the automatic exclusion of Spring Boot security
auto-configurations by setting:

  grails.plugin.springsecurity.excludeSpringSecurityAutoConfiguration: false

in application.yml. The filter implements EnvironmentAware so it reads
the property during the auto-configuration discovery phase. Defaults to
true (exclusions active) for backward compatibility.

Assisted-by: Claude Code <Claude@Claude.ai>
Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley
Copy link
Contributor Author

Addressed - the filter now implements EnvironmentAware and checks a property to allow opting out:

grails:
  plugin:
    springsecurity:
      excludeSpringSecurityAutoConfiguration: false

Defaults to true (exclusions active). Setting it to false disables the filter entirely and lets all Spring Boot security auto-configurations through - for users who want to override or use Spring Boot's security setup directly.

Also updated the README to document both the automatic behavior and the opt-out.

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley jamesfredley force-pushed the fix/auto-exclude-security-autoconfig branch from 34b806b to 6588157 Compare February 19, 2026 14:53
@jamesfredley jamesfredley dismissed jdaugherty’s stale review February 19, 2026 14:57

Added opt out mechanism

thrown(UnsupportedOperationException)
}

def "match allows all auto-configurations when disabled via environment property"() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should an actual functional test for this. I'm pretty sure this coudl be broken, but it may only be in edge cases with plugin's having configuration instead of the end app.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added in 9656c948:

  1. Integration test in the plugin repo (SecurityAutoConfigurationExcluderIntegrationSpec) - runs in the core-examples-integration-test-app with the full Grails context. Verifies the excluder is on the classpath, SecurityAutoConfiguration and SecurityFilterAutoConfiguration beans are NOT registered, no duplicate SecurityFilterChain beans, and only the plugin's UserDetailsService is active. All 5 assertions pass.

  2. External sample app with two integration test specs:

    • SecurityAutoConfigExclusionSpec (6 tests) - proves auto-configs are excluded by default
    • SecurityAutoConfigOptOutDisabledSpec (1 test) - proves setting excludeSpringSecurityAutoConfiguration: false lets SecurityAutoConfiguration through (confirming the EnvironmentAware opt-out works)

    App: https://github.com/jamesfredley/grails-spring-security-autoconfig-exclusion (uses locally-built 7.0.2-SNAPSHOT from this PR branch via mavenLocal())

Copy link
Contributor

Choose a reason for hiding this comment

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

we have example apps in the srpign security repo, why not import it here?

…iguration property

Add SecurityAutoConfigurationExcluderIntegrationSpec to verify the
auto-configuration exclusion filter works in a full Grails context.
Add the excludeSpringSecurityAutoConfiguration property to the
miscProperties reference table.

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley jamesfredley dismissed jdaugherty’s stale review February 19, 2026 19:26

Commit pushed with changes

Copy link
Contributor

@jdaugherty jdaugherty left a comment

Choose a reason for hiding this comment

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

I'm glad to see it working, wecan merge this. I'd prefer we just import a functional test app here though.

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

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants

Comments