Browse Source

Use PathPatternMessageMatcher By Default

Issue gh-17501
Josh Cummings 1 tháng trước cách đây
mục cha
commit
684775b46a

+ 10 - 15
config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java

@@ -16,29 +16,24 @@
 
 package org.springframework.security.config.annotation.web.socket;
 
-import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Fallback;
 import org.springframework.context.annotation.Scope;
-import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
+import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
 import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
-import org.springframework.security.messaging.util.matcher.MessageMatcherFactory;
-import org.springframework.util.AntPathMatcher;
 
 final class MessageMatcherAuthorizationManagerConfiguration {
 
+	@Bean
+	@Fallback
+	PathPatternMessageMatcherBuilderFactoryBean messageMatcherBuilderFactoryBean() {
+		return new PathPatternMessageMatcherBuilderFactoryBean();
+	}
+
 	@Bean
 	@Scope("prototype")
-	MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder(
-			ApplicationContext context) {
-		MessageMatcherFactory.setApplicationContext(context);
-		if (MessageMatcherFactory.usesPathPatterns()) {
-			return MessageMatcherDelegatingAuthorizationManager.builder();
-		}
-		return MessageMatcherDelegatingAuthorizationManager.builder()
-			.simpDestPathMatcher(
-					() -> (context.getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0)
-							? context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher()
-							: new AntPathMatcher());
+	MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder() {
+		return MessageMatcherDelegatingAuthorizationManager.builder();
 	}
 
 }

+ 2 - 20
config/src/main/java/org/springframework/security/config/http/MessageMatcherFactoryBean.java

@@ -23,9 +23,6 @@ import org.springframework.context.ApplicationContextAware;
 import org.springframework.messaging.simp.SimpMessageType;
 import org.springframework.security.messaging.util.matcher.MessageMatcher;
 import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
-import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
-import org.springframework.util.AntPathMatcher;
-import org.springframework.util.PathMatcher;
 
 @Deprecated
 public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatcher<?>>, ApplicationContextAware {
@@ -36,8 +33,6 @@ public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatch
 
 	private final String path;
 
-	private PathMatcher pathMatcher = new AntPathMatcher();
-
 	public MessageMatcherFactoryBean(String path) {
 		this(path, null);
 	}
@@ -49,16 +44,7 @@ public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatch
 
 	@Override
 	public MessageMatcher<?> getObject() throws Exception {
-		if (this.builder != null) {
-			return this.builder.matcher(this.method, this.path);
-		}
-		if (this.method == SimpMessageType.SUBSCRIBE) {
-			return SimpDestinationMessageMatcher.createSubscribeMatcher(this.path, this.pathMatcher);
-		}
-		if (this.method == SimpMessageType.MESSAGE) {
-			return SimpDestinationMessageMatcher.createMessageMatcher(this.path, this.pathMatcher);
-		}
-		return new SimpDestinationMessageMatcher(this.path, this.pathMatcher);
+		return this.builder.matcher(this.method, this.path);
 	}
 
 	@Override
@@ -66,13 +52,9 @@ public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatch
 		return null;
 	}
 
-	public void setPathMatcher(PathMatcher pathMatcher) {
-		this.pathMatcher = pathMatcher;
-	}
-
 	@Override
 	public void setApplicationContext(ApplicationContext context) throws BeansException {
-		this.builder = context.getBeanProvider(PathPatternMessageMatcher.Builder.class).getIfUnique();
+		this.builder = context.getBean(PathPatternMessageMatcher.Builder.class);
 	}
 
 }

+ 10 - 16
config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java

@@ -31,9 +31,9 @@ import org.springframework.beans.BeansException;
 import org.springframework.beans.PropertyValue;
 import org.springframework.beans.factory.FactoryBean;
 import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.BeanReference;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
@@ -56,6 +56,7 @@ import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.authorization.AuthorizationResult;
 import org.springframework.security.config.Elements;
 import org.springframework.security.config.http.MessageMatcherFactoryBean;
+import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -134,7 +135,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
 
 	private static final String TYPE_ATTR = "type";
 
