Skip to content

Commit ec16322

Browse files
committed
Merge branch '6.5.x'
2 parents b7ae991 + bc0d706 commit ec16322

File tree

6 files changed

+204
-15
lines changed

6 files changed

+204
-15
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2002-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config.http;
18+
19+
import org.springframework.beans.BeansException;
20+
import org.springframework.beans.factory.FactoryBean;
21+
import org.springframework.context.ApplicationContext;
22+
import org.springframework.context.ApplicationContextAware;
23+
import org.springframework.messaging.simp.SimpMessageType;
24+
import org.springframework.security.messaging.util.matcher.MessageMatcher;
25+
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;
29+
30+
@Deprecated
31+
public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatcher<?>>, ApplicationContextAware {
32+
33+
private PathPatternMessageMatcher.Builder builder;
34+
35+
private final SimpMessageType method;
36+
37+
private final String path;
38+
39+
private PathMatcher pathMatcher = new AntPathMatcher();
40+
41+
public MessageMatcherFactoryBean(String path) {
42+
this(path, null);
43+
}
44+
45+
public MessageMatcherFactoryBean(String path, SimpMessageType method) {
46+
this.method = method;
47+
this.path = path;
48+
}
49+
50+
@Override
51+
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);
62+
}
63+
64+
@Override
65+
public Class<?> getObjectType() {
66+
return null;
67+
}
68+
69+
public void setPathMatcher(PathMatcher pathMatcher) {
70+
this.pathMatcher = pathMatcher;
71+
}
72+
73+
@Override
74+
public void setApplicationContext(ApplicationContext context) throws BeansException {
75+
this.builder = context.getBeanProvider(PathPatternMessageMatcher.Builder.class).getIfUnique();
76+
}
77+
78+
}

config/src/main/java/org/springframework/security/config/web/messaging/PathPatternMessageMatcherBuilderFactoryBean.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.beans.factory.FactoryBean;
2020
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
2121
import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
22+
import org.springframework.web.util.pattern.PathPatternParser;
2223

2324
/**
2425
* Use this factory bean to configure the {@link PathPatternMessageMatcher.Builder} bean
@@ -31,9 +32,30 @@
3132
public final class PathPatternMessageMatcherBuilderFactoryBean
3233
implements FactoryBean<PathPatternMessageMatcher.Builder> {
3334

35+
private PathPatternParser parser;
36+
37+
/**
38+
* Create {@link PathPatternMessageMatcher}s using
39+
* {@link PathPatternParser#defaultInstance}
40+
*/
41+
public PathPatternMessageMatcherBuilderFactoryBean() {
42+
43+
}
44+
45+
/**
46+
* Create {@link PathPatternMessageMatcher}s using the given {@link PathPatternParser}
47+
* @param parser the {@link PathPatternParser} to use
48+
*/
49+
public PathPatternMessageMatcherBuilderFactoryBean(PathPatternParser parser) {
50+
this.parser = parser;
51+
}
52+
3453
@Override
3554
public PathPatternMessageMatcher.Builder getObject() throws Exception {
36-
return PathPatternMessageMatcher.withDefaults();
55+
if (this.parser == null) {
56+
return PathPatternMessageMatcher.withDefaults();
57+
}
58+
return PathPatternMessageMatcher.withPathPatternParser(this.parser);
3759
}
3860

3961
@Override

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

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.springframework.security.authorization.AuthorizationManager;
5656
import org.springframework.security.authorization.AuthorizationResult;
5757
import org.springframework.security.config.Elements;
58+
import org.springframework.security.config.http.MessageMatcherFactoryBean;
5859
import org.springframework.security.core.Authentication;
5960
import org.springframework.security.core.context.SecurityContextHolder;
6061
import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -68,7 +69,6 @@
6869
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
6970
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
7071
import org.springframework.security.messaging.util.matcher.MessageMatcher;
71-
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
7272
import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher;
7373
import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor;
7474
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
@@ -275,25 +275,18 @@ private BeanDefinition createMatcher(String matcherPattern, String messageType,
275275
matcher.addConstructorArgValue(messageType);
276276
return matcher.getBeanDefinition();
277277
}
278-
String factoryName = null;
279-
if (hasPattern && hasMessageType) {
278+
BeanDefinitionBuilder matcher = BeanDefinitionBuilder.rootBeanDefinition(MessageMatcherFactoryBean.class);
279+
matcher.addConstructorArgValue(matcherPattern);
280+
if (hasMessageType) {
280281
SimpMessageType type = SimpMessageType.valueOf(messageType);
281-
if (SimpMessageType.MESSAGE == type) {
282-
factoryName = "createMessageMatcher";
283-
}
284-
else if (SimpMessageType.SUBSCRIBE == type) {
285-
factoryName = "createSubscribeMatcher";
286-
}
287-
else {
282+
matcher.addConstructorArgValue(type);
283+
if (SimpMessageType.SUBSCRIBE != type && SimpMessageType.MESSAGE != type) {
288284
parserContext.getReaderContext()
289285
.error("Cannot use intercept-websocket@message-type=" + messageType
290286
+ " with a pattern because the type does not have a destination.", interceptMessage);
291287
}
292288
}
293-
BeanDefinitionBuilder matcher = BeanDefinitionBuilder.rootBeanDefinition(SimpDestinationMessageMatcher.class);
294-
matcher.setFactoryMethod(factoryName);
295-
matcher.addConstructorArgValue(matcherPattern);
296-
matcher.addConstructorArgValue(new RuntimeBeanReference("springSecurityMessagePathMatcher"));
289+
matcher.addPropertyValue("pathMatcher", new RuntimeBeanReference("springSecurityMessagePathMatcher"));
297290
return matcher.getBeanDefinition();
298291
}
299292

config/src/test/java/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,32 @@ public void sendWhenInterceptWiredForSubscribeTypeThenAuthorizationManagerDenies
342342
.withCauseInstanceOf(AccessDeniedException.class);
343343
}
344344

