Skip to content

Commit 6bbf3f6

Browse files
authored
Merge branch 'spring-projects:main' into main
2 parents d9f35a9 + 10394c8 commit 6bbf3f6

File tree

294 files changed

+3279
-368
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

294 files changed

+3279
-368
lines changed

.github/workflows/continuous-integration-workflow.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
env:
8080
STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }}
8181
run: |
82-
./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
82+
./gradlew assemble && ./gradlew s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
8383
deploy-artifacts:
8484
name: Deploy Artifacts
8585
needs: [ build, test, check-samples, check-tangles ]
@@ -116,7 +116,7 @@ jobs:
116116
send-notification:
117117
name: Send Notification
118118
needs: [ perform-release ]
119-
if: ${{ failure() || cancelled() }}
119+
if: ${{ !success() }}
120120
runs-on: ubuntu-latest
121121
steps:
122122
- name: Send Notification

.github/workflows/release-scheduler.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
strategy:
1212
matrix:
1313
# List of active maintenance branches.
14-
branch: [ main, 6.4.x, 6.3.x, 6.2.x, 5.8.x ]
14+
branch: [ main, 6.4.x, 6.3.x ]
1515
runs-on: ubuntu-latest
1616
steps:
1717
- name: Checkout

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ nohttp {
110110
source.builtBy(project(':spring-security-config').tasks.withType(RncToXsd))
111111
}
112112