-	private static final String PATH_MATCHER_BEAN_NAME = "springSecurityMessagePathMatcher";
+	private static final String MESSAGE_MATCHER_BUILDER_BEAN_NAME = "HttpConfigurationBuilder-pathPatternMessageMatcherBuilder";
 
 	/**
 	 * @param element
@@ -144,13 +145,17 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
 	@Override
 	public BeanDefinition parse(Element element, ParserContext parserContext) {
 		String id = element.getAttribute(ID_ATTR);
+		if (!parserContext.getRegistry().containsBeanDefinition(MESSAGE_MATCHER_BUILDER_BEAN_NAME)) {
+			BeanDefinitionBuilder pathPatternMessageMatcherBuilder = BeanDefinitionBuilder
+				.rootBeanDefinition(PathPatternMessageMatcherBuilderFactoryBean.class);
+			pathPatternMessageMatcherBuilder.setFallback(true);
+			BeanDefinition bean = pathPatternMessageMatcherBuilder.getBeanDefinition();
+			parserContext.registerBeanComponent(new BeanComponentDefinition(bean, MESSAGE_MATCHER_BUILDER_BEAN_NAME));
+		}
 		String inSecurityInterceptorName = parseAuthorization(element, parserContext);
 		BeanDefinitionRegistry registry = parserContext.getRegistry();
 		if (StringUtils.hasText(id)) {
 			registry.registerAlias(inSecurityInterceptorName, id);
-			if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
-				registry.registerBeanDefinition(PATH_MATCHER_BEAN_NAME, new RootBeanDefinition(AntPathMatcher.class));
-			}
 		}
 		else {
 			boolean sameOriginDisabled = Boolean.parseBoolean(element.getAttribute(DISABLED_ATTR));
@@ -286,7 +291,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
 							+ " with a pattern because the type does not have a destination.", interceptMessage);
 			}
 		}
-		matcher.addPropertyValue("pathMatcher", new RuntimeBeanReference("springSecurityMessagePathMatcher"));
 		return matcher.getBeanDefinition();
 	}
 
@@ -342,13 +346,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
 					}
 					argResolvers.add(beanDefinition);
 					bd.getPropertyValues().add(CUSTOM_ARG_RESOLVERS_PROP, argResolvers);
-					if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
-						PropertyValue pathMatcherProp = bd.getPropertyValues().getPropertyValue("pathMatcher");
-						Object pathMatcher = (pathMatcherProp != null) ? pathMatcherProp.getValue() : null;
-						if (pathMatcher instanceof BeanReference) {
-							registry.registerAlias(((BeanReference) pathMatcher).getBeanName(), PATH_MATCHER_BEAN_NAME);
-						}
-					}
 				}
 				else if (CSRF_HANDSHAKE_HANDLER_CLASSES.contains(beanClassName)) {
 					addCsrfTokenHandshakeInterceptor(bd);
@@ -376,9 +373,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
 				interceptors.addAll(currentInterceptors);
 			}
 			inboundChannel.getPropertyValues().add(INTERCEPTORS_PROP, interceptors);
-			if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
-				registry.registerBeanDefinition(PATH_MATCHER_BEAN_NAME, new RootBeanDefinition(AntPathMatcher.class));
-			}
 		}
 
 		private void addCsrfTokenHandshakeInterceptor(BeanDefinition bd) {

+ 10 - 2
config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java

@@ -45,6 +45,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 import org.springframework.core.MethodParameter;
+import org.springframework.http.server.PathContainer;
 import org.springframework.http.server.ServerHttpRequest;
 import org.springframework.http.server.ServerHttpResponse;
 import org.springframework.messaging.Message;
@@ -70,6 +71,7 @@ import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.observation.SecurityObservationSettings;
+import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
 import org.springframework.security.core.annotation.AuthenticationPrincipal;
@@ -99,6 +101,7 @@ import org.springframework.web.socket.server.HandshakeHandler;
 import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
 import org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler;
 import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession;
+import org.springframework.web.util.pattern.PathPatternParser;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -507,6 +510,13 @@ public class WebSocketMessageBrokerSecurityConfigurationTests {
 	@Import(SyncExecutorConfig.class)
 	static class MsmsRegistryCustomPatternMatcherConfig implements WebSocketMessageBrokerConfigurer {
 
+		@Bean
+		PathPatternMessageMatcherBuilderFactoryBean messageMatcherBuilder() {
+			PathPatternParser parser = new PathPatternParser();
+			parser.setPathOptions(PathContainer.Options.MESSAGE_ROUTE);
+			return new PathPatternMessageMatcherBuilderFactoryBean(parser);
+		}
+
 		// @formatter:off
 		@Override
 		public void registerStompEndpoints(StompEndpointRegistry registry) {
@@ -518,7 +528,6 @@ public class WebSocketMessageBrokerSecurityConfigurationTests {
 
 		@Override
 		public void configureMessageBroker(MessageBrokerRegistry registry) {
-			registry.setPathMatcher(new AntPathMatcher("."));
 			registry.enableSimpleBroker("/queue/", "/topic/");
 			registry.setApplicationDestinationPrefixes("/app");
 		}
@@ -567,7 +576,6 @@ public class WebSocketMessageBrokerSecurityConfigurationTests {
 		@Bean
 		AuthorizationManager<Message<?>> authorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
 			messages
-					.simpDestPathMatcher(new AntPathMatcher())
 					.simpDestMatchers("/app/a/*").permitAll()
 					.anyMessage().denyAll();
 			return messages.build();

+ 5 - 9
messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttribute.java

@@ -23,7 +23,6 @@ import org.springframework.expression.Expression;
 import org.springframework.messaging.Message;
 import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.messaging.util.matcher.MessageMatcher;
-import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
 import org.springframework.util.Assert;
 
 /**
@@ -42,7 +41,7 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
 
 	private final Expression authorizeExpression;
 
-	private final MessageMatcher<?> matcher;
+	private final MessageMatcher<Object> matcher;
 
 	/**
 	 * Creates a new instance
@@ -53,7 +52,7 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
 		Assert.notNull(authorizeExpression, "authorizeExpression cannot be null");
 		Assert.notNull(matcher, "matcher cannot be null");
 		this.authorizeExpression = authorizeExpression;
-		this.matcher = matcher;
+		this.matcher = (MessageMatcher<Object>) matcher;
 	}
 
 	Expression getAuthorizeExpression() {
@@ -72,12 +71,9 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
 
 	@Override
 	public EvaluationContext postProcess(EvaluationContext ctx, Message<?> message) {
-		if (this.matcher instanceof SimpDestinationMessageMatcher) {
-			Map<String, String> variables = ((SimpDestinationMessageMatcher) this.matcher)
-				.extractPathVariables(message);
-			for (Map.Entry<String, String> entry : variables.entrySet()) {
-				ctx.setVariable(entry.getKey(), entry.getValue());
-			}
+		Map<String, String> variables = this.matcher.matcher(message).getVariables();
+		for (Map.Entry<String, String> entry : variables.entrySet()) {
+			ctx.setVariable(entry.getKey(), entry.getValue());
 		}
 		return ctx;
 	}

+ 22 - 92
messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java

@@ -23,6 +23,9 @@ import java.util.function.Supplier;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
 import org.springframework.core.log.LogMessage;
 import org.springframework.messaging.Message;
 import org.springframework.messaging.simp.SimpMessageType;
@@ -33,15 +36,10 @@ import org.springframework.security.authorization.AuthorizationResult;
 import org.springframework.security.authorization.SingleResultAuthorizationManager;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.messaging.util.matcher.MessageMatcher;
-import org.springframework.security.messaging.util.matcher.MessageMatcherFactory;
 import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
-import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
 import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher;
-import org.springframework.util.AntPathMatcher;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
-import org.springframework.util.PathMatcher;
-import org.springframework.util.function.SingletonSupplier;
 
 public final class MessageMatcherDelegatingAuthorizationManager implements AuthorizationManager<Message<?>> {
 
@@ -99,12 +97,11 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 	/**
 	 * A builder for {@link MessageMatcherDelegatingAuthorizationManager}.
 	 */
