Explorar el Código

Revert "Add forServletPattern"

This reverts commit 762319b6bea04027ee83208f9e66073ab081bc40.
Josh Cummings hace 1 año
padre
commit
4131a38f9e
Se han modificado 16 ficheros con 62 adiciones y 2273 borrados
  1. 0 52
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractRequestMatcherBuilderRegistry.java
  2. 0 59
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/AntPathRequestMatcherBuilder.java
  3. 19 368
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java
  4. 0 103
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/DispatcherServletDelegatingRequestMatcherBuilder.java
  5. 0 76
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/MvcRequestMatcherBuilder.java
  6. 0 106
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherBuilder.java
  7. 0 215
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherBuilders.java
  8. 0 43
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletPatternRequestMatcher.java
  9. 0 152
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletRegistrationCollection.java
  10. 0 7
      config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryNoMvcTests.java
  11. 6 0
      config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java
  12. 0 349
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/AbstractRequestMatcherBuilderRegistryTests.java
  13. 5 363
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java
  14. 0 198
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherBuildersTests.java
  15. 0 64
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletPatternRequestMatcherTests.java
  16. 32 118
      docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc

+ 0 - 52
config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractRequestMatcherBuilderRegistry.java

@@ -1,52 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-
-abstract class AbstractRequestMatcherBuilderRegistry<C> extends AbstractRequestMatcherRegistry<C> {
-
-	private final RequestMatcherBuilder builder;
-
-	AbstractRequestMatcherBuilderRegistry(ApplicationContext context) {
-		this(context, RequestMatcherBuilders.createDefault(context));
-	}
-
-	AbstractRequestMatcherBuilderRegistry(ApplicationContext context, RequestMatcherBuilder builder) {
-		setApplicationContext(context);
-		this.builder = builder;
-	}
-
-	@Override
-	public final C requestMatchers(String... patterns) {
-		return requestMatchers(null, patterns);
-	}
-
-	@Override
-	public final C requestMatchers(HttpMethod method, String... patterns) {
-		return requestMatchers(this.builder.matchers(method, patterns).toArray(RequestMatcher[]::new));
-	}
-
-	@Override
-	public final C requestMatchers(HttpMethod method) {
-		return requestMatchers(method, "/**");
-	}
-
-}

+ 0 - 59
config/src/main/java/org/springframework/security/config/annotation/web/configurers/AntPathRequestMatcherBuilder.java

@@ -1,59 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import org.springframework.http.HttpMethod;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-
-final class AntPathRequestMatcherBuilder implements RequestMatcherBuilder {
-
-	private final String servletPath;
-
-	private AntPathRequestMatcherBuilder(String servletPath) {
-		this.servletPath = servletPath;
-	}
-
-	static AntPathRequestMatcherBuilder absolute() {
-		return new AntPathRequestMatcherBuilder(null);
-	}
-
-	static AntPathRequestMatcherBuilder relativeTo(String path) {
-		return new AntPathRequestMatcherBuilder(path);
-	}
-
-	@Override
-	public AntPathRequestMatcher matcher(String pattern) {
-		return matcher((String) null, pattern);
-	}
-
-	@Override
-	public AntPathRequestMatcher matcher(HttpMethod method, String pattern) {
-		return matcher((method != null) ? method.name() : null, pattern);
-	}
-
-	private AntPathRequestMatcher matcher(String method, String pattern) {
-		return new AntPathRequestMatcher(prependServletPath(pattern), method);
-	}
-
-	private String prependServletPath(String pattern) {
-		if (this.servletPath == null) {
-			return pattern;
-		}
-		return this.servletPath + pattern;
-	}
-
-}

+ 19 - 368
config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java

@@ -16,14 +16,10 @@
 
 package org.springframework.security.config.annotation.web.configurers;
 
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
 import java.util.function.Supplier;
 
 import io.micrometer.observation.ObservationRegistry;
-import jakarta.servlet.http.HttpServletMapping;
 import jakarta.servlet.http.HttpServletRequest;
 
 import org.springframework.context.ApplicationContext;
@@ -36,22 +32,17 @@ import org.springframework.security.authorization.AuthorizationEventPublisher;
 import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.authorization.ObservationAuthorizationManager;
 import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
-import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.ObjectPostProcessor;
 import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.core.GrantedAuthorityDefaults;
 import org.springframework.security.web.access.intercept.AuthorizationFilter;
 import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
-import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcherEntry;
 import org.springframework.util.Assert;
 import org.springframework.util.function.SingletonSupplier;
-import org.springframework.web.servlet.DispatcherServlet;
 
 /**
  * Adds a URL based authorization using {@link AuthorizationManager}.
@@ -146,62 +137,41 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
 	 * @author Evgeniy Cheban
 	 */
 	public final class AuthorizationManagerRequestMatcherRegistry
