Skip to content

Commit 684775b

Browse files
committed
Use PathPatternMessageMatcher By Default
Issue gh-17501
1 parent ff7359b commit 684775b

File tree

9 files changed

+96
-163
lines changed

9 files changed

+96
-163
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,24 @@
1616

1717
package org.springframework.security.config.annotation.web.socket;
1818

19-
import org.springframework.context.ApplicationContext;
2019
import org.springframework.context.annotation.Bean;
20+
import org.springframework.context.annotation.Fallback;
2121
import org.springframework.context.annotation.Scope;
22-
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
22+
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
2323
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
24-
import org.springframework.security.messaging.util.matcher.MessageMatcherFactory;
25-
import org.springframework.util.AntPathMatcher;
2624

2725
final class MessageMatcherAuthorizationManagerConfiguration {
2826

27+
@Bean
28+
@Fallback
29+
PathPatternMessageMatcherBuilderFactoryBean messageMatcherBuilderFactoryBean() {
30+
return new PathPatternMessageMatcherBuilderFactoryBean();
31+
}
32+
2933
@Bean
3034
@Scope("prototype")
31-
MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder(
32-
ApplicationContext context) {
33-
MessageMatcherFactory.setApplicationContext(context);
34-
if (MessageMatcherFactory.usesPathPatterns()) {
35-
return MessageMatcherDelegatingAuthorizationManager.builder();
36-
}
37-
return MessageMatcherDelegatingAuthorizationManager.builder()
38-
.simpDestPathMatcher(
39-
() -> (context.getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0)
40-
? context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher()
41-
: new AntPathMatcher());
35+
MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder() {
36+
return MessageMatcherDelegatingAuthorizationManager.builder();
4237
}
4338

4439
}

config/src/main/java/org/springframework/security/config/http/MessageMatcherFactoryBean.java

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
import org.springframework.messaging.simp.SimpMessageType;
2424
import org.springframework.security.messaging.util.matcher.MessageMatcher;
2525
import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
26-
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
27-
import org.springframework.util.AntPathMatcher;
28-
import org.springframework.util.PathMatcher;
2926

3027
@Deprecated
3128
public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatcher<?>>, ApplicationContextAware {
@@ -36,8 +33,6 @@ public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatch
3633

3734
private final String path;
3835

39-
private PathMatcher pathMatcher = new AntPathMatcher();
40-
4136
public MessageMatcherFactoryBean(String path) {
4237
this(path, null);
4338
}
@@ -49,30 +44,17 @@ public MessageMatcherFactoryBean(String path, SimpMessageType method) {
4944

5045
@Override
5146
public MessageMatcher<?> getObject() throws Exception {
52-
if (this.builder != null) {
53-
return this.builder.matcher(this.method, this.path);
54-
}
55-
if (this.method == SimpMessageType.SUBSCRIBE) {
56-
return SimpDestinationMessageMatcher.createSubscribeMatcher(this.path, this.pathMatcher);
57-
}
58-
if (this.method == SimpMessageType.MESSAGE) {
59-
return SimpDestinationMessageMatcher.createMessageMatcher(this.path, this.pathMatcher);
60-
}
61-
return new SimpDestinationMessageMatcher(this.path, this.pathMatcher);
47+
return this.builder.matcher(this.method, this.path);
6248
}
6349

6450
@Override
6551
public Class<?> getObjectType() {
6652
return null;
6753
}
6854

69-
public void setPathMatcher(PathMatcher pathMatcher) {
70-
this.pathMatcher = pathMatcher;
71-
}
72-
7355
@Override
7456
public void setApplicationContext(ApplicationContext context) throws BeansException {
75-
this.builder = context.getBeanProvider(PathPatternMessageMatcher.Builder.class).getIfUnique();
57+
this.builder = context.getBean(PathPatternMessageMatcher.Builder.class);
7658
}
7759

7860
}

config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
import org.springframework.beans.PropertyValue;
3232
import org.springframework.beans.factory.FactoryBean;
3333
import org.springframework.beans.factory.config.BeanDefinition;
34-
import org.springframework.beans.factory.config.BeanReference;
3534
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3635
import org.springframework.beans.factory.config.RuntimeBeanReference;
36+
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
3737
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3838
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3939
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
@@ -56,6 +56,7 @@
5656
import org.springframework.security.authorization.AuthorizationResult;
5757
import org.springframework.security.config.Elements;
5858
import org.springframework.security.config.http.MessageMatcherFactoryBean;
59+
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
5960
import org.springframework.security.core.Authentication;
6061
import org.springframework.security.core.context.SecurityContextHolder;
6162
import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -134,7 +135,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
134135

135136
private static final String TYPE_ATTR = "type";
136137

137-
private static final String PATH_MATCHER_BEAN_NAME = "springSecurityMessagePathMatcher";
138+
private static final String MESSAGE_MATCHER_BUILDER_BEAN_NAME = "HttpConfigurationBuilder-pathPatternMessageMatcherBuilder";
138139

139140
/**
140141
* @param element
@@ -144,13 +145,17 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
144145
@Override
145146
public BeanDefinition parse(Element element, ParserContext parserContext) {
146147
String id = element.getAttribute(ID_ATTR);
148+
if (!parserContext.getRegistry().containsBeanDefinition(MESSAGE_MATCHER_BUILDER_BEAN_NAME)) {
149+
BeanDefinitionBuilder pathPatternMessageMatcherBuilder = BeanDefinitionBuilder
150+
.rootBeanDefinition(PathPatternMessageMatcherBuilderFactoryBean.class);
151+
pathPatternMessageMatcherBuilder.setFallback(true);
152+
BeanDefinition bean = pathPatternMessageMatcherBuilder.getBeanDefinition();
153+
parserContext.registerBeanComponent(new BeanComponentDefinition(bean, MESSAGE_MATCHER_BUILDER_BEAN_NAME));
154+
}
147155
String inSecurityInterceptorName = parseAuthorization(element, parserContext);
148156
BeanDefinitionRegistry registry = parserContext.getRegistry();
149157
if (StringUtils.hasText(id)) {
150158
registry.registerAlias(inSecurityInterceptorName, id);
151-
if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
152-
registry.registerBeanDefinition(PATH_MATCHER_BEAN_NAME, new RootBeanDefinition(AntPathMatcher.class));
153-
}
154159
}
155160
else {
156161
boolean sameOriginDisabled = Boolean.parseBoolean(element.getAttribute(DISABLED_ATTR));
@@ -286,7 +291,6 @@ private BeanDefinition createMatcher(String matcherPattern, String messageType,
286291
+ " with a pattern because the type does not have a destination.", interceptMessage);
287292
}
288293
}
289-
matcher.addPropertyValue("pathMatcher", new RuntimeBeanReference("springSecurityMessagePathMatcher"));
290294
return matcher.getBeanDefinition();
291295
}
292296

@@ -342,13 +346,6 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t
342346
}
343347
argResolvers.add(beanDefinition);
344348
bd.getPropertyValues().add(CUSTOM_ARG_RESOLVERS_PROP, argResolvers);
345-
if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
346-
PropertyValue pathMatcherProp = bd.getPropertyValues().getPropertyValue("pathMatcher");
347-
Object pathMatcher = (pathMatcherProp != null) ? pathMatcherProp.getValue() : null;
348-
if (pathMatcher instanceof BeanReference) {
349-
registry.registerAlias(((BeanReference) pathMatcher).getBeanName(), PATH_MATCHER_BEAN_NAME);
350-
}
351-
}
352349
}
353350
else if (CSRF_HANDSHAKE_HANDLER_CLASSES.contains(beanClassName)) {
354351
addCsrfTokenHandshakeInterceptor(bd);
@@ -376,9 +373,6 @@ else if (CSRF_HANDSHAKE_HANDLER_CLASSES.contains(beanClassName)) {
376373
interceptors.addAll(currentInterceptors);
377374
}
378375
inboundChannel.getPropertyValues().add(INTERCEPTORS_PROP, interceptors);
379-
if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
380-
registry.registerBeanDefinition(PATH_MATCHER_BEAN_NAME, new RootBeanDefinition(AntPathMatcher.class));
381-
}
382376
}
383377

384378
private void addCsrfTokenHandshakeInterceptor(BeanDefinition bd) {

config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.springframework.context.annotation.Configuration;
4646
import org.springframework.context.annotation.Import;
4747
import org.springframework.core.MethodParameter;
48+
import org.springframework.http.server.PathContainer;
4849
import org.springframework.http.server.ServerHttpRequest;
4950
import org.springframework.http.server.ServerHttpResponse;
5051
import org.springframework.messaging.Message;
@@ -70,6 +71,7 @@
7071
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
7172
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
7273
import org.springframework.security.config.observation.SecurityObservationSettings;
74+
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
7375
import org.springframework.security.core.Authentication;
7476
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
7577
import org.springframework.security.core.annotation.AuthenticationPrincipal;
@@ -99,6 +101,7 @@
99101
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
100102
import org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler;
101103
import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession;
104+
import org.springframework.web.util.pattern.PathPatternParser;
102105

103106
import static org.assertj.core.api.Assertions.assertThat;
104107
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -507,6 +510,13 @@ private void loadConfig(Class<?>... configs) {
507510
@Import(SyncExecutorConfig.class)
508511
static class MsmsRegistryCustomPatternMatcherConfig implements WebSocketMessageBrokerConfigurer {
509512

513+
@Bean
514+
PathPatternMessageMatcherBuilderFactoryBean messageMatcherBuilder() {
515+
PathPatternParser parser = new PathPatternParser();
516+
parser.setPathOptions(PathContainer.Options.MESSAGE_ROUTE);
517+
return new PathPatternMessageMatcherBuilderFactoryBean(parser);
518+
}
519+
510520
// @formatter:off
511521
@Override
512522
public void registerStompEndpoints(StompEndpointRegistry registry) {
@@ -518,7 +528,6 @@ public void registerStompEndpoints(StompEndpointRegistry registry) {
518528

519529
@Override
520530
public void configureMessageBroker(MessageBrokerRegistry registry) {
521-
registry.setPathMatcher(new AntPathMatcher("."));
522531
registry.enableSimpleBroker("/queue/", "/topic/");
523532
registry.setApplicationDestinationPrefixes("/app");
524533
}
@@ -567,7 +576,6 @@ public void configureMessageBroker(MessageBrokerRegistry registry) {
567576
@Bean
568577
AuthorizationManager<Message<?>> authorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
569578
messages
570-
.simpDestPathMatcher(new AntPathMatcher())
571579
.simpDestMatchers("/app/a/*").permitAll()
572580
.anyMessage().denyAll();
573581
return messages.build();

messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttribute.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.springframework.messaging.Message;
2424
import org.springframework.security.access.ConfigAttribute;
2525
import org.springframework.security.messaging.util.matcher.MessageMatcher;
26-
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
2726
import org.springframework.util.Assert;
2827

2928
/**
@@ -42,7 +41,7 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
4241

4342
private final Expression authorizeExpression;
4443

45-
private final MessageMatcher<?> matcher;
44+
private final MessageMatcher<Object> matcher;
4645

4746
/**
4847
* Creates a new instance
@@ -53,7 +52,7 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
5352
Assert.notNull(authorizeExpression, "authorizeExpression cannot be null");
5453
Assert.notNull(matcher, "matcher cannot be null");
5554
this.authorizeExpression = authorizeExpression;
56-
this.matcher = matcher;
55+
this.matcher = (MessageMatcher<Object>) matcher;
5756
}
5857

5958
Expression getAuthorizeExpression() {
@@ -72,12 +71,9 @@ public String toString() {
7271

7372
@Override
7473
public EvaluationContext postProcess(EvaluationContext ctx, Message<?> message) {
75-
if (this.matcher instanceof SimpDestinationMessageMatcher) {
76-
Map<String, String> variables = ((SimpDestinationMessageMatcher) this.matcher)
77-
.extractPathVariables(message);
78-
for (Map.Entry<String, String> entry : variables.entrySet()) {
79-
ctx.setVariable(entry.getKey(), entry.getValue());
80-
}
74+
Map<String, String> variables = this.matcher.matcher(message).getVariables();
75+
for (Map.Entry<String, String> entry : variables.entrySet()) {
76+
ctx.setVariable(entry.getKey(), entry.getValue());
8177
}
8278
return ctx;
8379
}

0 commit comments

Comments
 (0)