From 686cc5fc1f33fc94a85064b1b9b83ee8b58c497a Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 10 Jul 2025 13:55:29 -0600 Subject: [PATCH] Remove PathMatcher Messaging Components Closes gh-17501 --- .../util/matcher/MessageMatcherFactory.java | 52 ------ .../SimpDestinationMessageMatcher.java | 176 ------------------ .../SimpDestinationMessageMatcherTests.java | 141 -------------- 3 files changed, 369 deletions(-) delete mode 100644 messaging/src/main/java/org/springframework/security/messaging/util/matcher/MessageMatcherFactory.java delete mode 100644 messaging/src/main/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcher.java delete mode 100644 messaging/src/test/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcherTests.java diff --git a/messaging/src/main/java/org/springframework/security/messaging/util/matcher/MessageMatcherFactory.java b/messaging/src/main/java/org/springframework/security/messaging/util/matcher/MessageMatcherFactory.java deleted file mode 100644 index d494b31b4c..0000000000 --- a/messaging/src/main/java/org/springframework/security/messaging/util/matcher/MessageMatcherFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2002-2025 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.messaging.util.matcher; - -import org.springframework.context.ApplicationContext; -import org.springframework.messaging.simp.SimpMessageType; - -/** - * This utility exists only to facilitate applications opting into using path patterns in - * the Message Security DSL. It is for internal use only. - * - * @deprecated - */ -@Deprecated(forRemoval = true) -public final class MessageMatcherFactory { - - private static PathPatternMessageMatcher.Builder builder; - - public static void setApplicationContext(ApplicationContext context) { - builder = context.getBeanProvider(PathPatternMessageMatcher.Builder.class).getIfUnique(); - } - - public static boolean usesPathPatterns() { - return builder != null; - } - - public static MessageMatcher matcher(String destination) { - return matcher(null, destination); - } - - public static MessageMatcher matcher(SimpMessageType type, String destination) { - return builder.matcher(type, destination); - } - - private MessageMatcherFactory() { - } - -} diff --git a/messaging/src/main/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcher.java b/messaging/src/main/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcher.java deleted file mode 100644 index 1761119825..0000000000 --- a/messaging/src/main/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcher.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2002-2025 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.messaging.util.matcher; - -import java.util.Collections; -import java.util.Map; - -import org.springframework.messaging.Message; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.Assert; -import org.springframework.util.PathMatcher; - -/** - *

- * MessageMatcher which compares a pre-defined pattern against the destination of a - * {@link Message}. There is also support for optionally matching on a specified - * {@link SimpMessageType}. - *

- * - * @author Rob Winch - * @since 4.0 - * @deprecated use {@link PathPatternMessageMatcher} - */ -@Deprecated -public final class SimpDestinationMessageMatcher implements MessageMatcher { - - public static final MessageMatcher NULL_DESTINATION_MATCHER = (message) -> { - String destination = SimpMessageHeaderAccessor.getDestination(message.getHeaders()); - return destination == null; - }; - - private final PathMatcher matcher; - - /** - * The {@link MessageMatcher} that determines if the type matches. If the type was - * null, this matcher will match every Message. - */ - private final MessageMatcher messageTypeMatcher; - - private final String pattern; - - /** - *

- * Creates a new instance with the specified pattern, null {@link SimpMessageType} - * (matches any type), and a {@link AntPathMatcher} created from the default - * constructor. - * - *

- * The mapping matches destinations despite the using the following rules: - * - *

    - *
  • ? matches one character
  • - *
  • * matches zero or more characters
  • - *
  • ** matches zero or more 'directories' in a path
  • - *
- * - *

- * Some examples: - * - *

    - *
  • {@code com/t?st.jsp} - matches {@code com/test} but also {@code com/tast} or - * {@code com/txst}
  • - *
  • {@code com/*suffix} - matches all files ending in {@code suffix} in the - * {@code com} directory
  • - *
  • {@code com/**/test} - matches all destinations ending with {@code test} - * underneath the {@code com} path
  • - *