-			extends AbstractRequestMatcherBuilderRegistry<AuthorizedUrl> {
+			extends AbstractRequestMatcherRegistry<AuthorizedUrl> {
 
 		private final RequestMatcherDelegatingAuthorizationManager.Builder managerBuilder = RequestMatcherDelegatingAuthorizationManager
 			.builder();
 
-		List<RequestMatcher> unmappedMatchers;
+		private List<RequestMatcher> unmappedMatchers;
 
 		private int mappingCount;
 
 		private boolean shouldFilterAllDispatcherTypes = true;
 
-		private final Map<String, AuthorizationManagerServletRequestMatcherRegistry> servletPattern = new LinkedHashMap<>();
-
-		AuthorizationManagerRequestMatcherRegistry(ApplicationContext context) {
-			super(context);
+		private AuthorizationManagerRequestMatcherRegistry(ApplicationContext context) {
+			setApplicationContext(context);
 		}
 
 		private void addMapping(RequestMatcher matcher, AuthorizationManager<RequestAuthorizationContext> manager) {
-			Assert.isTrue(this.servletPattern.isEmpty(),
-					"Since you have used forServletPattern, all request matchers must be configured using forServletPattern; alternatively, you can use requestMatchers(RequestMatcher) for all requests.");
 			this.unmappedMatchers = null;
 			this.managerBuilder.add(matcher, manager);
 			this.mappingCount++;
 		}
 
 		private void addFirst(RequestMatcher matcher, AuthorizationManager<RequestAuthorizationContext> manager) {
-			Assert.isTrue(this.servletPattern.isEmpty(),
-					"Since you have used forServletPattern, all request matchers must be configured using forServletPattern; alternatively, you can use requestMatchers(RequestMatcher) for all requests.");
 			this.unmappedMatchers = null;
 			this.managerBuilder.mappings((m) -> m.add(0, new RequestMatcherEntry<>(matcher, manager)));
 			this.mappingCount++;
 		}
 
-		private AuthorizationManager<HttpServletRequest> servletAuthorizationManager() {
-			for (Map.Entry<String, AuthorizationManagerServletRequestMatcherRegistry> entry : this.servletPattern
-				.entrySet()) {
-				AuthorizationManagerServletRequestMatcherRegistry registry = entry.getValue();
-				this.managerBuilder.add(new ServletPatternRequestMatcher(entry.getKey()),
-						registry.authorizationManager());
-			}
-			return postProcess(this.managerBuilder.build());
-		}
-
-		private AuthorizationManager<HttpServletRequest> authorizationManager() {
+		private AuthorizationManager<HttpServletRequest> createAuthorizationManager() {
 			Assert.state(this.unmappedMatchers == null,
 					() -> "An incomplete mapping was found for " + this.unmappedMatchers
 							+ ". Try completing it with something like requestUrls().<something>.hasRole('USER')");
 			Assert.state(this.mappingCount > 0,
 					"At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())");
-			return postProcess(this.managerBuilder.build());
-		}
-
-		private AuthorizationManager<HttpServletRequest> createAuthorizationManager() {
-			AuthorizationManager<HttpServletRequest> manager = (this.servletPattern.isEmpty()) ? authorizationManager()
-					: servletAuthorizationManager();
 			ObservationRegistry registry = getObservationRegistry();
+			RequestMatcherDelegatingAuthorizationManager manager = postProcess(this.managerBuilder.build());
 			if (registry.isNoop()) {
 				return manager;
 			}
@@ -211,74 +181,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
 		@Override
 		protected AuthorizedUrl chainRequestMatchers(List<RequestMatcher> requestMatchers) {
 			this.unmappedMatchers = requestMatchers;
-			return new AuthorizedUrl(
-					(manager) -> AuthorizeHttpRequestsConfigurer.this.addMapping(requestMatchers, manager));
-		}
-
-		/**
-		 * Begin registering {@link RequestMatcher}s based on the type of the servlet
-		 * mapped to {@code pattern}. Each registered request matcher will additionally
-		 * check {@link HttpServletMapping#getPattern} against the provided
-		 * {@code pattern}.
-		 *
-		 * <p>
-		 * If the corresponding servlet is of type {@link DispatcherServlet}, then use a
-		 * {@link AuthorizationManagerServletRequestMatcherRegistry} that registers
-		 * {@link MvcRequestMatcher}s.
-		 *
-		 * <p>
-		 * Otherwise, use a configurer that registers {@link AntPathRequestMatcher}s.
-		 *
-		 * <p>
-		 * When doing a path-based pattern, like `/path/*`, registered URIs should leave
-		 * out the matching path. For example, if the target URI is `/path/resource/3`,
-		 * then the configuration should look like this: <code>
-		 *	.forServletPattern("/path/*", (path) -> path
-		 *      .requestMatchers("/resource/3").hasAuthority(...)
-		 *  )
-		 * </code>
-		 *
-		 * <p>
-		 * Or, if the pattern is `/path/subpath/*`, and the URI is
-		 * `/path/subpath/resource/3`, then the configuration should look like this:
-		 * <code>
-		 *	.forServletPattern("/path/subpath/*", (path) -> path
-		 *      .requestMatchers("/resource/3").hasAuthority(...)
-		 *  )
-		 * </code>
-		 *
-		 * <p>
-		 * For all other patterns, please supply the URI in absolute terms. For example,
-		 * if the target URI is `/js/**` and it matches to the default servlet, then the
-		 * configuration should look like this: <code>
-		 * 	.forServletPattern("/", (root) -> root
-		 * 	    .requestMatchers("/js/**").hasAuthority(...)
-		 * 	)
-		 * </code>
-		 *
-		 * <p>
-		 * Or, if the target URI is `/views/**`, and it matches to a `*.jsp` extension
-		 * servlet, then the configuration should look like this: <code>
-		 * 	.forServletPattern("*.jsp", (jsp) -> jsp
-		 * 	    .requestMatchers("/views/**").hasAuthority(...)
-		 * 	)
-		 * </code>
-		 * @param customizer a customizer that uses a
-		 * {@link AuthorizationManagerServletRequestMatcherRegistry} for URIs mapped to
-		 * the provided servlet
-		 * @return an {@link AuthorizationManagerServletRequestMatcherRegistry} for
-		 * further configurations
-		 * @since 6.2
-		 */
-		public AuthorizationManagerRequestMatcherRegistry forServletPattern(String pattern,
-				Customizer<AuthorizationManagerServletRequestMatcherRegistry> customizer) {
-			ApplicationContext context = getApplicationContext();
-			RequestMatcherBuilder builder = RequestMatcherBuilders.createForServletPattern(context, pattern);
-			AuthorizationManagerServletRequestMatcherRegistry registry = new AuthorizationManagerServletRequestMatcherRegistry(
-					builder);
-			customizer.customize(registry);
-			this.servletPattern.put(pattern, registry);
-			return this;
+			return new AuthorizedUrl(requestMatchers);
 		}
 
 		/**
@@ -334,265 +237,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
 			return AuthorizeHttpRequestsConfigurer.this.and();
 		}
 
-		/**
-		 * A decorator class for registering {@link RequestMatcher} instances based on the
-		 * type of servlet. If the servlet is {@link DispatcherServlet}, then it will use
-		 * a {@link MvcRequestMatcher}; otherwise, it will use a
-		 * {@link AntPathRequestMatcher}.
-		 *
-		 * <p>
-		 * This class is designed primarily for use with the {@link HttpSecurity} DSL. For
-		 * that reason, please use {@link HttpSecurity#authorizeHttpRequests} instead as
-		 * it exposes this class fluently alongside related DSL configurations.
-		 *
-		 * <p>
-		 * NOTE: In many cases, which kind of request matcher is needed is apparent by the
-		 * servlet configuration, and so you should generally use the methods found in
-		 * {@link AbstractRequestMatcherRegistry} instead of this these. Use this class
-		 * when you want or need to indicate which request matcher URIs belong to which
-		 * servlet.
-		 *
-		 * <p>
-		 * In all cases, though, you may arrange your request matchers by servlet pattern
-		 * with the {@link AuthorizationManagerRequestMatcherRegistry#forServletPattern}
-		 * method in the {@link HttpSecurity#authorizeHttpRequests} DSL.
-		 *
-		 * <p>
-		 * Consider, for example, the circumstance where you have Spring MVC configured
-		 * and also Spring Boot H2 Console. Spring MVC registers a servlet of type
-		 * {@link DispatcherServlet} as the default servlet and Spring Boot registers a
-		 * servlet of its own as well at `/h2-console/*`.
-		 *
-		 * <p>
-		 * Such might have a configuration like this in Spring Security: <code>
-		 * 	http
-		 * 		.authorizeHttpRequests((authorize) -> authorize
-		 * 			.requestMatchers("/js/**", "/css/**").permitAll()
-		 * 			.requestMatchers("/my/controller/**").hasAuthority("CONTROLLER")
-		 * 			.requestMatchers("/h2-console/**").hasAuthority("H2")
-		 * 		)
-		 * 		// ...
-		 * </code>
-		 *
-		 * <p>
-		 * Spring Security by default addresses the above configuration on its own.
-		 *
-		 * <p>
-		 * However, consider the same situation, but where {@link DispatcherServlet} is
-		 * mapped to a path like `/mvc/*`. In this case, the above configuration is
-		 * ambiguous, and you should use this class to clarify the rest of each MVC URI
-		 * like so: <code>
-		 * 	http
-		 * 		.authorizeHttpRequests((authorize) -> authorize
-		 * 			.forServletPattern("/", (root) -> root
-		 * 				.requestMatchers("/js/**", "/css/**").permitAll()
-		 * 			)
-		 * 			.forServletPattern("/mvc/*", (mvc) -> mvc
-		 * 				.requestMatchers("/my/controller/**").hasAuthority("CONTROLLER")
-		 * 			)
-		 * 			.forServletPattern("/h2-console/*", (h2) -> h2
-		 * 				.anyRequest().hasAuthority("OTHER")
-		 * 			)
-		 * 		)
-		 * 		// ...
-		 * </code>
-		 *
-		 * <p>
-		 * In the above configuration, it's now clear to Spring Security that the
-		 * following matchers map to these corresponding URIs:
-		 *
-		 * <ul>
-		 * <li>&lt;default&gt; + <strong>`/js/**`</strong> ==> `/js/**`</li>
-		 * <li>&lt;default&gt; + <strong>`/css/**`</strong> ==> `/css/**`</li>
-		 * <li>`/mvc` + <strong>`/my/controller/**`</strong> ==>
-		 * `/mvc/my/controller/**`</li>
-		 * <li>`/h2-console` + <strong>&lt;any request&gt;</strong> ==>
-		 * `/h2-console/**`</li>
-		 * </ul>
-		 *
-		 * @author Josh Cummings
-		 * @since 6.2
-		 * @see AbstractRequestMatcherRegistry
-		 * @see AuthorizeHttpRequestsConfigurer
-		 */
-		public final class AuthorizationManagerServletRequestMatcherRegistry
-				extends AbstractRequestMatcherBuilderRegistry<ServletAuthorizedUrl> {
-
-			private final RequestMatcherDelegatingAuthorizationManager.Builder managerBuilder = RequestMatcherDelegatingAuthorizationManager
-				.builder();
-
-			private List<RequestMatcher> unmappedMatchers;
-
-			AuthorizationManagerServletRequestMatcherRegistry(RequestMatcherBuilder builder) {
-				super(AuthorizationManagerRequestMatcherRegistry.this.getApplicationContext(), builder);
-			}
-
-			AuthorizationManager<RequestAuthorizationContext> authorizationManager() {
-				Assert.state(this.unmappedMatchers == null,
-						() -> "An incomplete mapping was found for " + this.unmappedMatchers
-								+ ". Try completing it with something like requestUrls().<something>.hasRole('USER')");
-				AuthorizationManager<HttpServletRequest> request = this.managerBuilder.build();
-				return (authentication, context) -> request.check(authentication, context.getRequest());
-			}
-
-			@Override
-			protected ServletAuthorizedUrl chainRequestMatchers(List<RequestMatcher> requestMatchers) {
-				this.unmappedMatchers = requestMatchers;
-				return new ServletAuthorizedUrl((manager) -> addMapping(requestMatchers, manager));
-			}
-
-			private AuthorizationManagerServletRequestMatcherRegistry addMapping(List<RequestMatcher> matchers,
-					AuthorizationManager<RequestAuthorizationContext> manager) {
-				this.unmappedMatchers = null;
-				for (RequestMatcher matcher : matchers) {
-					this.managerBuilder.add(matcher, manager);
-				}
-				return this;
-			}
-
-		}
-
-		/**
-		 * An object that allows configuring the {@link AuthorizationManager} for
-		 * {@link RequestMatcher}s.
-		 *
-		 * @author Josh Cummings
-		 * @since 6.2
-		 */
-		public final class ServletAuthorizedUrl {
-
-			private final Function<AuthorizationManager<RequestAuthorizationContext>, AuthorizationManagerServletRequestMatcherRegistry> registrar;
-
-			ServletAuthorizedUrl(
-					Function<AuthorizationManager<RequestAuthorizationContext>, AuthorizationManagerServletRequestMatcherRegistry> registrar) {
-				this.registrar = registrar;
-			}
-
-			/**
-			 * Specify that URLs are allowed by anyone.
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry permitAll() {
-				return access(permitAllAuthorizationManager);
-			}
-
-			/**
-			 * Specify that URLs are not allowed by anyone.
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry denyAll() {
-				return access((a, o) -> new AuthorizationDecision(false));
-			}
-
-			/**
-			 * Specifies a user requires a role.
-			 * @param role the role that should be required which is prepended with ROLE_
-			 * automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_
-			 * @return {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry hasRole(String role) {
-				return access(withRoleHierarchy(AuthorityAuthorizationManager
-					.hasAnyRole(AuthorizeHttpRequestsConfigurer.this.rolePrefix, new String[] { role })));
-			}
-
-			/**
-			 * Specifies that a user requires one of many roles.
-			 * @param roles the roles that the user should have at least one of (i.e.
-			 * ADMIN, USER, etc). Each role should not start with ROLE_ since it is
-			 * automatically prepended already
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry hasAnyRole(String... roles) {
-				return access(withRoleHierarchy(AuthorityAuthorizationManager
-					.hasAnyRole(AuthorizeHttpRequestsConfigurer.this.rolePrefix, roles)));
-			}
-
-			/**
-			 * Specifies a user requires an authority.
-			 * @param authority the authority that should be required
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry hasAuthority(String authority) {
-				return access(withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority)));
-			}
-
-			/**
-			 * Specifies that a user requires one of many authorities.
-			 * @param authorities the authorities that the user should have at least one
-			 * of (i.e. ROLE_USER, ROLE_ADMIN, etc)
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry hasAnyAuthority(String... authorities) {
-				return access(withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities)));
-			}
-
-			private AuthorityAuthorizationManager<RequestAuthorizationContext> withRoleHierarchy(
-					AuthorityAuthorizationManager<RequestAuthorizationContext> manager) {
-				manager.setRoleHierarchy(AuthorizeHttpRequestsConfigurer.this.roleHierarchy.get());
-				return manager;
-			}
-
-			/**
-			 * Specify that URLs are allowed by any authenticated user.
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry authenticated() {
-				return access(AuthenticatedAuthorizationManager.authenticated());
-			}
-
-			/**
-			 * Specify that URLs are allowed by users who have authenticated and were not
-			 * "remembered".
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customization
-			 * @see RememberMeConfigurer
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry fullyAuthenticated() {
-				return access(AuthenticatedAuthorizationManager.fullyAuthenticated());
-			}
-
-			/**
-			 * Specify that URLs are allowed by users that have been remembered.
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customization
-			 * @since 5.8
-			 * @see RememberMeConfigurer
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry rememberMe() {
-				return access(AuthenticatedAuthorizationManager.rememberMe());
-			}
-
-			/**
-			 * Specify that URLs are allowed by anonymous users.
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customization
-			 * @since 5.8
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry anonymous() {
-				return access(AuthenticatedAuthorizationManager.anonymous());
-			}
-
-			/**
-			 * Allows specifying a custom {@link AuthorizationManager}.
-			 * @param manager the {@link AuthorizationManager} to use
-			 * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
-			 * customizations
-			 */
-			public AuthorizationManagerServletRequestMatcherRegistry access(
-					AuthorizationManager<RequestAuthorizationContext> manager) {
-				Assert.notNull(manager, "manager cannot be null");
-				return this.registrar.apply(manager);
-			}
-
-		}
-
 	}
 
 	/**
@@ -603,11 +247,18 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
 	 */
 	public class AuthorizedUrl {
 
-		private final Function<AuthorizationManager<RequestAuthorizationContext>, AuthorizationManagerRequestMatcherRegistry> registrar;
+		private final List<? extends RequestMatcher> matchers;
+
+		/**
+		 * Creates an instance.
+		 * @param matchers the {@link RequestMatcher} instances to map
+		 */
+		AuthorizedUrl(List<? extends RequestMatcher> matchers) {
+			this.matchers = matchers;
+		}
 
-		AuthorizedUrl(
-				Function<AuthorizationManager<RequestAuthorizationContext>, AuthorizationManagerRequestMatcherRegistry> registrar) {
-			this.registrar = registrar;
+		protected List<? extends RequestMatcher> getMatchers() {
+			return this.matchers;
 		}
 
 		/**
@@ -731,7 +382,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
 		public AuthorizationManagerRequestMatcherRegistry access(
 				AuthorizationManager<RequestAuthorizationContext> manager) {
 			Assert.notNull(manager, "manager cannot be null");
-			return this.registrar.apply(manager);
+			return AuthorizeHttpRequestsConfigurer.this.addMapping(this.matchers, manager);
 		}
 
 	}

+ 0 - 103
config/src/main/java/org/springframework/security/config/annotation/web/configurers/DispatcherServletDelegatingRequestMatcherBuilder.java

@@ -1,103 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import org.springframework.http.HttpMethod;
-import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.util.Assert;
-
-final class DispatcherServletDelegatingRequestMatcherBuilder implements RequestMatcherBuilder {
-
-	final MvcRequestMatcherBuilder mvc;
-
-	final AntPathRequestMatcherBuilder ant;
-
-	final ServletRegistrationCollection registrations;
-
-	DispatcherServletDelegatingRequestMatcherBuilder(MvcRequestMatcherBuilder mvc, AntPathRequestMatcherBuilder ant,
-			ServletRegistrationCollection registrations) {
-		this.mvc = mvc;
-		this.ant = ant;
-		this.registrations = registrations;
-	}
-
-	@Override
-	public RequestMatcher matcher(String pattern) {
-		MvcRequestMatcher mvc = this.mvc.matcher(pattern);
-		AntPathRequestMatcher ant = this.ant.matcher(pattern);
-		return new DispatcherServletDelegatingRequestMatcher(mvc, ant, this.registrations);
-	}
-
-	@Override
-	public RequestMatcher matcher(HttpMethod method, String pattern) {
-		MvcRequestMatcher mvc = this.mvc.matcher(method, pattern);
-		AntPathRequestMatcher ant = this.ant.matcher(method, pattern);
-		return new DispatcherServletDelegatingRequestMatcher(mvc, ant, this.registrations);
-	}
-
-	static final class DispatcherServletDelegatingRequestMatcher implements RequestMatcher {
-
-		private final MvcRequestMatcher mvc;
-
-		private final AntPathRequestMatcher ant;
-
-		private final ServletRegistrationCollection registrations;
-
-		private DispatcherServletDelegatingRequestMatcher(MvcRequestMatcher mvc, AntPathRequestMatcher ant,
-				ServletRegistrationCollection registrations) {
-			this.mvc = mvc;
-			this.ant = ant;
-			this.registrations = registrations;
-		}
-
-		@Override
-		public boolean matches(HttpServletRequest request) {
-			String name = request.getHttpServletMapping().getServletName();
-			ServletRegistrationCollection.Registration registration = this.registrations.registrationByName(name);
-			Assert.notNull(registration,
-					String.format("Could not find %s in servlet configuration %s", name, this.registrations));
-			if (registration.isDispatcherServlet()) {
-				return this.mvc.matches(request);
-			}
-			return this.ant.matches(request);
-		}
-
-		@Override
-		public MatchResult matcher(HttpServletRequest request) {
-			String name = request.getHttpServletMapping().getServletName();
-			ServletRegistrationCollection.Registration registration = this.registrations.registrationByName(name);
-			Assert.notNull(registration,
-					String.format("Could not find %s in servlet configuration %s", name, this.registrations));
-			if (registration.isDispatcherServlet()) {
-				return this.mvc.matcher(request);
-			}
-			return this.ant.matcher(request);
-		}
-
-		@Override
-		public String toString() {
-			return String.format("DispatcherServlet [mvc=[%s], ant=[%s], servlet=[%s]]", this.mvc, this.ant,
-					this.registrations);
-		}
-
-	}
-
-}

+ 0 - 76
config/src/main/java/org/springframework/security/config/annotation/web/configurers/MvcRequestMatcherBuilder.java

@@ -1,76 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.config.annotation.ObjectPostProcessor;
-import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
-import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
-
-final class MvcRequestMatcherBuilder implements RequestMatcherBuilder {
-
-	private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
-
-	private final HandlerMappingIntrospector introspector;
-
-	private final ObjectPostProcessor<Object> objectPostProcessor;
-
-	private final String servletPath;
-
-	private MvcRequestMatcherBuilder(ApplicationContext context, String servletPath) {
-		if (!context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
-			throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME
-					+ " of type " + HandlerMappingIntrospector.class.getName()
-					+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
-		}
-		this.introspector = context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class);
-		this.objectPostProcessor = context.getBean(ObjectPostProcessor.class);
-		this.servletPath = servletPath;
-	}
-
-	static MvcRequestMatcherBuilder absolute(ApplicationContext context) {
-		return new MvcRequestMatcherBuilder(context, null);
-	}
-
-	static MvcRequestMatcherBuilder relativeTo(ApplicationContext context, String path) {
-		return new MvcRequestMatcherBuilder(context, path);
-	}
-
-	@Override
-	public MvcRequestMatcher matcher(String pattern) {
-		MvcRequestMatcher matcher = new MvcRequestMatcher(this.introspector, pattern);
-		this.objectPostProcessor.postProcess(matcher);
-		if (this.servletPath != null) {
-			matcher.setServletPath(this.servletPath);
-		}
-		return matcher;
-	}
-
-	@Override
-	public MvcRequestMatcher matcher(HttpMethod method, String pattern) {
-		MvcRequestMatcher matcher = new MvcRequestMatcher(this.introspector, pattern);
-		this.objectPostProcessor.postProcess(matcher);
-		matcher.setMethod(method);
-		if (this.servletPath != null) {
-			matcher.setServletPath(this.servletPath);
-		}
-		return matcher;
-	}
-
-}

+ 0 - 106
config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherBuilder.java

@@ -1,106 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.springframework.http.HttpMethod;
-import org.springframework.security.web.util.matcher.AnyRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-
-/**
- * An interface that abstracts how matchers are created
- *
- * @author Josh Cummings
- * @since 6.2
- */
-interface RequestMatcherBuilder {
-
-	/**
-	 * Create a request matcher for the given pattern.
-	 *
-	 * <p>
-	 * For example, you might do something like the following: <code>
-	 *     builder.matcher("/controller/**")
-	 * </code>
-	 * @param pattern the pattern to use, typically an Ant path
-	 * @return a {@link RequestMatcher} that matches on the given {@code pattern}
-	 */
-	RequestMatcher matcher(String pattern);
-
-	/**
-	 * Create a request matcher for the given pattern.
-	 *
-	 * <p>
-	 * For example, you might do something like the following: <code>
-	 *     builder.matcher(HttpMethod.GET, "/controller/**")
-	 * </code>
-	 * @param method the HTTP method to use
-	 * @param pattern the pattern to use, typically an Ant path
-	 * @return a {@link RequestMatcher} that matches on the given HTTP {@code method} and
-	 * {@code pattern}
-	 */
-	RequestMatcher matcher(HttpMethod method, String pattern);
-
-	/**
-	 * Create a request matcher that matches any request
-	 * @return a {@link RequestMatcher} that matches any request
-	 */
-	default RequestMatcher any() {
-		return AnyRequestMatcher.INSTANCE;
-	}
-
-	/**
-	 * Create an array request matchers, one for each of the given patterns.
-	 *
-	 * <p>
-	 * For example, you might do something like the following: <code>
-	 *     builder.matcher("/controller-one/**", "/controller-two/**")
-	 * </code>
-	 * @param patterns the patterns to use, typically Ant paths
-	 * @return a list of {@link RequestMatcher} that match on the given {@code pattern}
-	 */
-	default List<RequestMatcher> matchers(String... patterns) {
-		List<RequestMatcher> matchers = new ArrayList<>();
-		for (String pattern : patterns) {
-			matchers.add(matcher(pattern));
-		}
-		return matchers;
-	}
-
-	/**
-	 * Create an array request matchers, one for each of the given patterns.
-	 *
-	 * <p>
-	 * For example, you might do something like the following: <code>
-	 *     builder.matcher(HttpMethod.POST, "/controller-one/**", "/controller-two/**")
-	 * </code>
-	 * @param method the HTTP method to use
-	 * @param patterns the patterns to use, typically Ant paths
-	 * @return a list of {@link RequestMatcher} that match on the given HTTP
-	 * {@code method} and {@code pattern}
-	 */
-	default List<RequestMatcher> matchers(HttpMethod method, String... patterns) {
-		List<RequestMatcher> matchers = new ArrayList<>();
-		for (String pattern : patterns) {
-			matchers.add(matcher(method, pattern));
-		}
-		return matchers;
-	}
-
-}

+ 0 - 215
config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherBuilders.java

@@ -1,215 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-import org.springframework.web.servlet.DispatcherServlet;
-
-/**
- * A factory for constructing {@link RequestMatcherBuilder} instances
- *
- * @author Josh Cummings
- * @since 6.2
- */
-final class RequestMatcherBuilders {
-
-	private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
-
-	private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
-
-	private static final boolean mvcPresent;
-
-	static {
-		mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, RequestMatcherBuilders.class.getClassLoader());
-	}
-
-	private static final Log logger = LogFactory.getLog(RequestMatcherBuilders.class);
-
-	private RequestMatcherBuilders() {
-
-	}
-
-	/**
-	 * Create the default {@link RequestMatcherBuilder} for use by Spring Security DSLs.
-	 *
-	 * <p>
-	 * If Spring MVC is not present on the classpath or if there is no
-	 * {@link DispatcherServlet}, this method will return an Ant-based builder.
-	 *
-	 * <p>
-	 * If the servlet configuration has only {@link DispatcherServlet} with a single
-	 * mapping (for example `/` or `/path/*`), then this method will return an MVC-based
-	 * builder.
-	 *
-	 * <p>
-	 * If the servlet configuration maps {@link DispatcherServlet} to a path and also has
-	 * other servlets, this will throw an exception. In that case, an application should
-	 * instead use the {@link RequestMatcherBuilders#createForServletPattern} ideally with
-	 * the associated
-	 * {@link org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer}
-	 * to create builders by servlet path.
-	 *
-	 * <p>
-	 * Otherwise, (namely if {@link DispatcherServlet} is root), this method will return a
-	 * builder that delegates to an Ant or Mvc builder at runtime.
-	 * @param context the application context
-	 * @return the appropriate {@link RequestMatcherBuilder} based on application
-	 * configuration
-	 */
-	static RequestMatcherBuilder createDefault(ApplicationContext context) {
-		if (!mvcPresent) {
-			logger.trace("Defaulting to Ant matching since Spring MVC is not on the classpath");
-			return AntPathRequestMatcherBuilder.absolute();
-		}
-		if (!context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
-			logger.trace("Defaulting to Ant matching since Spring MVC is not fully configured");
-			return AntPathRequestMatcherBuilder.absolute();
-		}
-		ServletRegistrationCollection registrations = ServletRegistrationCollection.registrations(context);
-		if (registrations.isEmpty()) {
-			logger.trace("Defaulting to MVC matching since Spring MVC is on the class path and no servlet "
-					+ "information is available");
-			return AntPathRequestMatcherBuilder.absolute();
-		}
-		ServletRegistrationCollection dispatcherServlets = registrations.dispatcherServlets();
-		if (dispatcherServlets.isEmpty()) {
-			logger.trace("Defaulting to Ant matching since there is no DispatcherServlet configured");
-			return AntPathRequestMatcherBuilder.absolute();
-		}
-		ServletRegistrationCollection.ServletPath servletPath = registrations.deduceOneServletPath();
-		if (servletPath != null) {
-			String message = "Defaulting to MVC matching since DispatcherServlet [%s] is the only servlet mapping";
-			logger.trace(String.format(message, servletPath.path()));
-			return MvcRequestMatcherBuilder.relativeTo(context, servletPath.path());
-		}
-		servletPath = dispatcherServlets.deduceOneServletPath();
-		if (servletPath == null) {
-			logger.trace("Did not choose a default since there is more than one DispatcherServlet mapping");
-			String message = String.format("""
-					This method cannot decide whether these patterns are Spring MVC patterns or not
-					since your servlet configuration has multiple Spring MVC servlet mappings.
-
-					For your reference, here is your servlet configuration: %s
-
-					To address this, you need to specify the servlet path for each endpoint.
-					You can use .forServletPattern in conjunction with requestMatchers do to this
-					like so:
-
-					@Bean
-					SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
-						http
-							.authorizeHttpRequests((authorize) -> authorize
-								.forServletPattern("/mvc-one/*", (one) -> one
-									.requestMatchers("/controller/**", "/endpoints/**"
-								)...
-								.forServletPattern("/mvc-two/*", (two) -> two
-									.requestMatchers("/other/**", "/controllers/**")...
-								)
-								.forServletPattern("/h2-console/*", (h2) -> h2
-									.requestMatchers("/**")...
-								)
-							)
-							// ...
-						return http.build();
-					}
-					""", registrations);
-			return new ErrorRequestMatcherBuilder(message);
-		}
-		if (servletPath.path() != null) {
-			logger.trace("Did not choose a default since there is a non-root DispatcherServlet mapping");
-			String message = String.format("""
-					This method cannot decide whether these patterns are Spring MVC patterns or not
-					since your Spring MVC mapping is mapped to a path and you have other servlet mappings.
-
-					For your reference, here is your servlet configuration: %s
-
-					To address this, you need to specify the servlet path for each endpoint.
-					You can use .forServletPattern in conjunction with requestMatchers do to this
-					like so:
-
-					@Bean
-					SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
-						http
-							.authorizeHttpRequests((authorize) -> authorize
-								.forServletPattern("/mvc/*", (mvc) -> mvc
-									.requestMatchers("/controller/**", "/endpoints/**")...
-								)
-								.forServletPattern("/h2-console/*", (h2) -> h2
-									.requestMatchers("/**")...
-								)
-							)
-							// ...
-						return http.build();
-					}
-					""", registrations);
-			return new ErrorRequestMatcherBuilder(message);
-		}
-		logger.trace("Defaulting to request-time checker since DispatcherServlet is mapped to root, but there are also "
-				+ "other servlet mappings");
-		return new DispatcherServletDelegatingRequestMatcherBuilder(MvcRequestMatcherBuilder.absolute(context),
-				AntPathRequestMatcherBuilder.absolute(), registrations);
-	}
-
-	static RequestMatcherBuilder createForServletPattern(ApplicationContext context, String pattern) {
-		Assert.notNull(pattern, "pattern cannot be null");
-		ServletRegistrationCollection registrations = ServletRegistrationCollection.registrations(context);
-		ServletRegistrationCollection.Registration registration = registrations.registrationByMapping(pattern);
-		Assert.notNull(registration, () -> String
-			.format("The given pattern %s doesn't seem to match any configured servlets: %s", pattern, registrations));
-		boolean isPathPattern = pattern.startsWith("/") && pattern.endsWith("/*");
-		if (isPathPattern) {
-			String path = pattern.substring(0, pattern.length() - 2);
-			return (registration.isDispatcherServlet()) ? MvcRequestMatcherBuilder.relativeTo(context, path)
-					: AntPathRequestMatcherBuilder.relativeTo(path);
-		}
-		return (registration.isDispatcherServlet()) ? MvcRequestMatcherBuilder.absolute(context)
-				: AntPathRequestMatcherBuilder.absolute();
-	}
-
-	private static class ErrorRequestMatcherBuilder implements RequestMatcherBuilder {
-
-		private final String errorMessage;
-
-		ErrorRequestMatcherBuilder(String errorMessage) {
-			this.errorMessage = errorMessage;
-		}
-
-		@Override
-		public RequestMatcher matcher(String pattern) {
-			throw new IllegalArgumentException(this.errorMessage);
-		}
-
-		@Override
-		public RequestMatcher matcher(HttpMethod method, String pattern) {
-			throw new IllegalArgumentException(this.errorMessage);
-		}
-
-		@Override
-		public RequestMatcher any() {
-			throw new IllegalArgumentException(this.errorMessage);
-		}
-
-	}
-
-}

+ 0 - 43
config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletPatternRequestMatcher.java

@@ -1,43 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import jakarta.servlet.http.HttpServletRequest;
-
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.util.Assert;
-
-final class ServletPatternRequestMatcher implements RequestMatcher {
-
-	final String pattern;
-
-	ServletPatternRequestMatcher(String pattern) {
-		Assert.notNull(pattern, "pattern cannot be null");
-		this.pattern = pattern;
-	}
-
-	@Override
-	public boolean matches(HttpServletRequest request) {
-		return this.pattern.equals(request.getHttpServletMapping().getPattern());
-	}
-
-	@Override
-	public String toString() {
-		return String.format("ServletPattern [pattern='%s']", this.pattern);
-	}
-
-}

+ 0 - 152
config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletRegistrationCollection.java

@@ -1,152 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import jakarta.servlet.ServletContext;
-import jakarta.servlet.ServletRegistration;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.context.WebApplicationContext;
-
-final class ServletRegistrationCollection {
-
-	private List<Registration> registrations;
-
-	private ServletRegistrationCollection() {
-		this.registrations = Collections.emptyList();
-	}
-
-	private ServletRegistrationCollection(List<Registration> registrations) {
-		this.registrations = registrations;
-	}
-
-	static ServletRegistrationCollection registrations(ApplicationContext context) {
-		if (!(context instanceof WebApplicationContext web)) {
-			return new ServletRegistrationCollection();
-		}
-		ServletContext servletContext = web.getServletContext();
-		if (servletContext == null) {
-			return new ServletRegistrationCollection();
-		}
-		Map<String, ? extends ServletRegistration> registrations = servletContext.getServletRegistrations();
-		if (registrations == null) {
-			return new ServletRegistrationCollection();
-		}
-		List<Registration> filtered = new ArrayList<>();
-		for (ServletRegistration registration : registrations.values()) {
-			Collection<String> mappings = registration.getMappings();
-			if (!CollectionUtils.isEmpty(mappings)) {
-				filtered.add(new Registration(registration));
-			}
-		}
-		return new ServletRegistrationCollection(filtered);
-	}
-
-	boolean isEmpty() {
-		return this.registrations.isEmpty();
-	}
-
-	Registration registrationByName(String name) {
-		for (Registration registration : this.registrations) {
-			if (registration.registration().getName().equals(name)) {
-				return registration;
-			}
-		}
-		return null;
-	}
-
-	Registration registrationByMapping(String target) {
-		for (Registration registration : this.registrations) {
-			for (String mapping : registration.registration().getMappings()) {
-				if (target.equals(mapping)) {
-					return registration;
-				}
-			}
-		}
-		return null;
-	}
-
-	ServletRegistrationCollection dispatcherServlets() {
-		List<Registration> dispatcherServlets = new ArrayList<>();
-		for (Registration registration : this.registrations) {
-			if (registration.isDispatcherServlet()) {
-				dispatcherServlets.add(registration);
-			}
-		}
-		return new ServletRegistrationCollection(dispatcherServlets);
-	}
-
-	ServletPath deduceOneServletPath() {
-		if (this.registrations.size() > 1) {
-			return null;
-		}
-		ServletRegistration registration = this.registrations.iterator().next().registration();
-		if (registration.getMappings().size() > 1) {
-			return null;
-		}
-		String mapping = registration.getMappings().iterator().next();
-		if ("/".equals(mapping)) {
-			return new ServletPath();
-		}
-		if (mapping.endsWith("/*")) {
-			return new ServletPath(mapping.substring(0, mapping.length() - 2));
-		}
-		return null;
-	}
-
-	@Override
-	public String toString() {
-		Map<String, Collection<String>> mappings = new LinkedHashMap<>();
-		for (Registration registration : this.registrations) {
-			mappings.put(registration.registration().getClassName(), registration.registration().getMappings());
-		}
-		return mappings.toString();
-	}
-
-	record Registration(ServletRegistration registration) {
-		boolean isDispatcherServlet() {
-			Class<?> dispatcherServlet = ClassUtils
-				.resolveClassName("org.springframework.web.servlet.DispatcherServlet", null);
-			try {
-				Class<?> clazz = Class.forName(this.registration.getClassName());
-				if (dispatcherServlet.isAssignableFrom(clazz)) {
-					return true;
-				}
-			}
-			catch (ClassNotFoundException ex) {
-				return false;
-			}
-			return false;
-		}
-	}
-
-	record ServletPath(String path) {
-		ServletPath() {
-			this(null);
-		}
-	}
-
-}

+ 0 - 7
config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryNoMvcTests.java

@@ -25,12 +25,8 @@ import org.springframework.http.HttpMethod;
 import org.springframework.security.test.support.ClassPathExclusions;
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.web.context.WebApplicationContext;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
 
 /**
  * Tests for {@link AbstractRequestMatcherRegistry} with no Spring MVC in the classpath
@@ -45,9 +41,6 @@ public class AbstractRequestMatcherRegistryNoMvcTests {
 	@BeforeEach
 	public void setUp() {
 		this.matcherRegistry = new TestRequestMatcherRegistry();
-		WebApplicationContext context = mock(WebApplicationContext.class);
-		given(context.getBeanNamesForType((Class<?>) any())).willReturn(new String[0]);
-		this.matcherRegistry.setApplicationContext(context);
 	}
 
 	@Test

+ 6 - 0
config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java

@@ -173,6 +173,12 @@ public class AbstractRequestMatcherRegistryTests {
 		assertThat(requestMatchers).isNotEmpty();
 		assertThat(requestMatchers).hasSize(1);
 		assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
+		servletContext.addServlet("servletOne", Servlet.class);
+		servletContext.addServlet("servletTwo", Servlet.class);
+		requestMatchers = this.matcherRegistry.requestMatchers("/**");
+		assertThat(requestMatchers).isNotEmpty();
+		assertThat(requestMatchers).hasSize(1);
+		assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
 	}
 
 	@Test

+ 0 - 349
config/src/test/java/org/springframework/security/config/annotation/web/configurers/AbstractRequestMatcherBuilderRegistryTests.java

@@ -1,349 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import java.util.List;
-import java.util.function.Consumer;
-
-import jakarta.servlet.Servlet;
-import jakarta.servlet.ServletContext;
-import org.assertj.core.api.AbstractObjectAssert;
-import org.assertj.core.api.ObjectAssert;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.config.MockServletContext;
-import org.springframework.security.config.annotation.ObjectPostProcessor;
-import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
-import org.springframework.security.web.util.matcher.AndRequestMatcher;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.test.util.ReflectionTestUtils;
-import org.springframework.web.context.support.GenericWebApplicationContext;
-import org.springframework.web.servlet.DispatcherServlet;
-import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.mockito.Mockito.mock;
-
-/**
- * Tests for {@link AbstractRequestMatcherBuilderRegistry}
- */
-class AbstractRequestMatcherBuilderRegistryTests {
-
-	@Test
-	void defaultServletMatchersWhenDefaultDispatcherServletThenMvc() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/mvc").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isNull();
-		assertThatMvc(matchers).pattern().isEqualTo("/mvc");
-		assertThatMvc(matchers).method().isNull();
-	}
-
-	@Test
-	void defaultServletHttpMethodMatchersWhenDefaultDispatcherServletThenMvc() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers(HttpMethod.GET, "/mvc").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isNull();
-		assertThatMvc(matchers).pattern().isEqualTo("/mvc");
-		assertThatMvc(matchers).method().isEqualTo(HttpMethod.GET);
-	}
-
-	@Test
-	void servletMatchersWhenPathDispatcherServletThenMvc() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*")
-			.requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-	}
-
-	@Test
-	void servletMatchersWhenAlsoExtraServletContainerMappingsThenMvc() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class);
-		servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
-		servletContext.addServlet("facesServlet", Servlet.class).addMapping("/faces/", "*.jsf", "*.faces", "*.xhtml");
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*")
-			.requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-	}
-
-	@Test
-	void defaultServletMatchersWhenOnlyDefaultServletThenAnt() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
-		assertThatAnt(matchers).pattern().isEqualTo("/controller");
-	}
-
-	@Test
-	void defaultDispatcherServletMatchersWhenNoHandlerMappingIntrospectorThenException() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
-			.isThrownBy(() -> defaultServlet(servletContext, (context) -> {
-			}));
-	}
-
-	@Test
-	void dispatcherServletMatchersWhenNoHandlerMappingIntrospectorThenException() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
-			.isThrownBy(() -> servletPattern(servletContext, (context) -> {
-			}, "/mvc/*"));
-	}
-
-	@Test
-	void matchersWhenNoDispatchServletThenAnt() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/services/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
-		assertThatAnt(matchers).pattern().isEqualTo("/services/endpoint");
-	}
-
-	@Test
-	void servletMatchersWhenMixedServletsThenDeterminesByServletPath() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
-		List<RequestMatcher> matchers = servletPattern(servletContext, "/services/*")
-			.requestMatchers("/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
-		assertThatAnt(matchers).pattern().isEqualTo("/services/endpoint");
-		matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isNull();
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-	}
-
-	@Test
-	void servletMatchersWhenDispatcherServletNotDefaultThenDeterminesByServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*")
-			.requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-		matchers = defaultServlet(servletContext).requestMatchers("/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
-		assertThatAnt(matchers).pattern().isEqualTo("/endpoint");
-	}
-
-	@Test
-	void servletHttpMatchersWhenDispatcherServletNotDefaultThenDeterminesByServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		List<RequestMatcher> matchers = servletPattern(servletContext, "/mvc/*").requestMatchers(HttpMethod.GET,
-				"/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).method().isEqualTo(HttpMethod.GET);
-		assertThatMvc(matchers).servletPath().isEqualTo("/mvc");
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-		matchers = defaultServlet(servletContext).requestMatchers(HttpMethod.GET, "/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
-		assertThatAnt(matchers).method().isEqualTo(HttpMethod.GET);
-		assertThatAnt(matchers).pattern().isEqualTo("/endpoint");
-	}
-
-	@Test
-	void servletMatchersWhenTwoDispatcherServletsThenDeterminesByServletPath() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("two", DispatcherServlet.class).addMapping("/other/*");
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isNull();
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-		matchers = servletPattern(servletContext, "/other/*").requestMatchers("/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isEqualTo("/other");
-		assertThatMvc(matchers).pattern().isEqualTo("/endpoint");
-	}
-
-	@Test
-	void servletMatchersWhenMoreThanOneMappingThenDeterminesByServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isNull();
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-		matchers = servletPattern(servletContext, "/two/*").requestMatchers("/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isEqualTo("/two");
-		assertThatMvc(matchers).pattern().isEqualTo("/endpoint");
-	}
-
-	@Test
-	void servletMatchersWhenMoreThanOneMappingAndDefaultServletsThenDeterminesByServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
-		servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isNull();
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-		matchers = servletPattern(servletContext, "/two/*").requestMatchers("/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isEqualTo("/two");
-		assertThatMvc(matchers).pattern().isEqualTo("/endpoint");
-	}
-
-	@Test
-	void defaultServletWhenDispatcherServletThenMvc() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
-		List<RequestMatcher> matchers = defaultServlet(servletContext).requestMatchers("/controller").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(MvcRequestMatcher.class);
-		assertThatMvc(matchers).servletPath().isNull();
-		assertThatMvc(matchers).pattern().isEqualTo("/controller");
-		matchers = servletPattern(servletContext, "/services/*").requestMatchers("/endpoint").matchers;
-		assertThat(matchers).hasSize(1).hasOnlyElementsOfType(AntPathRequestMatcher.class);
-		assertThatAnt(matchers).pattern().isEqualTo("/services/endpoint");
-	}
-
-	@Test
-	void defaultServletWhenNoDefaultServletThenException() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
-		assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> defaultServlet(servletContext));
-	}
-
-	@Test
-	void servletPathWhenNoMatchingServletThenException() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		assertThatExceptionOfType(IllegalArgumentException.class)
-			.isThrownBy(() -> servletPattern(servletContext, "/wrong/*"));
-	}
-
-	TestServletRequestMatcherRegistry defaultServlet(ServletContext servletContext) {
-		return servletPattern(servletContext, "/");
-	}
-
-	TestServletRequestMatcherRegistry defaultServlet(ServletContext servletContext,
-			Consumer<GenericWebApplicationContext> consumer) {
-		return servletPattern(servletContext, consumer, "/");
-	}
-
-	TestServletRequestMatcherRegistry servletPattern(ServletContext servletContext, String pattern) {
-		return servletPattern(servletContext, (context) -> {
-			context.registerBean("mvcHandlerMappingIntrospector", HandlerMappingIntrospector.class);
-			context.registerBean(ObjectPostProcessor.class, () -> mock(ObjectPostProcessor.class));
-		}, pattern);
-	}
-
-	TestServletRequestMatcherRegistry servletPattern(ServletContext servletContext,
-			Consumer<GenericWebApplicationContext> consumer, String pattern) {
-		GenericWebApplicationContext context = new GenericWebApplicationContext(servletContext);
-		consumer.accept(context);
-		context.refresh();
-		return new TestServletRequestMatcherRegistry(context, pattern);
-	}
-
-	static MvcRequestMatcherAssert assertThatMvc(List<RequestMatcher> matchers) {
-		RequestMatcher matcher = matchers.get(0);
-		if (matcher instanceof AndRequestMatcher matching) {
-			List<RequestMatcher> and = (List<RequestMatcher>) ReflectionTestUtils.getField(matching, "requestMatchers");
-			assertThat(and).hasSize(2);
-			assertThat(and.get(1)).isInstanceOf(MvcRequestMatcher.class);
-			return new MvcRequestMatcherAssert((MvcRequestMatcher) and.get(1));
-		}
-		assertThat(matcher).isInstanceOf(MvcRequestMatcher.class);
-		return new MvcRequestMatcherAssert((MvcRequestMatcher) matcher);
-	}
-
-	static AntPathRequestMatcherAssert assertThatAnt(List<RequestMatcher> matchers) {
-		RequestMatcher matcher = matchers.get(0);
-		if (matcher instanceof AndRequestMatcher matching) {
-			List<RequestMatcher> and = (List<RequestMatcher>) ReflectionTestUtils.getField(matching, "requestMatchers");
-			assertThat(and).hasSize(2);
-			assertThat(and.get(1)).isInstanceOf(AntPathRequestMatcher.class);
-			return new AntPathRequestMatcherAssert((AntPathRequestMatcher) and.get(1));
-		}
-		assertThat(matcher).isInstanceOf(AntPathRequestMatcher.class);
-		return new AntPathRequestMatcherAssert((AntPathRequestMatcher) matcher);
-	}
-
-	static final class TestServletRequestMatcherRegistry
-			extends AbstractRequestMatcherBuilderRegistry<TestServletRequestMatcherRegistry> {
-
-		List<RequestMatcher> matchers;
-
-		TestServletRequestMatcherRegistry(ApplicationContext context, String pattern) {
-			super(context, RequestMatcherBuilders.createForServletPattern(context, pattern));
-		}
-
-		@Override
-		protected TestServletRequestMatcherRegistry chainRequestMatchers(List<RequestMatcher> requestMatchers) {
-			this.matchers = requestMatchers;
-			return this;
-		}
-
-	}
-
-	static final class MvcRequestMatcherAssert extends ObjectAssert<MvcRequestMatcher> {
-
-		private MvcRequestMatcherAssert(MvcRequestMatcher matcher) {
-			super(matcher);
-		}
-
-		AbstractObjectAssert<?, ?> servletPath() {
-			return extracting("servletPath");
-		}
-
-		AbstractObjectAssert<?, ?> pattern() {
-			return extracting("pattern");
-		}
-
-		AbstractObjectAssert<?, ?> method() {
-			return extracting("method");
-		}
-
-	}
-
-	static final class AntPathRequestMatcherAssert extends ObjectAssert<AntPathRequestMatcher> {
-
-		private AntPathRequestMatcherAssert(AntPathRequestMatcher matcher) {
-			super(matcher);
-		}
-
-		AbstractObjectAssert<?, ?> pattern() {
-			return extracting("pattern");
-		}
-
-		AbstractObjectAssert<?, ?> method() {
-			return extracting("httpMethod");
-		}
-
-	}
-
-}