345+
@Test
346+
public void sendWhenPathPatternFactoryBeanThenConstructsPatternsWithPathPattern() {
347+
this.spring.configLocations(xml("SubscribeInterceptTypePathPattern")).autowire();
348+
Message<?> message = message("/permitAll", SimpMessageType.SUBSCRIBE);
349+
send(message);
350+
message = message("/permitAll", SimpMessageType.UNSUBSCRIBE);
351+
assertThatExceptionOfType(Exception.class).isThrownBy(send(message))
352+
.withCauseInstanceOf(AccessDeniedException.class);
353+
message = message("/anyOther", SimpMessageType.SUBSCRIBE);
354+
assertThatExceptionOfType(Exception.class).isThrownBy(send(message))
355+
.withCauseInstanceOf(AccessDeniedException.class);
356+
}
357+
358+
@Test
359+
public void sendWhenCaseInsensitivePathPatternParserThenMatchesMixedCase() {
360+
this.spring.configLocations(xml("SubscribeInterceptTypePathPatternParser")).autowire();
361+
Message<?> message = message("/peRmItAll", SimpMessageType.SUBSCRIBE);
362+
send(message);
363+
message = message("/peRmKtAll", SimpMessageType.UNSUBSCRIBE);
364+
assertThatExceptionOfType(Exception.class).isThrownBy(send(message))
365+
.withCauseInstanceOf(AccessDeniedException.class);
366+
message = message("/aNyOtHer", SimpMessageType.SUBSCRIBE);
367+
assertThatExceptionOfType(Exception.class).isThrownBy(send(message))
368+
.withCauseInstanceOf(AccessDeniedException.class);
369+
}
370+
345371
@Test
346372
public void configureWhenUsingConnectMessageTypeThenAutowireFails() {
347373
assertThatExceptionOfType(BeanDefinitionParsingException.class)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2002-2018 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
18+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xmlns="http://www.springframework.org/schema/security"
20+
xsi:schemaLocation="http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
21+
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
22+
23+
<b:import resource="classpath:org/springframework/security/config/websocket/controllers.xml"/>
24+
<b:import resource="classpath:org/springframework/security/config/websocket/websocket.xml"/>
25+
26+
<websocket-message-broker>
27+
<intercept-message pattern="/permitAll" type="SUBSCRIBE" access="permitAll"/>
28+
<intercept-message pattern="/**" access="denyAll"/>
29+
</websocket-message-broker>
30+
31+
<b:bean class="org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean"/>
32+
</b:beans>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2002-2018 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
18+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xmlns="http://www.springframework.org/schema/security"
20+
xsi:schemaLocation="http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
21+
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
22+
23+
<b:import resource="classpath:org/springframework/security/config/websocket/controllers.xml"/>
24+
<b:import resource="classpath:org/springframework/security/config/websocket/websocket.xml"/>
25+
26+
<websocket-message-broker>
27+
<intercept-message pattern="/permitAll" type="SUBSCRIBE" access="permitAll"/>
28+
<intercept-message pattern="/**" access="denyAll"/>
29+
</websocket-message-broker>
30+
31+
<b:bean name="pathPatternParser" class="org.springframework.web.util.pattern.PathPatternParser">
32+
<b:property name="caseSensitive" value="false"/>
33+
</b:bean>
34+
35+
<b:bean class="org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean">
36+
<b:constructor-arg ref="pathPatternParser"/>
37+
</b:bean>
38+
</b:beans>

0 commit comments

Comments
 (0)