From f1e367f93d62df64e9f674f94549cee722334a49 Mon Sep 17 00:00:00 2001 From: CHANHAN <130114269+chanani@users.noreply.github.com> Date: Tue, 20 Jan 2026 08:43:34 +0900 Subject: [PATCH 1/4] fix missing access attribute validation in AuthorizationFilterParser Fixes gh-18503 Signed-off-by: CHANHAN <130114269+chanani@users.noreply.github.com> --- .../security/config/http/AuthorizationFilterParser.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java index 548649675f..2edf6e8f7f 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java @@ -124,6 +124,11 @@ class AuthorizationFilterParser implements BeanDefinitionParser { List interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL); for (Element interceptMessage : interceptMessages) { String accessExpression = interceptMessage.getAttribute(ATT_ACCESS); + if (!StringUtils.hasText(accessExpression)) { + parserContext.getReaderContext() + .error("access attribute cannot be empty or null", interceptMessage); + continue; + } BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder .rootBeanDefinition(WebExpressionAuthorizationManager.class); authorizationManager.addPropertyReference("expressionHandler", expressionHandlerRef); From fa87c78edb8e1cd98867634463b79053d33d4ba7 Mon Sep 17 00:00:00 2001 From: CHANHAN <130114269+chanani@users.noreply.github.com> Date: Tue, 20 Jan 2026 08:43:52 +0900 Subject: [PATCH 2/4] fix missing access attribute validation in FilterInvocationSecurityMetadataSourceParser Fixes gh-18503 Signed-off-by: CHANHAN <130114269+chanani@users.noreply.github.com> --- .../http/FilterInvocationSecurityMetadataSourceParser.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java b/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java index 8e174f18bd..442343d5ce 100644 --- a/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java +++ b/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java @@ -142,10 +142,12 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit ManagedMap filterInvocationDefinitionMap = new ManagedMap<>(); for (Element urlElt : urlElts) { String access = urlElt.getAttribute(ATT_ACCESS); + String path = urlElt.getAttribute(ATT_PATTERN); if (!StringUtils.hasText(access)) { + parserContext.getReaderContext() + .error("access attribute cannot be empty or null", urlElt); continue; } - String path = urlElt.getAttribute(ATT_PATTERN); String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF); boolean hasMatcherRef = StringUtils.hasText(matcherRef); if (!hasMatcherRef && !StringUtils.hasText(path)) { From d5ba9dcadab5598e5a3e79a08a17075344a4f7b8 Mon Sep 17 00:00:00 2001 From: CHANHAN <130114269+chanani@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:21:55 +0900 Subject: [PATCH 3/4] Add tests for intercept-url access attribute validation Fixes gh-18503 Signed-off-by: CHANHAN <130114269+chanani@users.noreply.github.com> --- .../config/http/InterceptUrlConfigTests.java | 49 +++++++++++++++++++ .../InterceptUrlConfigTests-EmptyAccess.xml | 19 +++++++ ...erceptUrlConfigTests-EmptyAccessLegacy.xml | 19 +++++++ .../InterceptUrlConfigTests-MissingAccess.xml | 19 +++++++ ...ceptUrlConfigTests-MissingAccessLegacy.xml | 19 +++++++ .../InterceptUrlConfigTests-ValidAccess.xml | 20 ++++++++ 6 files changed, 145 insertions(+) create mode 100644 config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccess.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccessLegacy.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccess.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccessLegacy.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-ValidAccess.xml diff --git a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java index fab1e932c0..22c30bc185 100644 --- a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java @@ -337,6 +337,55 @@ public class InterceptUrlConfigTests { assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull(); } + /** + * gh-18503 + */ + @Test + public void configWhenInterceptUrlMissingAccessThenException() { + assertThatExceptionOfType(BeanDefinitionParsingException.class) + .isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccess")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); + } + + /** + * gh-18503 + */ + @Test + public void configWhenInterceptUrlEmptyAccessThenException() { + assertThatExceptionOfType(BeanDefinitionParsingException.class) + .isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccess")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); + } + + /** + * gh-18503 + */ + @Test + public void configWhenInterceptUrlValidAccessThenLoads() { + assertThatNoException() + .isThrownBy(() -> this.spring.configLocations(this.xml("ValidAccess")).autowire()); + } + + /** + * gh-18503 + */ + @Test + public void configWhenUseAuthorizationManagerFalseAndMissingAccessThenException() { + assertThatExceptionOfType(BeanDefinitionParsingException.class) + .isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccessLegacy")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); + } + + /** + * gh-18503 + */ + @Test + public void configWhenUseAuthorizationManagerFalseAndEmptyAccessThenException() { + assertThatExceptionOfType(BeanDefinitionParsingException.class) + .isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccessLegacy")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); + } + private static RequestPostProcessor adminCredentials() { return httpBasic("admin", "password"); } diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccess.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccess.xml new file mode 100644 index 0000000000..26197d5bd4 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccess.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccessLegacy.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccessLegacy.xml new file mode 100644 index 0000000000..897a1852e4 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-EmptyAccessLegacy.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccess.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccess.xml new file mode 100644 index 0000000000..d09f24205b --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccess.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccessLegacy.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccessLegacy.xml new file mode 100644 index 0000000000..ad9f6ef9c9 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MissingAccessLegacy.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-ValidAccess.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-ValidAccess.xml new file mode 100644 index 0000000000..00a33b7f0f --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-ValidAccess.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + From 53300be8d7355f8a2e88134952965a3de707b2ae Mon Sep 17 00:00:00 2001 From: Robert Winch <362503+rwinch@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:15:29 -0600 Subject: [PATCH 4/4] Fix checkstyle Issue gh-18530 --- .../http/AuthorizationFilterParser.java | 3 +-- ...nvocationSecurityMetadataSourceParser.java | 3 +-- .../config/http/InterceptUrlConfigTests.java | 19 +++++++++---------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java index 2edf6e8f7f..de676a0791 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java @@ -125,8 +125,7 @@ class AuthorizationFilterParser implements BeanDefinitionParser { for (Element interceptMessage : interceptMessages) { String accessExpression = interceptMessage.getAttribute(ATT_ACCESS); if (!StringUtils.hasText(accessExpression)) { - parserContext.getReaderContext() - .error("access attribute cannot be empty or null", interceptMessage); + parserContext.getReaderContext().error("access attribute cannot be empty or null", interceptMessage); continue; } BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder diff --git a/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java b/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java index 442343d5ce..4716b7f535 100644 --- a/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java +++ b/config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java @@ -144,8 +144,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit String access = urlElt.getAttribute(ATT_ACCESS); String path = urlElt.getAttribute(ATT_PATTERN); if (!StringUtils.hasText(access)) { - parserContext.getReaderContext() - .error("access attribute cannot be empty or null", urlElt); + parserContext.getReaderContext().error("access attribute cannot be empty or null", urlElt); continue; } String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF); diff --git a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java index 22c30bc185..38ac6cf434 100644 --- a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java @@ -343,8 +343,8 @@ public class InterceptUrlConfigTests { @Test public void configWhenInterceptUrlMissingAccessThenException() { assertThatExceptionOfType(BeanDefinitionParsingException.class) - .isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccess")).autowire()) - .withMessageContaining("access attribute cannot be empty or null"); + .isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccess")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); } /** @@ -353,8 +353,8 @@ public class InterceptUrlConfigTests { @Test public void configWhenInterceptUrlEmptyAccessThenException() { assertThatExceptionOfType(BeanDefinitionParsingException.class) - .isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccess")).autowire()) - .withMessageContaining("access attribute cannot be empty or null"); + .isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccess")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); } /** @@ -362,8 +362,7 @@ public class InterceptUrlConfigTests { */ @Test public void configWhenInterceptUrlValidAccessThenLoads() { - assertThatNoException() - .isThrownBy(() -> this.spring.configLocations(this.xml("ValidAccess")).autowire()); + assertThatNoException().isThrownBy(() -> this.spring.configLocations(this.xml("ValidAccess")).autowire()); } /** @@ -372,8 +371,8 @@ public class InterceptUrlConfigTests { @Test public void configWhenUseAuthorizationManagerFalseAndMissingAccessThenException() { assertThatExceptionOfType(BeanDefinitionParsingException.class) - .isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccessLegacy")).autowire()) - .withMessageContaining("access attribute cannot be empty or null"); + .isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccessLegacy")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); } /** @@ -382,8 +381,8 @@ public class InterceptUrlConfigTests { @Test public void configWhenUseAuthorizationManagerFalseAndEmptyAccessThenException() { assertThatExceptionOfType(BeanDefinitionParsingException.class) - .isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccessLegacy")).autowire()) - .withMessageContaining("access attribute cannot be empty or null"); + .isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccessLegacy")).autowire()) + .withMessageContaining("access attribute cannot be empty or null"); } private static RequestPostProcessor adminCredentials() {