+ 5 - 363
config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java

@@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.configurers;
 
 import java.util.function.Supplier;
 
-import jakarta.servlet.Servlet;
 import jakarta.servlet.http.HttpServletRequest;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -27,7 +26,6 @@ import org.springframework.beans.factory.BeanCreationException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpMethod;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
 import org.springframework.security.authentication.RememberMeAuthenticationToken;
@@ -35,8 +33,6 @@ import org.springframework.security.authentication.TestAuthentication;
 import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.authorization.AuthorizationEventPublisher;
 import org.springframework.security.authorization.AuthorizationManager;
-import org.springframework.security.config.MockServletContext;
-import org.springframework.security.config.TestMockHttpServletMappings;
 import org.springframework.security.config.annotation.ObjectPostProcessor;
 import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -62,7 +58,6 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.servlet.DispatcherServlet;
 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
 
@@ -76,7 +71,6 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
@@ -127,7 +121,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
 	public void configureWhenMvcMatcherAfterAnyRequestThenException() {
 		assertThatExceptionOfType(BeanCreationException.class)
 			.isThrownBy(() -> this.spring.register(AfterAnyRequestConfig.class).autowire())
-			.withMessageContaining("Can't configure requestMatchers after anyRequest");
+			.withMessageContaining("Can't configure mvcMatchers after anyRequest");
 	}
 
 	@Test