113+
tasks.named('checkstyleNohttp') {
114+
maxHeapSize = '1g'
115+
}
116+
113117
tasks.register('cloneRepository', IncludeRepoTask) {
114118
repository = project.getProperties().get("repositoryName")
115119
ref = project.getProperties().get("ref")

buildSrc/src/main/java/s101/S101Plugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ private void configure(S101Configure configure) {
5050

5151
private void configure(JavaExec exec) {
5252
exec.setDescription("Runs Structure101 headless analysis, installing and configuring if necessary");
53-
exec.dependsOn("check");
53+
exec.dependsOn("assemble");
5454
Project project = exec.getProject();
5555
S101PluginExtension extension = project.getExtensions().getByType(S101PluginExtension.class);
5656
exec

cas/src/main/java/org/springframework/security/cas/jackson2/CasJackson2Module.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* @since 4.2
4242
* @see org.springframework.security.jackson2.SecurityJackson2Modules
4343
*/
44+
@SuppressWarnings("serial")
4445
public class CasJackson2Module extends SimpleModule {
4546

4647
public CasJackson2Module() {

config/src/integration-test/java/org/springframework/security/config/annotation/configurers/WebAuthnWebDriverTests.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.junit.jupiter.api.BeforeEach;
3434
import org.junit.jupiter.api.Test;
3535
import org.openqa.selenium.By;
36+
import org.openqa.selenium.WebDriverException;
3637
import org.openqa.selenium.WebElement;
3738
import org.openqa.selenium.chrome.ChromeDriverService;
3839
import org.openqa.selenium.chrome.ChromeOptions;
@@ -273,12 +274,14 @@ private AbstractStringAssert<?> assertHasAlertStartingWith(String alertType, Str
273274

274275
/**
275276
* Await until the assertion passes. If the assertion fails, it will display the
276-
* assertion error in stdout.
277+
* assertion error in stdout. WebDriver-related exceptions are ignored, so that
278+
* {@code assertion}s can interact with the page and be retried on error, e.g.
279+
* {@code assertThat(this.driver.findElement(By.Id("some-id")).isNotNull()}.
277280
*/
278281
private void await(Supplier<AbstractAssert<?, ?>> assertion) {
279282
new FluentWait<>(this.driver).withTimeout(Duration.ofSeconds(2))
280283
.pollingEvery(Duration.ofMillis(100))
281-
.ignoring(AssertionError.class)
284+
.ignoring(AssertionError.class, WebDriverException.class)
282285
.until((d) -> {
283286
assertion.get();
284287
return true;

config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java

Lines changed: 22 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.springframework.http.HttpMethod;
4141
import org.springframework.lang.Nullable;
4242
import org.springframework.security.config.ObjectPostProcessor;
43+
import org.springframework.security.config.annotation.web.ServletRegistrationsSupport.RegistrationMapping;
4344
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry;
4445
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
4546
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -235,103 +236,31 @@ private boolean anyPathsDontStartWithLeadingSlash(String... patterns) {
235236
}
236237

237238
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
238-
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
239-
if (registrations.isEmpty()) {
239+
ServletRegistrationsSupport registrations = new ServletRegistrationsSupport(servletContext);
240+
Collection<RegistrationMapping> mappings = registrations.mappings();
241+
if (mappings.isEmpty()) {
240242
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
241243
}
242-
if (!hasDispatcherServlet(registrations)) {
244+
Collection<RegistrationMapping> dispatcherServletMappings = registrations.dispatcherServletMappings();
245+
if (dispatcherServletMappings.isEmpty()) {
243246
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, new MockMvcRequestMatcher());
244247
}
245-
ServletRegistration dispatcherServlet = requireOneRootDispatcherServlet(registrations);
246-
if (dispatcherServlet != null) {
247-
if (registrations.size() == 1) {
248-
return mvc;
249-
}
250-
return new DispatcherServletDelegatingRequestMatcher(ant, mvc, servletContext);
251-
}
252-
dispatcherServlet = requireOnlyPathMappedDispatcherServlet(registrations);
253-
if (dispatcherServlet != null) {
254-
String mapping = dispatcherServlet.getMappings().iterator().next();
255-
mvc.setServletPath(mapping.substring(0, mapping.length() - 2));
256-
return mvc;
248+
if (dispatcherServletMappings.size() > 1) {
249+
String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values());
250+
throw new IllegalArgumentException(errorMessage);
257251
}
258-
String errorMessage = computeErrorMessage(registrations.values());
259-
throw new IllegalArgumentException(errorMessage);
260-
}
261-
262-
private Map<String, ? extends ServletRegistration> mappableServletRegistrations(ServletContext servletContext) {
263-
Map<String, ServletRegistration> mappable = new LinkedHashMap<>();
264-
for (Map.Entry<String, ? extends ServletRegistration> entry : servletContext.getServletRegistrations()
265-
.entrySet()) {
266-
if (!entry.getValue().getMappings().isEmpty()) {
267-
mappable.put(entry.getKey(), entry.getValue());
268-
}
269-
}
270-
return mappable;
271-
}
272-
273-
private boolean hasDispatcherServlet(Map<String, ? extends ServletRegistration> registrations) {
274-
if (registrations == null) {
275-
return false;
252+
RegistrationMapping dispatcherServlet = dispatcherServletMappings.iterator().next();
253+
if (mappings.size() > 1 && !dispatcherServlet.isDefault()) {
254+
String errorMessage = computeErrorMessage(servletContext.getServletRegistrations().values());
255+
throw new IllegalArgumentException(errorMessage);
276256
}
277-
for (ServletRegistration registration : registrations.values()) {
278-
if (isDispatcherServlet(registration)) {
279-
return true;
280-
}
281-
}
282-
return false;
283-
}
284-
285-
private ServletRegistration requireOneRootDispatcherServlet(
286-
Map<String, ? extends ServletRegistration> registrations) {
287-
ServletRegistration rootDispatcherServlet = null;
288-
for (ServletRegistration registration : registrations.values()) {
289-
if (!isDispatcherServlet(registration)) {
290-
continue;
291-
}
292-
if (registration.getMappings().size() > 1) {
293-
return null;
294-
}
295-
if (!"/".equals(registration.getMappings().iterator().next())) {
296-
return null;
297-
}
298-
rootDispatcherServlet = registration;
299-
}
300-
return rootDispatcherServlet;
301-
}
302-
303-
private ServletRegistration requireOnlyPathMappedDispatcherServlet(
304-
Map<String, ? extends ServletRegistration> registrations) {
305-
ServletRegistration pathDispatcherServlet = null;
306-
for (ServletRegistration registration : registrations.values()) {
307-
if (!isDispatcherServlet(registration)) {
308-
return null;
309-
}
310-
if (registration.getMappings().size() > 1) {
311-
return null;
312-
}
313-
String mapping = registration.getMappings().iterator().next();
314-
if (!mapping.startsWith("/") || !mapping.endsWith("/*")) {
315-
return null;
316-
}
317-
if (pathDispatcherServlet != null) {
318-
return null;
257+
if (dispatcherServlet.isDefault()) {
258+
if (mappings.size() == 1) {
259+
return mvc;
319260
}
320-
pathDispatcherServlet = registration;
321-
}
322-
return pathDispatcherServlet;
323-
}
324-
325-
private boolean isDispatcherServlet(ServletRegistration registration) {
326-
Class<?> dispatcherServlet = ClassUtils.resolveClassName("org.springframework.web.servlet.DispatcherServlet",
327-
null);
328-
try {
329-
Class<?> clazz = Class.forName(registration.getClassName());
330-
return dispatcherServlet.isAssignableFrom(clazz);
331-
}
332-
catch (ClassNotFoundException ex) {
333-
return false;
261+
return new DispatcherServletDelegatingRequestMatcher(ant, mvc);
334262
}
263+
return mvc;
335264
}
336265

337266
private static String computeErrorMessage(Collection<? extends ServletRegistration> registrations) {
@@ -518,18 +447,12 @@ public boolean matches(HttpServletRequest request) {
518447

519448
static class DispatcherServletRequestMatcher implements RequestMatcher {
520449

521-
private final ServletContext servletContext;
522-
523-
DispatcherServletRequestMatcher(ServletContext servletContext) {
524-
this.servletContext = servletContext;
525-
}
526-
527450
@Override
528451
public boolean matches(HttpServletRequest request) {
529452
String name = request.getHttpServletMapping().getServletName();
530-
ServletRegistration registration = this.servletContext.getServletRegistration(name);
453+
ServletRegistration registration = request.getServletContext().getServletRegistration(name);
531454
Assert.notNull(registration,
532-
() -> computeErrorMessage(this.servletContext.getServletRegistrations().values()));
455+
() -> computeErrorMessage(request.getServletContext().getServletRegistrations().values()));
533456
try {
534457
Class<?> clazz = Class.forName(registration.getClassName());
535458
return DispatcherServlet.class.isAssignableFrom(clazz);
@@ -549,10 +472,8 @@ static class DispatcherServletDelegatingRequestMatcher implements RequestMatcher
549472

550473
private final RequestMatcher dispatcherServlet;
551474

552-
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc,
553-
ServletContext servletContext) {
554-
this(ant, mvc, new OrRequestMatcher(new MockMvcRequestMatcher(),
555-
new DispatcherServletRequestMatcher(servletContext)));
475+
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc) {
476+
this(ant, mvc, new OrRequestMatcher(new MockMvcRequestMatcher(), new DispatcherServletRequestMatcher()));
556477
}
557478

558479
DispatcherServletDelegatingRequestMatcher(AntPathRequestMatcher ant, MvcRequestMatcher mvc,
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2002-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config.annotation.web;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collection;
21+
import java.util.Map;
22+
23+
import jakarta.servlet.ServletContext;
24+
import jakarta.servlet.ServletRegistration;
25+
26+
import org.springframework.util.ClassUtils;
27+
28+
class ServletRegistrationsSupport {
29+
30+
private final Collection<RegistrationMapping> registrations;
31+
32+
ServletRegistrationsSupport(ServletContext servletContext) {
33+
Map<String, ? extends ServletRegistration> registrations = servletContext.getServletRegistrations();
34+
Collection<RegistrationMapping> mappings = new ArrayList<>();
35+
for (Map.Entry<String, ? extends ServletRegistration> entry : registrations.entrySet()) {
36+
if (!entry.getValue().getMappings().isEmpty()) {
37+
for (String mapping : entry.getValue().getMappings()) {
38+
mappings.add(new RegistrationMapping(entry.getValue(), mapping));
39+
}
40+
}
41+
}
42+
this.registrations = mappings;
43+
}
44+
45+
Collection<RegistrationMapping> dispatcherServletMappings() {
46+
Collection<RegistrationMapping> mappings = new ArrayList<>();
47+
for (RegistrationMapping registration : this.registrations) {
48+
if (registration.isDispatcherServlet()) {
49+
mappings.add(registration);
50+
}
51+
}
52+
return mappings;
53+
}
54+
55+
Collection<RegistrationMapping> mappings() {
56+
return this.registrations;
57+
}
58+
59+
record RegistrationMapping(ServletRegistration registration, String mapping) {
60+
boolean isDispatcherServlet() {
61+
Class<?> dispatcherServlet = ClassUtils
62+
.resolveClassName("org.springframework.web.servlet.DispatcherServlet", null);
63+
try {
64+
Class<?> clazz = Class.forName(this.registration.getClassName());
65+
return dispatcherServlet.isAssignableFrom(clazz);
66+
}
67+
catch (ClassNotFoundException ex) {
68+
return false;
69+
}
70+
}
71+
72+
boolean isDefault() {
73+
return "/".equals(this.mapping);
74+
}
75+
}
76+
77+
}

0 commit comments

Comments
 (0)