Переглянути джерело

Default to XorCsrfChannelInterceptor in XML

Change WebSocketMessageBrokerSecurityBeanDefinitionParser to use
XorCsrfChannelInterceptor by default, so WebSocket XML configuration
matches the default Xor-based configuration already in
WebSocketMessageBrokerSecurityConfiguration.

Closes gh-17260

Signed-off-by: Matt Magoffin <matt@solarnetwork.net>
Matt Magoffin 2 місяців тому
батько
коміт
62252c1232

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

@@ -70,7 +70,7 @@ import org.springframework.security.messaging.context.SecurityContextChannelInte
 import org.springframework.security.messaging.util.matcher.MessageMatcher;
 import org.springframework.security.messaging.util.matcher.MessageMatcher;
 import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
 import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
 import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher;
 import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher;
-import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor;
+import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor;
 import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
 import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.Assert;
 import org.springframework.util.Assert;
@@ -368,7 +368,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
 			interceptors.add(new RootBeanDefinition(SecurityContextChannelInterceptor.class));
 			interceptors.add(new RootBeanDefinition(SecurityContextChannelInterceptor.class));
 			if (!this.sameOriginDisabled) {
 			if (!this.sameOriginDisabled) {
 				if (!registry.containsBeanDefinition(CSRF_CHANNEL_INTERCEPTOR_BEAN_ID)) {
 				if (!registry.containsBeanDefinition(CSRF_CHANNEL_INTERCEPTOR_BEAN_ID)) {
-					interceptors.add(new RootBeanDefinition(CsrfChannelInterceptor.class));
+					interceptors.add(new RootBeanDefinition(XorCsrfChannelInterceptor.class));
 				}
 				}
 				else {
 				else {
 					interceptors.add(new RuntimeBeanReference(CSRF_CHANNEL_INTERCEPTOR_BEAN_ID));
 					interceptors.add(new RuntimeBeanReference(CSRF_CHANNEL_INTERCEPTOR_BEAN_ID));

+ 10 - 2
config/src/test/java/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.java

@@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.annotation.Target;
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
@@ -98,6 +99,13 @@ public class WebSocketMessageBrokerConfigTests {
 
 
 	private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests";
 	private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests";
 
 
+	/*
+	 * Token format: "token" length random pad bytes + "token" (each byte UTF8 ^= 1).
+	 */
+	private static final byte[] XOR_CSRF_TOKEN_BYTES = new byte[] { 1, 1, 1, 1, 1, 117, 110, 106, 100, 111 };
+
+	private static final String XOR_CSRF_TOKEN_VALUE = Base64.getEncoder().encodeToString(XOR_CSRF_TOKEN_BYTES);
+
 	public final SpringTestContext spring = new SpringTestContext(this);
 	public final SpringTestContext spring = new SpringTestContext(this);
 
 
 	@Autowired(required = false)
 	@Autowired(required = false)
@@ -126,7 +134,7 @@ public class WebSocketMessageBrokerConfigTests {
 	public void sendWhenAnonymousMessageWithConnectMessageTypeThenPermitted() {
 	public void sendWhenAnonymousMessageWithConnectMessageTypeThenPermitted() {
 		this.spring.configLocations(xml("NoIdConfig")).autowire();
 		this.spring.configLocations(xml("NoIdConfig")).autowire();
 		SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
 		SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
-		headers.setNativeHeader(this.token.getHeaderName(), this.token.getToken());
+		headers.setNativeHeader(this.token.getHeaderName(), XOR_CSRF_TOKEN_VALUE);
 		this.clientInboundChannel.send(message("/permitAll", headers));
 		this.clientInboundChannel.send(message("/permitAll", headers));
 	}
 	}
 
 
@@ -198,7 +206,7 @@ public class WebSocketMessageBrokerConfigTests {
 	public void sendWhenAnonymousMessageWithConnectMessageTypeThenAuthorizationManagerPermits() {
 	public void sendWhenAnonymousMessageWithConnectMessageTypeThenAuthorizationManagerPermits() {
 		this.spring.configLocations(xml("NoIdAuthorizationManager")).autowire();
 		this.spring.configLocations(xml("NoIdAuthorizationManager")).autowire();
 		SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
 		SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
-		headers.setNativeHeader(this.token.getHeaderName(), this.token.getToken());
+		headers.setNativeHeader(this.token.getHeaderName(), XOR_CSRF_TOKEN_VALUE);
 		this.clientInboundChannel.send(message("/permitAll", headers));
 		this.clientInboundChannel.send(message("/permitAll", headers));
 	}
 	}