@@ -368,7 +362,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
 
 	@Test
 	public void getWhenServletPathRoleAdminConfiguredAndRoleIsUserThenRespondsWithForbidden() throws Exception {
-		this.spring.register(MvcServletPathConfig.class, BasicController.class).autowire();
+		this.spring.register(ServletPathConfig.class, BasicController.class).autowire();
 		// @formatter:off
 		MockHttpServletRequestBuilder requestWithUser = get("/spring/")
 				.servletPath("/spring")
@@ -381,7 +375,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
 	@Test
 	public void getWhenServletPathRoleAdminConfiguredAndRoleIsUserAndWithoutServletPathThenRespondsWithForbidden()
 			throws Exception {
-		this.spring.register(MvcServletPathConfig.class, BasicController.class).autowire();
+		this.spring.register(ServletPathConfig.class, BasicController.class).autowire();
 		// @formatter:off
 		MockHttpServletRequestBuilder requestWithUser = get("/")
 				.with(user("user")
@@ -392,7 +386,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
 
 	@Test
 	public void getWhenServletPathRoleAdminConfiguredAndRoleIsAdminThenRespondsWithOk() throws Exception {
-		this.spring.register(MvcServletPathConfig.class, BasicController.class).autowire();
+		this.spring.register(ServletPathConfig.class, BasicController.class).autowire();
 		// @formatter:off
 		MockHttpServletRequestBuilder requestWithAdmin = get("/spring/")
 				.servletPath("/spring")
@@ -602,200 +596,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
 		this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
 	}
 
-	@Test
-	public void configureWhenNoDispatcherServletThenSucceeds() throws Exception {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		this.spring.register(AuthorizeHttpRequestsConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/path")).andExpect(status().isNotFound());
-	}
-
-	@Test
-	public void configureWhenOnlyDispatcherServletThenSucceeds() throws Exception {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		this.spring.register(AuthorizeHttpRequestsConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/mvc/path").servletPath("/mvc")).andExpect(status().isNotFound());
-		this.mvc.perform(get("/mvc")).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	public void configureWhenMultipleServletsThenSucceeds() throws Exception {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
-		this.spring.register(AuthorizeHttpRequestsConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/path").with(servletPath("/path"))).andExpect(status().isNotFound());
-	}
-
-	@Test
-	public void configureWhenAmbiguousServletsThenWiringException() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
-		assertThatExceptionOfType(BeanCreationException.class)
-			.isThrownBy(() -> this.spring.register(AuthorizeHttpRequestsConfig.class)
-				.postProcessor((context) -> context.setServletContext(servletContext))
-				.autowire());
-	}
-
-	@Test
-	void defaultServletMatchersWhenDefaultServletThenPermits() throws Exception {
-		this.spring.register(DefaultServletConfig.class)
-			.postProcessor((context) -> context.setServletContext(MockServletContext.mvc()))
-			.autowire();
-		this.mvc.perform(get("/path/path").with(defaultServlet())).andExpect(status().isNotFound());
-		this.mvc.perform(get("/path/path").with(servletPath("/path"))).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	void defaultServletHttpMethodMatchersWhenDefaultServletThenPermits() throws Exception {
-		this.spring.register(DefaultServletConfig.class)
-			.postProcessor((context) -> context.setServletContext(MockServletContext.mvc()))
-			.autowire();
-		this.mvc.perform(get("/path/method").with(defaultServlet())).andExpect(status().isNotFound());
-		this.mvc.perform(head("/path/method").with(defaultServlet())).andExpect(status().isUnauthorized());
-		this.mvc.perform(get("/path/method").with(servletPath("/path"))).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	void defaultServletWhenNoDefaultServletThenWiringException() {
-		assertThatExceptionOfType(BeanCreationException.class)
-			.isThrownBy(() -> this.spring.register(DefaultServletConfig.class)
-				.postProcessor((context) -> context.setServletContext(new MockServletContext()))
-				.autowire());
-	}
-
-	@Test
-	void servletPathMatchersWhenMatchingServletThenPermits() throws Exception {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
-		this.spring.register(ServletPathConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/path/path").with(servletPath("/path"))).andExpect(status().isNotFound());
-		this.mvc.perform(get("/path/path").with(defaultServlet())).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	void servletPathHttpMethodMatchersWhenMatchingServletThenPermits() throws Exception {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("path", Servlet.class).addMapping("/path/*");
-		this.spring.register(ServletPathConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/path/method").with(servletPath("/path"))).andExpect(status().isNotFound());
-		this.mvc.perform(head("/path/method").with(servletPath("/path"))).andExpect(status().isUnauthorized());
-		this.mvc.perform(get("/path/method").with(defaultServlet())).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	void servletPathWhenNoMatchingPathThenWiringException() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		assertThatExceptionOfType(BeanCreationException.class)
-			.isThrownBy(() -> this.spring.register(ServletPathConfig.class)
-				.postProcessor((context) -> context.setServletContext(servletContext))
-				.autowire());
-	}
-
-	@Test
-	void servletMappingMatchersWhenMatchingServletThenPermits() throws Exception {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("jsp", Servlet.class).addMapping("*.jsp");
-		this.spring.register(ServletMappingConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/path/file.jsp").with(servletExtension(".jsp"))).andExpect(status().isNotFound());
-		this.mvc.perform(get("/path/file.jsp").with(defaultServlet())).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	void servletMappingHttpMethodMatchersWhenMatchingServletThenPermits() throws Exception {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("jsp", Servlet.class).addMapping("*.jsp");
-		this.spring.register(ServletMappingConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/method/file.jsp").with(servletExtension(".jsp"))).andExpect(status().isNotFound());
-		this.mvc.perform(head("/method/file.jsp").with(servletExtension(".jsp"))).andExpect(status().isUnauthorized());
-		this.mvc.perform(get("/method/file.jsp").with(defaultServlet())).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	void servletMappingWhenNoMatchingExtensionThenWiringException() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		assertThatExceptionOfType(BeanCreationException.class)
-			.isThrownBy(() -> this.spring.register(ServletMappingConfig.class)
-				.postProcessor((context) -> context.setServletContext(servletContext))
-				.autowire());
-	}
-
-	@Test
-	void anyRequestWhenUsedWithDefaultServletThenDoesNotWire() {
-		assertThatExceptionOfType(BeanCreationException.class)
-			.isThrownBy(() -> this.spring.register(MixedServletEndpointConfig.class).autowire())
-			.withMessageContaining("forServletPattern");
-	}
-
-	@Test
-	void servletWhenNoMatchingPathThenDenies() throws Exception {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp");
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		this.spring.register(DefaultServletAndServletPathConfig.class)
-			.postProcessor((context) -> context.setServletContext(servletContext))
-			.autowire();
-		this.mvc.perform(get("/js/color.js").with(servletPath("/js"))).andExpect(status().isUnauthorized());
-		this.mvc.perform(get("/mvc/controller").with(defaultServlet())).andExpect(status().isUnauthorized());
-		this.mvc.perform(get("/js/color.js").with(defaultServlet())).andExpect(status().isNotFound());
-		this.mvc.perform(get("/mvc/controller").with(servletPath("/mvc"))).andExpect(status().isUnauthorized());
-		this.mvc.perform(get("/mvc/controller").with(user("user")).with(servletPath("/mvc")))
-			.andExpect(status().isNotFound());
-	}
-
-	@Test
-	void permitAllWhenDefaultServletThenDoesNotWire() {
-		assertThatExceptionOfType(BeanCreationException.class)
-			.isThrownBy(() -> this.spring.register(MixedServletPermitAllConfig.class).autowire())
-			.withMessageContaining("forServletPattern");
-	}
-
-	static RequestPostProcessor defaultServlet() {
-		return (request) -> {
-			String uri = request.getRequestURI();
-			request.setHttpServletMapping(TestMockHttpServletMappings.defaultMapping());
-			request.setServletPath(uri);
-			request.setPathInfo("");
-			return request;
-		};
-	}
-
-	static RequestPostProcessor servletPath(String path) {
-		return (request) -> {
-			String uri = request.getRequestURI();
-			request.setHttpServletMapping(TestMockHttpServletMappings.path(request, path));
-			request.setServletPath(path);
-			request.setPathInfo(uri.substring(path.length()));
-			return request;
-		};
-	}
-
-	static RequestPostProcessor servletExtension(String extension) {
-		return (request) -> {
-			String uri = request.getRequestURI();
-			request.setHttpServletMapping(TestMockHttpServletMappings.extension(request, extension));
-			request.setServletPath(uri);
-			request.setPathInfo("");
-			return request;
-		};
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class GrantedAuthorityDefaultHasRoleConfig {
@@ -893,7 +693,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
 
 	@Configuration
 	@EnableWebSecurity
-	@EnableWebMvc
 	static class AfterAnyRequestConfig {
 
 		@Bean
@@ -1155,7 +954,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
 	@Configuration
 	@EnableWebMvc
 	@EnableWebSecurity
-	static class MvcServletPathConfig {
+	static class ServletPathConfig {
 
 		@Bean
 		SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
@@ -1337,163 +1136,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
 
 	}
 
-	@Configuration
-	@EnableWebSecurity
-	@EnableWebMvc
-	static class AuthorizeHttpRequestsConfig {
-
-		@Bean
-		SecurityFilterChain chain(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic(withDefaults())
-				.authorizeHttpRequests((requests) -> requests
-					.requestMatchers("/path/**").permitAll()
-					.anyRequest().authenticated()
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
-	@Configuration
-	@EnableWebSecurity
-	@EnableWebMvc
-	static class DefaultServletConfig {
-
-		@Bean
-		SecurityFilterChain chain(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic(withDefaults())
-				.authorizeHttpRequests((requests) -> requests
-					.forServletPattern("/", (root) -> root
-						.requestMatchers(HttpMethod.GET, "/path/method/**").permitAll()
-						.requestMatchers("/path/path/**").permitAll()
-						.anyRequest().authenticated()
-					)
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
-	@Configuration
-	@EnableWebSecurity
-	@EnableWebMvc
-	static class ServletPathConfig {
-
-		@Bean
-		SecurityFilterChain chain(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic(withDefaults())
-				.authorizeHttpRequests((requests) -> requests
-					.forServletPattern("/path/*", (root) -> root
-						.requestMatchers(HttpMethod.GET, "/method/**").permitAll()
-						.requestMatchers("/path/**").permitAll()
-						.anyRequest().authenticated()
-					)
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
-	@Configuration
-	@EnableWebSecurity
-	@EnableWebMvc
-	static class ServletMappingConfig {
-
-		@Bean
-		SecurityFilterChain chain(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic(withDefaults())
-				.authorizeHttpRequests((requests) -> requests
-					.forServletPattern("*.jsp", (jsp) -> jsp
-						.requestMatchers(HttpMethod.GET, "/method/**").permitAll()
-						.requestMatchers("/path/**").permitAll()
-						.anyRequest().authenticated()
-					)
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
-	@Configuration
-	@EnableWebSecurity
-	@EnableWebMvc
-	static class MixedServletEndpointConfig {
-
-		@Bean
-		SecurityFilterChain chain(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic(withDefaults())
-				.authorizeHttpRequests((requests) -> requests
-					.forServletPattern("/", (root) -> root.anyRequest().permitAll())
-					.anyRequest().authenticated()
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
-	@Configuration
-	@EnableWebSecurity
-	@EnableWebMvc
-	static class MixedServletPermitAllConfig {
-
-		@Bean
-		SecurityFilterChain chain(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.formLogin((form) -> form.loginPage("/page").permitAll())
-				.authorizeHttpRequests((requests) -> requests
-					.forServletPattern("/", (root) -> root
-						.anyRequest().authenticated()
-					)
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
-	@Configuration
-	@EnableWebSecurity
-	@EnableWebMvc
-	static class DefaultServletAndServletPathConfig {
-
-		@Bean
-		SecurityFilterChain chain(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic(withDefaults())
-				.authorizeHttpRequests((requests) -> requests
-					.forServletPattern("/", (root) -> root
-						.requestMatchers("/js/**", "/css/**").permitAll()
-					)
-					.forServletPattern("/mvc/*", (mvc) -> mvc
-						.requestMatchers("/controller/**").authenticated()
-					)
-					.forServletPattern("*.jsp", (jsp) -> jsp
-						.anyRequest().authenticated()
-					)
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
 	@Configuration
 	static class AuthorizationEventPublisherConfig {
 

+ 0 - 198
config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherBuildersTests.java

@@ -1,198 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import java.util.List;
-import java.util.function.Consumer;
-
-import jakarta.servlet.Servlet;
-import jakarta.servlet.ServletContext;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.http.HttpMethod;
-import org.springframework.security.config.MockServletContext;
-import org.springframework.security.config.annotation.ObjectPostProcessor;
-import org.springframework.security.config.annotation.web.configurers.DispatcherServletDelegatingRequestMatcherBuilder.DispatcherServletDelegatingRequestMatcher;
-import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.test.util.ReflectionTestUtils;
-import org.springframework.web.context.support.GenericWebApplicationContext;
-import org.springframework.web.servlet.DispatcherServlet;
-import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.mockito.Mockito.mock;
-
-public class RequestMatcherBuildersTests {
-
-	@Test
-	void matchersWhenDefaultDispatcherServletThenMvc() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
-		List<RequestMatcher> matchers = builder.matchers("/mvc");
-		assertThat(matchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
-		MvcRequestMatcher matcher = (MvcRequestMatcher) matchers.get(0);
-		assertThat(ReflectionTestUtils.getField(matcher, "servletPath")).isNull();
-		assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/mvc");
-	}
-
-	@Test
-	void httpMethodMatchersWhenDefaultDispatcherServletThenMvc() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
-		List<RequestMatcher> matchers = builder.matchers(HttpMethod.GET, "/mvc");
-		assertThat(matchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
-		MvcRequestMatcher matcher = (MvcRequestMatcher) matchers.get(0);
-		assertThat(ReflectionTestUtils.getField(matcher, "servletPath")).isNull();
-		assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/mvc");
-		assertThat(ReflectionTestUtils.getField(matcher, "method")).isEqualTo(HttpMethod.GET);
-	}
-
-	@Test
-	void matchersWhenPathDispatcherServletThenMvc() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
-		List<RequestMatcher> matchers = builder.matchers("/controller");
-		assertThat(matchers.get(0)).isInstanceOf(MvcRequestMatcher.class);
-		MvcRequestMatcher matcher = (MvcRequestMatcher) matchers.get(0);
-		assertThat(ReflectionTestUtils.getField(matcher, "servletPath")).isEqualTo("/mvc");
-		assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/controller");
-	}
-
-	@Test
-	void matchersWhenAlsoExtraServletContainerMappingsThenRequiresServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
-		servletContext.addServlet("facesServlet", Servlet.class).addMapping("/faces/", "*.jsf", "*.faces", "*.xhtml");
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		assertThatExceptionOfType(IllegalArgumentException.class)
-			.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path"))
-			.withMessageContaining(".forServletPattern");
-	}
-
-	@Test
-	void matchersWhenOnlyDefaultServletThenAnt() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
-		List<RequestMatcher> matchers = builder.matchers("/controller");
-		assertThat(matchers.get(0)).isInstanceOf(AntPathRequestMatcher.class);
-		AntPathRequestMatcher matcher = (AntPathRequestMatcher) matchers.get(0);
-		assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/controller");
-	}
-
-	@Test
-	void matchersWhenNoHandlerMappingIntrospectorThenAnt() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		RequestMatcherBuilder builder = requestMatchersBuilder(servletContext, (context) -> {
-		});
-		List<RequestMatcher> matchers = builder.matchers("/controller");
-		assertThat(matchers.get(0)).isInstanceOf(AntPathRequestMatcher.class);
-		AntPathRequestMatcher matcher = (AntPathRequestMatcher) matchers.get(0);
-		assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/controller");
-	}
-
-	@Test
-	void matchersWhenNoDispatchServletThenAnt() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
-		RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
-		List<RequestMatcher> matchers = builder.matchers("/services/endpoint");
-		assertThat(matchers.get(0)).isInstanceOf(AntPathRequestMatcher.class);
-		AntPathRequestMatcher matcher = (AntPathRequestMatcher) matchers.get(0);
-		assertThat(ReflectionTestUtils.getField(matcher, "pattern")).isEqualTo("/services/endpoint");
-	}
-
-	@Test
-	void matchersWhenMixedServletsThenServletPathDelegating() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("messageDispatcherServlet", Servlet.class).addMapping("/services/*");
-		RequestMatcherBuilder builder = requestMatchersBuilder(servletContext);
-		assertThat(builder.matchers("/services/endpoint").get(0))
-			.isInstanceOf(DispatcherServletDelegatingRequestMatcher.class);
-	}
-
-	@Test
-	void matchersWhenDispatcherServletNotDefaultAndOtherServletsThenRequiresServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		assertThatExceptionOfType(IllegalArgumentException.class)
-			.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
-			.withMessageContaining(".forServletPattern");
-	}
-
-	@Test
-	void httpMatchersWhenDispatcherServletNotDefaultAndOtherServletsThenRequiresServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("default", Servlet.class).addMapping("/");
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/mvc/*");
-		assertThatExceptionOfType(IllegalArgumentException.class)
-			.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/pattern"))
-			.withMessageContaining(".forServletPattern");
-	}
-
-	@Test
-	void matchersWhenTwoDispatcherServletsThenException() {
-		MockServletContext servletContext = MockServletContext.mvc();
-		servletContext.addServlet("two", DispatcherServlet.class).addMapping("/other/*");
-		assertThatExceptionOfType(IllegalArgumentException.class)
-			.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
-			.withMessageContaining(".forServletPattern");
-	}
-
-	@Test
-	void matchersWhenMoreThanOneMappingThenException() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
-		assertThatExceptionOfType(IllegalArgumentException.class)
-			.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
-			.withMessageContaining(".forServletPattern");
-	}
-
-	@Test
-	void matchersWhenMoreThanOneMappingAndDefaultServletsThenRequiresServletPath() {
-		MockServletContext servletContext = new MockServletContext();
-		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/", "/two/*");
-		servletContext.addServlet("jspServlet", Servlet.class).addMapping("*.jsp", "*.jspx");
-		assertThatExceptionOfType(IllegalArgumentException.class)
-			.isThrownBy(() -> requestMatchersBuilder(servletContext).matcher("/path/**"))
-			.withMessageContaining(".forServletPattern");
-	}
-
-	RequestMatcherBuilder requestMatchersBuilder(ServletContext servletContext) {
-		return requestMatchersBuilder(servletContext, (context) -> {
-			context.registerBean("mvcHandlerMappingIntrospector", HandlerMappingIntrospector.class,
-					() -> mock(HandlerMappingIntrospector.class));
-			context.registerBean(ObjectPostProcessor.class, () -> mock(ObjectPostProcessor.class));
-		});
-	}
-
-	RequestMatcherBuilder requestMatchersBuilder(ServletContext servletContext,
-			Consumer<GenericWebApplicationContext> consumer) {
-		GenericWebApplicationContext context = new GenericWebApplicationContext(servletContext);
-		consumer.accept(context);
-		context.refresh();
-		return RequestMatcherBuilders.createDefault(context);
-	}
-
-}

+ 0 - 64
config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletPatternRequestMatcherTests.java

@@ -1,64 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.config.annotation.web.configurers;
-
-import org.junit.jupiter.api.Test;
-
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.security.config.TestMockHttpServletMappings;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests for {@link ServletPatternRequestMatcher}
- */
-class ServletPatternRequestMatcherTests {
-
-	ServletPatternRequestMatcher matcher = new ServletPatternRequestMatcher("*.jsp");
-
-	@Test
-	void matchesWhenDefaultServletThenTrue() {
-		MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
-		request.setHttpServletMapping(TestMockHttpServletMappings.extension(request, ".jsp"));
-		assertThat(this.matcher.matches(request)).isTrue();
-	}
-
-	@Test
-	void matchesWhenNotDefaultServletThenFalse() {
-		MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
-		request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/a"));
-		request.setServletPath("/a/uri.jsp");
-		assertThat(this.matcher.matches(request)).isFalse();
-	}
-
-	@Test
-	void matcherWhenDefaultServletThenTrue() {
-		MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
-		request.setHttpServletMapping(TestMockHttpServletMappings.extension(request, ".jsp"));
-		request.setServletPath("/a/uri.jsp");
-		assertThat(this.matcher.matcher(request).isMatch()).isTrue();
-	}
-
-	@Test
-	void matcherWhenNotDefaultServletThenFalse() {
-		MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a/uri.jsp");
-		request.setHttpServletMapping(TestMockHttpServletMappings.path(request, "/a"));
-		request.setServletPath("/a/uri.jsp");
-		assertThat(this.matcher.matcher(request).isMatch()).isFalse();
-	}
-
-}

+ 32 - 118
docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc

@@ -571,156 +571,70 @@ http {
 ----
 ====
 
-[[match-by-servlet-path]]
-[[mvc-not-default-servlet]]
 [[match-by-mvc]]
-=== Matching by Servlet Pattern
+=== Using an MvcRequestMatcher
 
-Generally speaking, you can use `requestMatchers(String...)` and `requestMatchers(HttpMethod, String...)` as demonstrated above.
+Generally speaking, you can use `requestMatchers(String)` as demonstrated above.
 
 However, if you map Spring MVC to a different servlet path, then you need to account for that in your security configuration.
 
-For example, if Spring MVC is mapped to `/mvc` instead of `/` (the default), then you may have an endpoint like `/mvc/my/controller` that you want to authorize.
+For example, if Spring MVC is mapped to `/spring-mvc` instead of `/` (the default), then you may have an endpoint like `/spring-mvc/my/controller` that you want to authorize.
 
-If you have multiple servlets, and `DispatcherServlet` is mapped in this way, you'll see an error that's something like this:
-
-[source,bash]
-----
-This method cannot decide whether these patterns are Spring MVC patterns or not
-
-...
-
-For your reference, here is your servlet configuration: {default=[/], dispatcherServlet=[/mvc/*]}
-
-To address this, you need to specify the servlet path or pattern for each endpoint.
-You can use .forServletPattern in conjunction with requestMatchers do to this
-----
-
-You can use `.forServletPattern` (or construct your own `MvcRequestMatcher` instance) to split the servlet path and the controller path in your configuration, like so:
+You need to use `MvcRequestMatcher` to split the servlet path and the controller path in your configuration like so:
 
 .Match by MvcRequestMatcher
 ====
 .Java
 [source,java,role="primary"]
 ----
+@Bean
+MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
+	return new MvcRequestMatcher.Builder(introspector).servletPath("/spring-mvc");
+}
+
 @Bean
 SecurityFilterChain appEndpoints(HttpSecurity http, MvcRequestMatcher.Builder mvc) {
 	http
         .authorizeHttpRequests((authorize) -> authorize
-            .forServletPattern("/mvc/*", (mvc) -> mvc
-                .requestMatchers("/my/resource/**").hasAuthority("resource:read")
-                .anyRequest().authenticated()
-            )
+            .requestMatchers(mvc.pattern("/my/controller/**")).hasAuthority("controller")
+            .anyRequest().authenticated()
         );
 
 	return http.build();
 }
 ----
-====
-
-where `/mvc/*` is the matching pattern in your servlet configuration listed in the error message.
-
-This need can arise in at least two different ways:
-
-* If you use the `spring.mvc.servlet.path` Boot property to change the default path (`/`) to something else
-* If you register more than one Spring MVC `DispatcherServlet` (thus requiring that one of them not be the default servlet)
-
-Note that when either of these cases come up, all URIs need to be fully-qualified as above.
-
-For example, consider a more sophisticated setup where you have Spring MVC resources mapped to `/mvc/*` and Spring Boot H2 Console mapped to `/h2-console/*`.
-In that case, each URI can be made absolute, listing the servlet path like so:
 
-.Match by Servlet Path
-====
-.Java
-[source,java,role="primary"]
+.Kotlin
+[source,kotlin,role="secondary"]
 ----
 @Bean
-SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .forServletPattern("/mvc/*", (mvc) -> mvc
-                .requestMatchers("/my/resource/**").hasAuthority("resource:read")
-            )
-            .forServletPattern("/h2-console/*", (h2) -> h2
-                .anyRequest().hasAuthority("h2")
-            )
-        )
-    // ...
-}
-----
-====
-
-Alternatively, you can do one of three things to remove the need to disambiguate:
-
-1. Always deploy `DispatcherServlet` to `/` (the default behavior)
-+
-When `DispatcherServlet` is mapped to `/`, it's clear that all the URIs supplied in `requestMatchers(String)` are absolute URIs.
-Because of that, there is no ambiguity when interpreting them.
-+
-2. Remove all other servlets
-+
-When there is only `DispatcherServlet`, it's clear that all the URIs supplied in `requestMatchers(String)` are relative to the Spring MVC configuration.
-Because of that, there is no ambiguity when interpreting them.
-
-At times, servlet containers add other servlets by default that you aren't actually using.
-So, if these aren't needed, remove them, bringing you down to just `DispatcherServlet`.
-+
-3. Create an `HttpRequestHandler` so that `DispatcherServlet` dispatches to your servlets instead of your servlet container.
-+
-If you are deploying Spring MVC to a separate path to allow your container to serve static resources, consider instead {spring-framework-reference-url}web/webmvc/mvc-config/default-servlet-handler.html#page-title[notifying Spring MVC about this].
-Or, if you have a custom servlet, publishing {spring-framework-api-url}org/springframework/web/servlet/mvc/HttpRequestHandlerAdapter.html[a custom `HttpRequestHandler` bean within {spring-framework-api-url}org/springframework/web/servlet/DispatcherServlet.html[the `DispatcherServlet` configuration] instead.
-+
-
-=== Matching by the Default Servlet
-
-You can also match more generally by the matching pattern specified in your servlet configuration.
-
-For example, to match the default servlet (whichever servlet is mapped to `/`), use `forServletPattern` like so:
+fun mvc(introspector: HandlerMappingIntrospector): MvcRequestMatcher.Builder =
+    MvcRequestMatcher.Builder(introspector).servletPath("/spring-mvc");
 
-.Match by the Default Servlet
-====
-.Java
-[source,java,role="primary"]
-----
 @Bean
-SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .forServletPattern("/", (root) -> root
-                .requestMatchers("/my/resource/**").hasAuthority("resource:read")
-            )
-        )
-    // ...
-}
+fun appEndpoints(http: HttpSecurity, mvc: MvcRequestMatcher.Builder): SecurityFilterChain =
+    http {
+        authorizeHttpRequests {
+            authorize(mvc.pattern("/my/controller/**"), hasAuthority("controller"))
+            authorize(anyRequest, authenticated)
+        }
+    }
 ----
-====
 
-Such will match on requests that the servlet container matches to your default servlet that start with the URI `/my/resource`.
-
-=== Matching by an Extension Servlet
-
-Or, to match to an extension servlet (like a servlet mapped to `*.jsp`), use `forServletPattern` as follows:
-
-.Match by an Extension Servlet
-====
-.Java
-[source,java,role="primary"]
+.Xml
+[source,xml,role="secondary"]
 ----
-@Bean
-SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
-    http
-        .authorizeHttpRequests((authorize) -> authorize
-            .forServletPattern("*.jsp", (jsp) -> jsp
-                .requestMatchers("/my/resource/**").hasAuthority("resource:read")
-            )
-        )
-    // ...
-}
+<http>
+    <intercept-url servlet-path="/spring-mvc" pattern="/my/controller/**" access="hasAuthority('controller')"/>
+    <intercept-url pattern="/**" access="authenticated"/>
+</http>
 ----
 ====
 
-Such will match on requests that the servlet container matches to your `*.jsp` servlet that start with the URI `/my/resource` (for example a request like `/my/resource/page.jsp`).
+This need can arise in at least two different ways:
+
+* If you use the `spring.mvc.servlet.path` Boot property to change the default path (`/`) to something else
+* If you register more than one Spring MVC `DispatcherServlet` (thus requiring that one of them not be the default path)
 
 [[match-by-custom]]
 === Using a Custom Matcher