-	public static final class Builder {
+	public static final class Builder implements ApplicationContextAware {
 
 		private final List<Entry<AuthorizationManager<MessageAuthorizationContext<?>>>> mappings = new ArrayList<>();
 
-		@Deprecated
-		private Supplier<PathMatcher> pathMatcher = AntPathMatcher::new;
+		private PathPatternMessageMatcher.Builder messageMatcherBuilder = PathPatternMessageMatcher.withDefaults();
 
 		public Builder() {
 		}
@@ -142,11 +139,9 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 		}
 
 		/**
-		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
-		 * {@link PathPatternMessageMatcher} if the application has configured a
-		 * {@link PathPatternMessageMatcher.Builder} bean) instances without regard to the
-		 * {@link SimpMessageType}. If no destination is found on the Message, then the
-		 * Matcher returns false.
+		 * Maps a {@link List} of {@link PathPatternMessageMatcher}s instances without
+		 * regard to the {@link SimpMessageType}. If no destination is found on the
+		 * Message, then the Matcher returns false.
 		 * @param patterns the patterns to create {@code MessageMatcher}s from.
 		 */
 		public Builder.Constraint simpDestMatchers(String... patterns) {
@@ -154,10 +149,8 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 		}
 
 		/**
-		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
-		 * {@link PathPatternMessageMatcher} if the application has configured a
-		 * {@link PathPatternMessageMatcher.Builder} bean) instances that match on
-		 * {@code SimpMessageType.MESSAGE}. If no destination is found on the Message,
+		 * Maps a {@link List} of {@link PathPatternMessageMatcher}s instances that match
+		 * on {@code SimpMessageType.MESSAGE}. If no destination is found on the Message,
 		 * then the Matcher returns false.
 		 * @param patterns the patterns to create {@code MessageMatcher}s from.
 		 */
@@ -166,11 +159,9 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 		}
 
 		/**
-		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
-		 * {@link PathPatternMessageMatcher} if the application has configured a
-		 * {@link PathPatternMessageMatcher.Builder} bean) instances that match on
-		 * {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the Message,
-		 * then the Matcher returns false.
+		 * Maps a {@link List} of {@link PathPatternMessageMatcher}s instances that match
+		 * on {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the
+		 * Message, then the Matcher returns false.
 		 * @param patterns the patterns to create {@code MessageMatcher}s from.
 		 */
 		public Builder.Constraint simpSubscribeDestMatchers(String... patterns) {
@@ -178,10 +169,8 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 		}
 
 		/**
-		 * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
-		 * {@link PathPatternMessageMatcher} if the application has configured a
-		 * {@link PathPatternMessageMatcher.Builder} bean) instances. If no destination is
-		 * found on the Message, then the Matcher returns false.
+		 * Maps a {@link List} of {@link PathPatternMessageMatcher} instances. If no
+		 * destination is found on the Message, then the Matcher returns false.
 		 * @param type the {@link SimpMessageType} to match on. If null, the
 		 * {@link SimpMessageType} is not considered for matching.
 		 * @param patterns the patterns to create {@code MessageMatcher}s from.
@@ -191,44 +180,12 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 		private Builder.Constraint simpDestMatchers(SimpMessageType type, String... patterns) {
 			List<MessageMatcher<?>> matchers = new ArrayList<>(patterns.length);
 			for (String pattern : patterns) {
-				MessageMatcher<Object> matcher = MessageMatcherFactory.usesPathPatterns()
-						? MessageMatcherFactory.matcher(type, pattern)
-						: new LazySimpDestinationMessageMatcher(pattern, type);
+				MessageMatcher<Object> matcher = this.messageMatcherBuilder.matcher(type, pattern);
 				matchers.add(matcher);
 			}
 			return new Builder.Constraint(matchers);
 		}
 
-		/**
-		 * The {@link PathMatcher} to be used with the
-		 * {@link Builder#simpDestMatchers(String...)}. The default is to use the default
-		 * constructor of {@link AntPathMatcher}.
-		 * @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
-		 * @return the {@link Builder} for further customization.
-		 * @deprecated
-		 */
-		@Deprecated
-		public Builder simpDestPathMatcher(PathMatcher pathMatcher) {
-			Assert.notNull(pathMatcher, "pathMatcher cannot be null");
-			this.pathMatcher = () -> pathMatcher;
-			return this;
-		}
-
-		/**
-		 * The {@link PathMatcher} to be used with the
-		 * {@link Builder#simpDestMatchers(String...)}. Use this method to delay the
-		 * computation or lookup of the {@link PathMatcher}.
-		 * @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
-		 * @return the {@link Builder} for further customization.
-		 * @deprecated
-		 */
-		@Deprecated
-		public Builder simpDestPathMatcher(Supplier<PathMatcher> pathMatcher) {
-			Assert.notNull(pathMatcher, "pathMatcher cannot be null");
-			this.pathMatcher = pathMatcher;
-			return this;
-		}
-
 		/**
 		 * Maps a {@link List} of {@link MessageMatcher} instances to a security
 		 * expression.
@@ -248,6 +205,12 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 			return new MessageMatcherDelegatingAuthorizationManager(this.mappings);
 		}
 
+		@Override
+		public void setApplicationContext(ApplicationContext context) throws BeansException {
+			this.messageMatcherBuilder = context.getBeanProvider(PathPatternMessageMatcher.Builder.class)
+				.getIfUnique(PathPatternMessageMatcher::withDefaults);
+		}
+
 		/**
 		 * Represents the security constraint to be applied to the {@link MessageMatcher}
 		 * instances.
@@ -379,39 +342,6 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
 
 		}
 
-		@Deprecated
-		private final class LazySimpDestinationMessageMatcher implements MessageMatcher<Object> {
-
-			private final Supplier<SimpDestinationMessageMatcher> delegate;
-
-			private LazySimpDestinationMessageMatcher(String pattern, SimpMessageType type) {
-				this.delegate = SingletonSupplier.of(() -> {
-					PathMatcher pathMatcher = Builder.this.pathMatcher.get();
-					if (type == null) {
-						return new SimpDestinationMessageMatcher(pattern, pathMatcher);
-					}
-					if (SimpMessageType.MESSAGE == type) {
-						return SimpDestinationMessageMatcher.createMessageMatcher(pattern, pathMatcher);
-					}
-					if (SimpMessageType.SUBSCRIBE == type) {
-						return SimpDestinationMessageMatcher.createSubscribeMatcher(pattern, pathMatcher);
-					}
-					throw new IllegalStateException(type + " is not supported since it does not have a destination");
-				});
-			}
-
-			@Override
-			public boolean matches(Message<?> message) {
-				return this.delegate.get().matches(message);
-			}
-
-			@Override
-			public MatchResult matcher(Message<?> message) {
-				return this.delegate.get().matcher(message);
-			}
-
-		}
-
 	}
 
 	private static final class Entry<T> {

+ 2 - 2
messaging/src/test/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttributeTests.java

@@ -28,7 +28,7 @@ import org.springframework.messaging.Message;
 import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
 import org.springframework.messaging.support.MessageBuilder;
 import org.springframework.security.messaging.util.matcher.MessageMatcher;
-import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
+import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -81,7 +81,7 @@ public class MessageExpressionConfigAttributeTests {
 
 	@Test
 	public void postProcessContext() {
-		SimpDestinationMessageMatcher matcher = new SimpDestinationMessageMatcher("/topics/{topic}/**");
+		PathPatternMessageMatcher matcher = PathPatternMessageMatcher.withDefaults().matcher("/topics/{topic}/**");
 		// @formatter:off
 		Message<?> message = MessageBuilder.withPayload("M")
 				.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/topics/someTopic/sub1")

+ 3 - 0
messaging/src/test/java/org/springframework/security/messaging/access/expression/MessageExpressionVoterTests.java

@@ -78,6 +78,7 @@ public class MessageExpressionVoterTests {
 	@Test
 	public void voteGranted() {
 		given(this.expression.getValue(any(EvaluationContext.class), eq(Boolean.class))).willReturn(true);
+		given(this.matcher.matcher(any())).willCallRealMethod();
 		assertThat(this.voter.vote(this.authentication, this.message, this.attributes))
 			.isEqualTo(AccessDecisionVoter.ACCESS_GRANTED);
 	}
@@ -85,6 +86,7 @@ public class MessageExpressionVoterTests {
 	@Test
 	public void voteDenied() {
 		given(this.expression.getValue(any(EvaluationContext.class), eq(Boolean.class))).willReturn(false);
+		given(this.matcher.matcher(any())).willCallRealMethod();
 		assertThat(this.voter.vote(this.authentication, this.message, this.attributes))
 			.isEqualTo(AccessDecisionVoter.ACCESS_DENIED);
 	}
@@ -127,6 +129,7 @@ public class MessageExpressionVoterTests {
 		given(this.expressionHandler.createEvaluationContext(this.authentication, this.message))
 			.willReturn(this.evaluationContext);
 		given(this.expression.getValue(this.evaluationContext, Boolean.class)).willReturn(true);
+		given(this.matcher.matcher(any())).willCallRealMethod();
 		assertThat(this.voter.vote(this.authentication, this.message, this.attributes))
 			.isEqualTo(AccessDecisionVoter.ACCESS_GRANTED);
 		verify(this.expressionHandler).createEvaluationContext(this.authentication, this.message);

+ 32 - 7
messaging/src/test/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManagerTests.java

@@ -37,10 +37,11 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.messaging.util.matcher.MessageMatcherFactory;
 import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
+import org.springframework.web.util.pattern.PathPatternParser;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 
 /**
@@ -58,7 +59,7 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
 	@BeforeEach
 	void setUp() {
 		Mockito.when(this.context.getBeanProvider(PathPatternMessageMatcher.Builder.class)).thenReturn(this.provider);
-		MessageMatcherFactory.setApplicationContext(this.context);
+		Mockito.when(this.provider.getIfUnique(any())).thenReturn(PathPatternMessageMatcher.withDefaults());
 	}
 
 	@Test
@@ -135,8 +136,7 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
 
 	@Test
 	void checkWhenMessageTypeAndPathPatternMatches() {
-		Mockito.when(this.provider.getIfUnique()).thenReturn(PathPatternMessageMatcher.withDefaults());
-		MessageMatcherFactory.setApplicationContext(this.context);
+		Mockito.when(this.provider.getIfUnique(any())).thenReturn(PathPatternMessageMatcher.withDefaults());
 		AuthorizationManager<Message<?>> authorizationManager = builder().simpMessageDestMatchers("/destination")
 			.permitAll()
 			.simpSubscribeDestMatchers("/destination")
@@ -154,10 +154,32 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
 		assertThat(authorizationManager.authorize(mock(Supplier.class), message2).isGranted()).isFalse();
 	}
 
+	@Test
+	void checkWhenMessageTypeAndPathPatternMatchesCaseInsensitive() {
+		PathPatternParser pathPatternParser = new PathPatternParser();
+		pathPatternParser.setCaseSensitive(false);
+		PathPatternMessageMatcher.Builder messageMatcherBuilder = PathPatternMessageMatcher
+			.withPathPatternParser(pathPatternParser);
+		Mockito.when(this.provider.getIfUnique(any())).thenReturn(messageMatcherBuilder);
+		AuthorizationManager<Message<?>> authorizationManager = builder().simpMessageDestMatchers("/desTinaTion")
+			.permitAll()
+			.simpSubscribeDestMatchers("/desTinaTion")
+			.denyAll()
+			.anyMessage()
+			.denyAll()
+			.build();
+		MessageHeaders headers = new MessageHeaders(Map.of(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER,
+				SimpMessageType.MESSAGE, SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination"));
+		Message<?> message = new GenericMessage<>(new Object(), headers);
+		assertThat(authorizationManager.authorize(mock(Supplier.class), message).isGranted()).isTrue();
+		MessageHeaders headers2 = new MessageHeaders(Map.of(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER,
+				SimpMessageType.SUBSCRIBE, SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination"));
+		Message<?> message2 = new GenericMessage<>(new Object(), headers2);
+		assertThat(authorizationManager.authorize(mock(Supplier.class), message2).isGranted()).isFalse();
+	}
+
 	@Test
 	void checkPatternMismatch() {
-		Mockito.when(this.provider.getIfUnique()).thenReturn(PathPatternMessageMatcher.withDefaults());
-		MessageMatcherFactory.setApplicationContext(this.context);
 		AuthorizationManager<Message<?>> authorizationManager = builder().simpDestMatchers("/destination/*")
 			.permitAll()
 			.anyMessage()
@@ -170,7 +192,10 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
 	}
 
 	private MessageMatcherDelegatingAuthorizationManager.Builder builder() {
-		return MessageMatcherDelegatingAuthorizationManager.builder();
+		MessageMatcherDelegatingAuthorizationManager.Builder builder = MessageMatcherDelegatingAuthorizationManager
+			.builder();
+		builder.setApplicationContext(this.context);
+		return builder;
 	}
 
 	private Builder variable(String name) {