- * @param pattern the pattern to use - */ - public SimpDestinationMessageMatcher(String pattern) { - this(pattern, new AntPathMatcher()); - } - - /** - *

- * Creates a new instance with the specified pattern and {@link PathMatcher}. - * @param pattern the pattern to use - * @param pathMatcher the {@link PathMatcher} to use. - */ - public SimpDestinationMessageMatcher(String pattern, PathMatcher pathMatcher) { - this(pattern, null, pathMatcher); - } - - /** - *

- * Creates a new instance with the specified pattern, {@link SimpMessageType}, and - * {@link PathMatcher}. - * @param pattern the pattern to use - * @param type the {@link SimpMessageType} to match on or null if any - * {@link SimpMessageType} should be matched. - * @param pathMatcher the {@link PathMatcher} to use. - */ - private SimpDestinationMessageMatcher(String pattern, SimpMessageType type, PathMatcher pathMatcher) { - Assert.notNull(pattern, "pattern cannot be null"); - Assert.notNull(pathMatcher, "pathMatcher cannot be null"); - Assert.isTrue(isTypeWithDestination(type), - () -> "SimpMessageType " + type + " does not contain a destination and so cannot be matched on."); - this.matcher = pathMatcher; - this.messageTypeMatcher = (type != null) ? new SimpMessageTypeMatcher(type) : ANY_MESSAGE; - this.pattern = pattern; - } - - @Override - public boolean matches(Message message) { - if (!this.messageTypeMatcher.matches(message)) { - return false; - } - String destination = SimpMessageHeaderAccessor.getDestination(message.getHeaders()); - return destination != null && this.matcher.match(this.pattern, destination); - } - - @Override - public MatchResult matcher(Message message) { - boolean match = matches(message); - return (!match) ? MatchResult.notMatch() : MatchResult.match(extractPathVariables(message)); - } - - public Map extractPathVariables(Message message) { - final String destination = SimpMessageHeaderAccessor.getDestination(message.getHeaders()); - return (destination != null) ? this.matcher.extractUriTemplateVariables(this.pattern, destination) - : Collections.emptyMap(); - } - - public MessageMatcher getMessageTypeMatcher() { - return this.messageTypeMatcher; - } - - @Override - public String toString() { - return "SimpDestinationMessageMatcher [matcher=" + this.matcher + ", messageTypeMatcher=" - + this.messageTypeMatcher + ", pattern=" + this.pattern + "]"; - } - - private boolean isTypeWithDestination(SimpMessageType type) { - return type == null || SimpMessageType.MESSAGE.equals(type) || SimpMessageType.SUBSCRIBE.equals(type); - } - - /** - *

- * Creates a new instance with the specified pattern, - * {@code SimpMessageType.SUBSCRIBE}, and {@link PathMatcher}. - * @param pattern the pattern to use - * @param matcher the {@link PathMatcher} to use. - */ - public static SimpDestinationMessageMatcher createSubscribeMatcher(String pattern, PathMatcher matcher) { - return new SimpDestinationMessageMatcher(pattern, SimpMessageType.SUBSCRIBE, matcher); - } - - /** - *

- * Creates a new instance with the specified pattern, {@code SimpMessageType.MESSAGE}, - * and {@link PathMatcher}. - * @param pattern the pattern to use - * @param matcher the {@link PathMatcher} to use. - */ - public static SimpDestinationMessageMatcher createMessageMatcher(String pattern, PathMatcher matcher) { - return new SimpDestinationMessageMatcher(pattern, SimpMessageType.MESSAGE, matcher); - } - -} diff --git a/messaging/src/test/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcherTests.java b/messaging/src/test/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcherTests.java deleted file mode 100644 index c36fe7ac47..0000000000 --- a/messaging/src/test/java/org/springframework/security/messaging/util/matcher/SimpDestinationMessageMatcherTests.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2002-2025 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.messaging.util.matcher; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.PathMatcher; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; - -public class SimpDestinationMessageMatcherTests { - - MessageBuilder messageBuilder; - - SimpDestinationMessageMatcher matcher; - - PathMatcher pathMatcher; - - @BeforeEach - public void setup() { - this.messageBuilder = MessageBuilder.withPayload("M"); - this.matcher = new SimpDestinationMessageMatcher("/**"); - this.pathMatcher = new AntPathMatcher(); - } - - @Test - public void constructorPatternNull() { - assertThatIllegalArgumentException().isThrownBy(() -> new SimpDestinationMessageMatcher(null)); - } - - public void constructorOnlyPathNoError() { - new SimpDestinationMessageMatcher("/path"); - } - - @Test - public void matchesDoesNotMatchNullDestination() { - assertThat(this.matcher.matches(this.messageBuilder.build())).isFalse(); - } - - @Test - public void matchesAllWithDestination() { - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination/1"); - assertThat(this.matcher.matches(this.messageBuilder.build())).isTrue(); - } - - @Test - public void matchesSpecificWithDestination() { - this.matcher = new SimpDestinationMessageMatcher("/destination/1"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination/1"); - assertThat(this.matcher.matches(this.messageBuilder.build())).isTrue(); - } - - @Test - public void matchesFalseWithDestination() { - this.matcher = new SimpDestinationMessageMatcher("/nomatch"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination/1"); - assertThat(this.matcher.matches(this.messageBuilder.build())).isFalse(); - } - - @Test - public void matchesFalseMessageTypeNotDisconnectType() { - this.matcher = SimpDestinationMessageMatcher.createMessageMatcher("/match", this.pathMatcher); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.DISCONNECT); - assertThat(this.matcher.matches(this.messageBuilder.build())).isFalse(); - } - - @Test - public void matchesTrueMessageType() { - this.matcher = SimpDestinationMessageMatcher.createMessageMatcher("/match", this.pathMatcher); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/match"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.MESSAGE); - assertThat(this.matcher.matches(this.messageBuilder.build())).isTrue(); - } - - @Test - public void matchesTrueSubscribeType() { - this.matcher = SimpDestinationMessageMatcher.createSubscribeMatcher("/match", this.pathMatcher); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/match"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.SUBSCRIBE); - assertThat(this.matcher.matches(this.messageBuilder.build())).isTrue(); - } - - @Test - public void matchesNullMessageType() { - this.matcher = new SimpDestinationMessageMatcher("/match"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/match"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.MESSAGE); - assertThat(this.matcher.matches(this.messageBuilder.build())).isTrue(); - } - - @Test - public void extractPathVariablesFromDestination() { - this.matcher = new SimpDestinationMessageMatcher("/topics/{topic}/**"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/topics/someTopic/sub1"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.MESSAGE); - assertThat(this.matcher.extractPathVariables(this.messageBuilder.build())).containsEntry("topic", "someTopic"); - } - - @Test - public void extractedVariablesAreEmptyInNullDestination() { - this.matcher = new SimpDestinationMessageMatcher("/topics/{topic}/**"); - assertThat(this.matcher.extractPathVariables(this.messageBuilder.build())).isEmpty(); - } - - @Test - public void typeConstructorParameterIsTransmitted() { - this.matcher = SimpDestinationMessageMatcher.createMessageMatcher("/match", this.pathMatcher); - MessageMatcher expectedTypeMatcher = new SimpMessageTypeMatcher(SimpMessageType.MESSAGE); - assertThat(this.matcher.getMessageTypeMatcher()).isEqualTo(expectedTypeMatcher); - } - - @Test - public void extractPathVariablesWhenNoMatchThenIllegalState() { - this.matcher = new SimpDestinationMessageMatcher("/nomatch"); - this.messageBuilder.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination/1"); - assertThatIllegalStateException() - .isThrownBy(() -> this.matcher.extractPathVariables(this.messageBuilder.build())); - } - -}