diff --git a/config/src/test/groovy/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.groovy b/config/src/test/groovy/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.groovy deleted file mode 100644 index b22300a547..0000000000 --- a/config/src/test/groovy/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.groovy +++ /dev/null @@ -1,560 +0,0 @@ -package org.springframework.security.config.websocket - -import static org.mockito.Mockito.* - -import org.springframework.beans.BeansException -import org.springframework.beans.factory.config.BeanDefinition -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory -import org.springframework.beans.factory.parsing.BeanDefinitionParsingException -import org.springframework.beans.factory.support.BeanDefinitionRegistry -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor -import org.springframework.beans.factory.support.RootBeanDefinition -import org.springframework.core.MethodParameter -import org.springframework.core.task.SyncTaskExecutor -import org.springframework.http.server.ServerHttpRequest -import org.springframework.http.server.ServerHttpResponse -import org.springframework.messaging.Message -import org.springframework.messaging.MessageDeliveryException -import org.springframework.messaging.handler.annotation.MessageMapping -import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver -import org.springframework.messaging.simp.SimpMessageHeaderAccessor -import org.springframework.messaging.simp.SimpMessageType -import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler -import org.springframework.messaging.support.ChannelInterceptor -import org.springframework.messaging.support.GenericMessage -import org.springframework.mock.web.MockHttpServletRequest -import org.springframework.mock.web.MockHttpServletResponse -import org.springframework.security.access.AccessDeniedException -import org.springframework.security.access.expression.SecurityExpressionOperations; -import org.springframework.security.authentication.TestingAuthenticationToken -import org.springframework.security.config.AbstractXmlConfigTests -import org.springframework.security.core.Authentication -import org.springframework.security.core.annotation.AuthenticationPrincipal -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler; -import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot; -import org.springframework.security.web.csrf.CsrfToken -import org.springframework.security.web.csrf.DefaultCsrfToken -import org.springframework.security.web.csrf.InvalidCsrfTokenException -import org.springframework.stereotype.Controller -import org.springframework.util.AntPathMatcher -import org.springframework.web.servlet.HandlerMapping -import org.springframework.web.socket.WebSocketHandler -import org.springframework.web.socket.server.HandshakeFailureException -import org.springframework.web.socket.server.HandshakeHandler -import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor -import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler -import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler -import org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler - -import spock.lang.Unroll - -/** - * - * @author Rob Winch - */ -class WebSocketMessageBrokerConfigTests extends AbstractXmlConfigTests { - Authentication messageUser = new TestingAuthenticationToken('user','pass','ROLE_USER') - boolean useSockJS = false - CsrfToken csrfToken = new DefaultCsrfToken('headerName', 'paramName', 'token') - - def cleanup() { - SecurityContextHolder.clearContext() - } - - def 'websocket with no id automatically integrates with clientInboundChannel'() { - setup: - websocket { - 'intercept-message'(pattern:'/permitAll',access:'permitAll') - 'intercept-message'(pattern:'/denyAll',access:'denyAll') - } - - - when: 'message is sent to the denyAll endpoint' - clientInboundChannel.send(message('/denyAll')) - - then: 'access is denied to the denyAll endpoint' - def e = thrown(MessageDeliveryException) - e.cause instanceof AccessDeniedException - - and: 'access is granted to the permitAll endpoint' - clientInboundChannel.send(message('/permitAll')) - } - - def 'anonymous authentication supported'() { - setup: - websocket { - 'intercept-message'(pattern:'/permitAll',access:'permitAll') - 'intercept-message'(pattern:'/denyAll',access:'denyAll') - } - messageUser = null - - when: 'message is sent to the permitAll endpoint with no user' - clientInboundChannel.send(message('/permitAll')) - - then: 'access is granted' - noExceptionThrown() - } - - @Unroll - def "message type - #type"(SimpMessageType type) { - setup: - websocket { - 'intercept-message'('type': type.toString(), access:'permitAll') - 'intercept-message'(pattern:'/**', access:'denyAll') - } - messageUser = null - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(type) - if(SimpMessageType.CONNECT == type) { - headers.setNativeHeader(csrfToken.headerName, csrfToken.token) - } - Message message = message(headers, '/permitAll') - - when: 'message is sent to the permitAll endpoint with no user' - clientInboundChannel.send(message) - - then: 'access is granted' - noExceptionThrown() - - where: - type << SimpMessageType.values() - } - - @Unroll - def "pattern and message type - #type"(SimpMessageType type) { - setup: - websocket { - 'intercept-message'(pattern: '/permitAll', 'type': type.toString(), access:'permitAll') - 'intercept-message'(pattern:'/**', access:'denyAll') - } - - when: 'message is sent to the permitAll endpoint with no user' - clientInboundChannel.send(message('/permitAll', type)) - - then: 'access is granted' - noExceptionThrown() - - when: 'message sent to other message type' - clientInboundChannel.send(message('/permitAll', SimpMessageType.UNSUBSCRIBE)) - - then: 'does not match' - MessageDeliveryException e = thrown() - e.cause instanceof AccessDeniedException - - when: 'message is sent to other pattern' - clientInboundChannel.send(message('/other', type)) - - then: 'does not match' - MessageDeliveryException eOther = thrown() - eOther.cause instanceof AccessDeniedException - - where: - type << [SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE] - } - - @Unroll - def "intercept-message with invalid type and pattern - #type"(SimpMessageType type) { - when: - websocket { - 'intercept-message'(pattern : '/**', 'type': type.toString(), access:'permitAll') - } - then: - thrown(BeanDefinitionParsingException) - - where: - type << [SimpMessageType.CONNECT, SimpMessageType.CONNECT_ACK, SimpMessageType.DISCONNECT, SimpMessageType.DISCONNECT_ACK, SimpMessageType.HEARTBEAT, SimpMessageType.OTHER, SimpMessageType.UNSUBSCRIBE ] - } - - def 'messages with no id automatically adds Authentication argument resolver'() { - setup: - def id = 'authenticationController' - bean(id,MyController) - bean('inPostProcessor',InboundExecutorPostProcessor) - websocket { - 'intercept-message'(pattern:'/**',access:'permitAll') - } - - when: 'message is sent to the authentication endpoint' - clientInboundChannel.send(message('/authentication')) - - then: 'the AuthenticationPrincipal is resolved' - def controller = appContext.getBean(id) - controller.authenticationPrincipal == messageUser.name - } - - def 'messages of type CONNECT use CsrfTokenHandshakeInterceptor'() { - setup: - def id = 'authenticationController' - bean(id,MyController) - bean('inPostProcessor',InboundExecutorPostProcessor) - websocket { - 'intercept-message'(pattern:'/**',access:'permitAll') - } - - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT) - Message message = message(headers,'/authentication') - WebSocketHttpRequestHandler handler = appContext.getBean(WebSocketHttpRequestHandler) - MockHttpServletRequest request = new MockHttpServletRequest() - String sessionAttr = "sessionAttr" - request.getSession().setAttribute(sessionAttr,"sessionValue") - - CsrfToken token = new DefaultCsrfToken("header", "param", "token") - request.setAttribute(CsrfToken.name, token) - - when: - handler.handleRequest(request , new MockHttpServletResponse()) - TestHandshakeHandler handshakeHandler = appContext.getBean(TestHandshakeHandler) - - then: 'CsrfToken is populated' - handshakeHandler.attributes.get(CsrfToken.name) == token - - and: 'Explicitly listed HandshakeInterceptor are not overridden' - handshakeHandler.attributes.get(sessionAttr) == request.getSession().getAttribute(sessionAttr) - } - - def 'messages of type CONNECT use CsrfTokenHandshakeInterceptor with SockJS'() { - setup: - useSockJS = true - def id = 'authenticationController' - bean(id,MyController) - bean('inPostProcessor',InboundExecutorPostProcessor) - websocket { - 'intercept-message'(pattern:'/**',access:'permitAll') - } - - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT) - Message message = message(headers,'/authentication') - SockJsHttpRequestHandler handler = appContext.getBean(SockJsHttpRequestHandler) - MockHttpServletRequest request = new MockHttpServletRequest() - String sessionAttr = "sessionAttr" - request.getSession().setAttribute(sessionAttr,"sessionValue") - - CsrfToken token = new DefaultCsrfToken("header", "param", "token") - request.setAttribute(CsrfToken.name, token) - - request.setMethod("GET") - request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/289/tpyx6mde/websocket") - - when: - handler.handleRequest(request , new MockHttpServletResponse()) - TestHandshakeHandler handshakeHandler = appContext.getBean(TestHandshakeHandler) - - then: 'CsrfToken is populated' - handshakeHandler.attributes?.get(CsrfToken.name) == token - - and: 'Explicitly listed HandshakeInterceptor are not overridden' - handshakeHandler.attributes?.get(sessionAttr) == request.getSession().getAttribute(sessionAttr) - } - - def 'messages of type CONNECT require valid CsrfToken'() { - setup: - def id = 'authenticationController' - bean(id,MyController) - bean('inPostProcessor',InboundExecutorPostProcessor) - websocket { - 'intercept-message'(pattern:'/**',access:'permitAll') - } - - when: 'websocket of type CONNECTION is sent without CsrfTOken' - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT) - Message message = message(headers,'/authentication') - clientInboundChannel.send(message) - - then: 'CSRF Protection blocks the Message' - MessageDeliveryException expected = thrown() - expected.cause instanceof InvalidCsrfTokenException - } - - def 'messages of type CONNECT disabled valid CsrfToken'() { - setup: - def id = 'authenticationController' - bean(id,MyController) - bean('inPostProcessor',InboundExecutorPostProcessor) - websocket('same-origin-disabled':true) { - 'intercept-message'(pattern:'/**',access:'permitAll') - } - - when: 'websocket of type CONNECTION is sent without CsrfTOken' - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT) - Message message = message(headers,'/authentication') - clientInboundChannel.send(message) - - then: 'CSRF Protection blocks the Message' - noExceptionThrown() - } - - def 'websocket with no id does not override customArgumentResolvers'() { - setup: - def id = 'authenticationController' - bean(id,MyController) - bean('inPostProcessor',InboundExecutorPostProcessor) - bean('mcar', MyCustomArgumentResolver) - xml.'websocket:message-broker' { - 'websocket:transport' {} - 'websocket:stomp-endpoint'(path:'/app') { - 'websocket:handshake-handler'(ref:'testHandler') {} - } - 'websocket:simple-broker'(prefix:"/queue, /topic"){} - 'websocket:argument-resolvers' { - 'b:ref'(bean:'mcar') - } - } - websocket { - 'intercept-message'(pattern:'/**',access:'permitAll') - } - - when: 'websocket is sent to the myCustom endpoint' - clientInboundChannel.send(message('/myCustom')) - - then: 'myCustomArgument is resolved' - def controller = appContext.getBean(id) - controller.myCustomArgument!= null - } - - def 'websocket defaults pathMatcher'() { - setup: - bean('pathMatcher',AntPathMatcher.name,['.']) - bean('testHandler', TestHandshakeHandler) - xml.'websocket:message-broker'('path-matcher':'pathMatcher') { - 'websocket:transport' {} - 'websocket:stomp-endpoint'(path:'/app') { - 'websocket:handshake-handler'(ref:'testHandler') {} - } - 'websocket:simple-broker'(prefix:"/queue, /topic"){} - } - xml.'websocket-message-broker' { - 'intercept-message'(pattern:'/denyAll.*',access:'denyAll') - } - createAppContext() - - when: 'sent to denyAll.a' - appContext.getBean(SimpAnnotationMethodMessageHandler) - clientInboundChannel.send(message('/denyAll.a')) - - then: 'access is denied' - MessageDeliveryException expected = thrown() - expected.cause instanceof AccessDeniedException - - when: 'sent to denyAll.a.b' - clientInboundChannel.send(message('/denyAll.a.b')) - - then: 'access is allowed' - noExceptionThrown() - } - - def 'websocket with id does not integrate with clientInboundChannel'() { - setup: - websocket([id:'inCsi']) { - 'intercept-message'(pattern:'/**',access:'denyAll') - } - - when: - def success = clientInboundChannel.send(message('/denyAll')) - - then: - success - - } - - def 'websocket with id can be explicitly integrated with clientInboundChannel'() { - setup: 'websocket security explicitly setup' - xml.'websocket:message-broker' { - 'websocket:transport' {} - 'websocket:stomp-endpoint'(path:'/app') { - 'websocket:sockjs' {} - } - 'websocket:simple-broker'(prefix:"/queue, /topic"){} - 'websocket:client-inbound-channel' { - 'websocket:interceptors' { - 'b:bean'(class:'org.springframework.security.messaging.context.SecurityContextChannelInterceptor'){} - 'b:ref'(bean:'inCsi'){} - } - } - } - xml.'websocket-message-broker'(id:'inCsi') { - 'intercept-message'(pattern:'/**',access:'denyAll') - } - createAppContext() - - when: - clientInboundChannel.send(message('/denyAll')) - - then: - def e = thrown(MessageDeliveryException) - e.cause instanceof AccessDeniedException - - } - - def 'automatic integration with clientInboundChannel does not override exisiting websocket:interceptors'() { - setup: - mockBean(ChannelInterceptor,'mci') - xml.'websocket:message-broker'('application-destination-prefix':'/app', - 'user-destination-prefix':'/user') { - 'websocket:transport' {} - 'websocket:stomp-endpoint'(path:'/foo') { - 'websocket:sockjs' {} - } - 'websocket:simple-broker'(prefix:"/queue, /topic"){} - 'websocket:client-inbound-channel' { - 'websocket:interceptors' { - 'b:ref'(bean:'mci'){} - } - } - } - xml.'websocket-message-broker' { - 'intercept-message'(pattern:'/denyAll',access:'denyAll') - 'intercept-message'(pattern:'/permitAll',access:'permitAll') - } - createAppContext() - ChannelInterceptor mci = appContext.getBean('mci') - when: - Message message = message('/permitAll') - clientInboundChannel.send(message) - - then: - verify(mci).preSend(message, clientInboundChannel) || true - - } - - def websocket(Map attrs=[:], Closure c) { - bean('testHandler', TestHandshakeHandler) - xml.'websocket:message-broker' { - 'websocket:transport' {} - 'websocket:stomp-endpoint'(path:'/app') { - 'websocket:handshake-handler'(ref:'testHandler') {} - 'websocket:handshake-interceptors' { - 'b:bean'('class':HttpSessionHandshakeInterceptor.name) {} - } - if(useSockJS) { - 'websocket:sockjs' {} - } - } - 'websocket:simple-broker'(prefix:"/queue, /topic"){} - } - xml.'websocket-message-broker'(attrs, c) - createAppContext() - } - - def 'custom expressions'() { - setup: - bean('expressionHandler', DenyRobMessageSecurityExpressionHandler) - websocket { - 'expression-handler' (ref: 'expressionHandler') {} - 'intercept-message'(pattern:'/**',access:'denyRob()') - } - - when: 'message is sent with user' - clientInboundChannel.send(message('/message')) - - then: 'access is allowed to custom expression' - noExceptionThrown() - - when: - messageUser = new TestingAuthenticationToken('rob', 'pass', 'ROLE_USER') - clientInboundChannel.send(message('/message')) - - then: - def e = thrown(MessageDeliveryException) - e.cause instanceof AccessDeniedException - } - - def getClientInboundChannel() { - appContext.getBean("clientInboundChannel") - } - - def message(String destination, SimpMessageType type=SimpMessageType.MESSAGE) { - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(type) - message(headers, destination) - } - - def message(SimpMessageHeaderAccessor headers, String destination) { - headers.sessionId = '123' - headers.sessionAttributes = [:] - headers.destination = destination - if(messageUser != null) { - headers.user = messageUser - } - if(csrfToken != null) { - headers.sessionAttributes[CsrfToken.name] = csrfToken - } - new GenericMessage("hi",headers.messageHeaders) - } - - @Controller - static class MyController { - String authenticationPrincipal - MyCustomArgument myCustomArgument - - @MessageMapping('/authentication') - public void authentication(@AuthenticationPrincipal String un) { - this.authenticationPrincipal = un - } - - @MessageMapping('/myCustom') - public void myCustom(MyCustomArgument myCustomArgument) { - this.myCustomArgument = myCustomArgument - } - } - - static class MyCustomArgument { - MyCustomArgument(String notDefaultConstr) {} - } - - static class MyCustomArgumentResolver implements HandlerMethodArgumentResolver { - - @Override - boolean supportsParameter(MethodParameter parameter) { - parameter.parameterType.isAssignableFrom(MyCustomArgument) - } - - @Override - Object resolveArgument(MethodParameter parameter, Message message) throws Exception { - new MyCustomArgument("") - } - } - - static class TestHandshakeHandler implements HandshakeHandler { - Map attributes; - - boolean doHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws HandshakeFailureException { - this.attributes = attributes - if(wsHandler instanceof SockJsWebSocketHandler) { - // work around SPR-12716 - SockJsWebSocketHandler sockJs = (SockJsWebSocketHandler) wsHandler; - this.attributes = sockJs.sockJsSession.attributes - } - true - } - } - - /** - * Changes the clientInboundChannel Executor to be synchronous - */ - static class InboundExecutorPostProcessor implements BeanDefinitionRegistryPostProcessor { - - @Override - void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { - BeanDefinition inbound = registry.getBeanDefinition("clientInboundChannel") - inbound.getConstructorArgumentValues().addIndexedArgumentValue(0, new RootBeanDefinition(SyncTaskExecutor)); - } - - @Override - void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - - } - } - - static class DenyRobMessageSecurityExpressionHandler extends DefaultMessageSecurityExpressionHandler { - @Override - protected SecurityExpressionOperations createSecurityExpressionRoot( - Authentication authentication, - Message invocation) { - return new MessageSecurityExpressionRoot(authentication, invocation) { - public boolean denyRob() { - Authentication auth = getAuthentication(); - return auth != null && !"rob".equals(auth.getName()); - } - }; - } - } -} diff --git a/config/src/test/java/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.java b/config/src/test/java/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.java new file mode 100644 index 0000000000..494ceaa457 --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests.java @@ -0,0 +1,547 @@ +/* + * Copyright 2002-2018 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 + * + * http://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.config.websocket; + +import org.assertj.core.api.ThrowableAssert; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.MethodParameter; +import org.springframework.core.task.SyncTaskExecutor; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.messaging.simp.SimpMessageType; +import org.springframework.messaging.support.ChannelInterceptorAdapter; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.access.expression.SecurityExpressionOperations; +import org.springframework.security.config.test.SpringTestRule; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler; +import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot; +import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.security.web.csrf.DefaultCsrfToken; +import org.springframework.security.web.csrf.InvalidCsrfTokenException; +import org.springframework.stereotype.Controller; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.HandshakeFailureException; +import org.springframework.web.socket.server.HandshakeHandler; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + +/** + * @author Rob Winch + * @author Josh Cummings + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SecurityTestExecutionListeners +public class WebSocketMessageBrokerConfigTests { + private static final String CONFIG_LOCATION_PREFIX = + "classpath:org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests"; + + @Rule + public final SpringTestRule spring = new SpringTestRule(); + + @Autowired(required = false) + private MessageChannel clientInboundChannel; + + @Autowired(required = false) + private MessageController messageController; + + @Autowired(required = false) + private MessageWithArgumentController messageWithArgumentController; + + @Autowired(required = false) + private TestHandshakeHandler testHandshakeHandler; + + private CsrfToken token = new DefaultCsrfToken("header", "param", "token"); + + @Test + public void sendWhenNoIdSpecifiedThenIntegratesWithClientInboundChannel() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + this.clientInboundChannel.send(message("/permitAll")); + + assertThatThrownBy(() -> this.clientInboundChannel.send(message("/denyAll"))) + .hasCauseInstanceOf(AccessDeniedException.class); + } + + @Test + public void sendWhenAnonymousMessageWithConnectMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); + headers.setNativeHeader(this.token.getHeaderName(), this.token.getToken()); + + assertThatCode(() -> this.clientInboundChannel.send(message("/permitAll", headers))) + .doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithConnectAckMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.CONNECT_ACK); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithDisconnectMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.DISCONNECT); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithDisconnectAckMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.DISCONNECT_ACK); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithHeartbeatMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.HEARTBEAT); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithMessageMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.MESSAGE); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithOtherMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.OTHER); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithSubscribeMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.SUBSCRIBE); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenAnonymousMessageWithUnsubscribeMessageTypeThenPermitted() { + this.spring.configLocations(xml("NoIdConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.UNSUBSCRIBE); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenConnectWithoutCsrfTokenThenDenied() { + this.spring.configLocations(xml("SyncConfig")).autowire(); + + Message message = message("/message", SimpMessageType.CONNECT); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(InvalidCsrfTokenException.class); + } + + @Test + public void sendWhenConnectWithSameOriginDisabledThenCsrfTokenNotRequired() { + this.spring.configLocations(xml("SyncSameOriginDisabledConfig")).autowire(); + + Message message = message("/message", SimpMessageType.CONNECT); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenInterceptWiredForMessageTypeThenDeniesOnTypeMismatch() { + this.spring.configLocations(xml("MessageInterceptTypeConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.MESSAGE); + + assertThatCode(send(message)).doesNotThrowAnyException(); + + message = message("/permitAll", SimpMessageType.UNSUBSCRIBE); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(AccessDeniedException.class); + + message = message("/anyOther", SimpMessageType.MESSAGE); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(AccessDeniedException.class); + } + + @Test + public void sendWhenInterceptWiredForSubscribeTypeThenDeniesOnTypeMismatch() { + this.spring.configLocations(xml("SubscribeInterceptTypeConfig")).autowire(); + + Message message = message("/permitAll", SimpMessageType.SUBSCRIBE); + + assertThatCode(send(message)).doesNotThrowAnyException(); + + message = message("/permitAll", SimpMessageType.UNSUBSCRIBE); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(AccessDeniedException.class); + + message = message("/anyOther", SimpMessageType.SUBSCRIBE); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(AccessDeniedException.class); + } + + // -- invalid intercept types -- // + + @Test + public void configureWhenUsingConnectMessageTypeThenAutowireFails() { + ThrowingCallable bad = () -> + this.spring.configLocations(xml("ConnectInterceptTypeConfig")).autowire(); + + assertThatThrownBy(bad).isInstanceOf(BeanDefinitionParsingException.class); + } + + @Test + public void configureWhenUsingConnectAckMessageTypeThenAutowireFails() { + ThrowingCallable bad = () -> + this.spring.configLocations(xml("ConnectAckInterceptTypeConfig")).autowire(); + + assertThatThrownBy(bad).isInstanceOf(BeanDefinitionParsingException.class); + } + + @Test + public void configureWhenUsingDisconnectMessageTypeThenAutowireFails() { + ThrowingCallable bad = () -> + this.spring.configLocations(xml("DisconnectInterceptTypeConfig")).autowire(); + + assertThatThrownBy(bad).isInstanceOf(BeanDefinitionParsingException.class); + } + + @Test + public void configureWhenUsingDisconnectAckMessageTypeThenAutowireFails() { + ThrowingCallable bad = () -> + this.spring.configLocations(xml("DisconnectAckInterceptTypeConfig")).autowire(); + + assertThatThrownBy(bad).isInstanceOf(BeanDefinitionParsingException.class); + } + + @Test + public void configureWhenUsingHeartbeatMessageTypeThenAutowireFails() { + ThrowingCallable bad = () -> + this.spring.configLocations(xml("HeartbeatInterceptTypeConfig")).autowire(); + + assertThatThrownBy(bad).isInstanceOf(BeanDefinitionParsingException.class); + } + + @Test + public void configureWhenUsingOtherMessageTypeThenAutowireFails() { + ThrowingCallable bad = () -> + this.spring.configLocations(xml("OtherInterceptTypeConfig")).autowire(); + + assertThatThrownBy(bad).isInstanceOf(BeanDefinitionParsingException.class); + } + + @Test + public void configureWhenUsingUnsubscribeMessageTypeThenAutowireFails() { + ThrowingCallable bad = () -> + this.spring.configLocations(xml("UnsubscribeInterceptTypeConfig")).autowire(); + + assertThatThrownBy(bad).isInstanceOf(BeanDefinitionParsingException.class); + } + + @Test + public void sendWhenNoIdMessageThenAuthenticationPrincipalResolved() throws Exception { + this.spring.configLocations(xml("SyncConfig")).autowire(); + + this.clientInboundChannel.send(message("/message")); + + assertThat(this.messageController.username).isEqualTo("anonymous"); + } + + @Test + public void requestWhenConnectMessageThenUsesCsrfTokenHandshakeInterceptor() throws Exception { + this.spring.configLocations(xml("SyncConfig")).autowire(); + + WebApplicationContext context = (WebApplicationContext) this.spring.getContext(); + MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build(); + + String csrfAttributeName = CsrfToken.class.getName(); + String customAttributeName = this.getClass().getName(); + + MvcResult result = mvc.perform(get("/app") + .requestAttr(csrfAttributeName, this.token) + .sessionAttr(customAttributeName, "attributeValue")) + .andReturn(); + + CsrfToken handshakeToken = (CsrfToken) this.testHandshakeHandler.attributes.get(csrfAttributeName); + String handshakeValue = (String) this.testHandshakeHandler.attributes.get(customAttributeName); + String sessionValue = (String) result.getRequest().getSession().getAttribute(customAttributeName); + + assertThat(handshakeToken).isEqualTo(this.token) + .withFailMessage("CsrfToken is populated"); + + assertThat(handshakeValue).isEqualTo(sessionValue) + .withFailMessage("Explicitly listed session variables are not overridden"); + } + + @Test + public void requestWhenConnectMessageAndUsingSockJsThenUsesCsrfTokenHandshakeInterceptor() throws Exception { + this.spring.configLocations(xml("SyncSockJsConfig")).autowire(); + + WebApplicationContext context = (WebApplicationContext) this.spring.getContext(); + MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build(); + + String csrfAttributeName = CsrfToken.class.getName(); + String customAttributeName = this.getClass().getName(); + + MvcResult result = mvc.perform(get("/app/289/tpyx6mde/websocket") + .requestAttr(csrfAttributeName, this.token) + .sessionAttr(customAttributeName, "attributeValue")) + .andReturn(); + + CsrfToken handshakeToken = (CsrfToken) this.testHandshakeHandler.attributes.get(csrfAttributeName); + String handshakeValue = (String) this.testHandshakeHandler.attributes.get(customAttributeName); + String sessionValue = (String) result.getRequest().getSession().getAttribute(customAttributeName); + + assertThat(handshakeToken).isEqualTo(this.token) + .withFailMessage("CsrfToken is populated"); + + assertThat(handshakeValue).isEqualTo(sessionValue) + .withFailMessage("Explicitly listed session variables are not overridden"); + } + + @Test + public void sendWhenNoIdSpecifiedThenCustomArgumentResolversAreNotOverridden() { + this.spring.configLocations(xml("SyncCustomArgumentResolverConfig")).autowire(); + + this.clientInboundChannel.send(message("/message-with-argument")); + + assertThat(this.messageWithArgumentController.messageArgument).isNotNull(); + } + + @Test + public void sendWhenUsingCustomPathMatcherThenSecurityAppliesIt() { + this.spring.configLocations(xml("CustomPathMatcherConfig")).autowire(); + + Message message = message("/denyAll.a"); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(AccessDeniedException.class); + + message = message("/denyAll.a.b"); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + public void sendWhenIdSpecifiedThenSecurityDoesNotIntegrateWithClientInboundChannel() { + this.spring.configLocations(xml("IdConfig")).autowire(); + + Message message = message("/denyAll"); + + assertThatCode(send(message)).doesNotThrowAnyException(); + } + + @Test + @WithMockUser + public void sendWhenIdSpecifiedAndExplicitlyIntegratedWhenBrokerUsesClientInboundChannel() { + this.spring.configLocations(xml("IdIntegratedConfig")).autowire(); + + Message message = message("/denyAll"); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(AccessDeniedException.class); + } + + @Test + public void sendWhenNoIdSpecifiedThenSecurityDoesntOverrideCustomInterceptors() { + this.spring.configLocations(xml("CustomInterceptorConfig")).autowire(); + + Message message = message("/throwAll"); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(UnsupportedOperationException.class); + } + + @Test + @WithMockUser(username = "nile") + public void sendWhenCustomExpressionHandlerThenAuthorizesAccordingly() { + this.spring.configLocations(xml("CustomExpressionHandlerConfig")).autowire(); + + Message message = message("/denyNile"); + + assertThatThrownBy(send(message)).hasCauseInstanceOf(AccessDeniedException.class); + } + + private String xml(String configName) { + return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml"; + } + + private ThrowableAssert.ThrowingCallable send(Message message) { + return () -> this.clientInboundChannel.send(message); + } + + private Message message(String destination) { + return message(destination, SimpMessageType.MESSAGE); + } + + private Message message(String destination, SimpMessageType type) { + SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(type); + return message(destination, headers); + } + + private Message message(String destination, SimpMessageHeaderAccessor headers) { + headers.setSessionId("123"); + headers.setSessionAttributes(new HashMap<>()); + headers.setDestination(destination); + + if (SecurityContextHolder.getContext().getAuthentication() != null) { + headers.setUser(SecurityContextHolder.getContext().getAuthentication()); + } + + headers.getSessionAttributes().put(CsrfToken.class.getName(), this.token); + + return new GenericMessage<>("hi", headers.getMessageHeaders()); + } + + @Controller + static class MessageController { + String username; + + @MessageMapping("/message") + public void authentication(@AuthenticationPrincipal String username) { + this.username = username; + } + } + + @Controller + static class MessageWithArgumentController { + MessageArgument messageArgument; + + @MessageMapping("/message-with-argument") + public void myCustom(MessageArgument messageArgument) { + this.messageArgument = messageArgument; + } + } + + + static class MessageArgument { + MessageArgument(String notDefaultConstructor) { + } + } + + static class MessageArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.getParameterType().isAssignableFrom(MessageArgument.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, Message message) throws Exception { + return new MessageArgument(""); + } + } + + static class TestHandshakeHandler implements HandshakeHandler { + Map attributes; + + @Override + public boolean doHandshake( + ServerHttpRequest request, + org.springframework.http.server.ServerHttpResponse response, + WebSocketHandler wsHandler, + Map attributes) throws HandshakeFailureException { + + this.attributes = attributes; + + return true; + } + } + + static class InboundExecutorPostProcessor implements BeanDefinitionRegistryPostProcessor { + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + BeanDefinition inbound = registry.getBeanDefinition("clientInboundChannel"); + inbound.getConstructorArgumentValues() + .addIndexedArgumentValue(0, new RootBeanDefinition(SyncTaskExecutor.class)); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + + } + } + + static class ExceptingInterceptor extends ChannelInterceptorAdapter { + + @Override + public Message preSend(Message message, MessageChannel channel) { + throw new UnsupportedOperationException("no"); + } + } + + static class DenyNileMessageSecurityExpressionHandler + extends DefaultMessageSecurityExpressionHandler { + + @Override + protected SecurityExpressionOperations createSecurityExpressionRoot( + Authentication authentication, + Message invocation) { + + return new MessageSecurityExpressionRoot(authentication, invocation) { + public boolean denyNile() { + Authentication auth = getAuthentication(); + return auth != null && !"nile".equals(auth.getName()); + } + }; + } + } +} diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-ConnectAckInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-ConnectAckInterceptTypeConfig.xml new file mode 100644 index 0000000000..a552da7d0b --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-ConnectAckInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-ConnectInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-ConnectInterceptTypeConfig.xml new file mode 100644 index 0000000000..6aad9392f6 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-ConnectInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomExpressionHandlerConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomExpressionHandlerConfig.xml new file mode 100644 index 0000000000..1233c499cb --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomExpressionHandlerConfig.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomInterceptorConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomInterceptorConfig.xml new file mode 100644 index 0000000000..f04e58b04f --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomInterceptorConfig.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomPathMatcherConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomPathMatcherConfig.xml new file mode 100644 index 0000000000..d6f3425d99 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-CustomPathMatcherConfig.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-DisconnectAckInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-DisconnectAckInterceptTypeConfig.xml new file mode 100644 index 0000000000..5de4483b2b --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-DisconnectAckInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-DisconnectInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-DisconnectInterceptTypeConfig.xml new file mode 100644 index 0000000000..d95757eb27 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-DisconnectInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-HeartbeatInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-HeartbeatInterceptTypeConfig.xml new file mode 100644 index 0000000000..d95757eb27 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-HeartbeatInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-IdConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-IdConfig.xml new file mode 100644 index 0000000000..6e50edd5fd --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-IdConfig.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-IdIntegratedConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-IdIntegratedConfig.xml new file mode 100644 index 0000000000..e902996305 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-IdIntegratedConfig.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-MessageInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-MessageInterceptTypeConfig.xml new file mode 100644 index 0000000000..58ea2babd3 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-MessageInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-NoIdConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-NoIdConfig.xml new file mode 100644 index 0000000000..ea01b96849 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-NoIdConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-OtherInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-OtherInterceptTypeConfig.xml new file mode 100644 index 0000000000..1555ff77e5 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-OtherInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SubscribeInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SubscribeInterceptTypeConfig.xml new file mode 100644 index 0000000000..116b84599d --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SubscribeInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncConfig.xml new file mode 100644 index 0000000000..e1d7668cfe --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncCustomArgumentResolverConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncCustomArgumentResolverConfig.xml new file mode 100644 index 0000000000..537ec37946 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncCustomArgumentResolverConfig.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncSameOriginDisabledConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncSameOriginDisabledConfig.xml new file mode 100644 index 0000000000..9b119ef1df --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncSameOriginDisabledConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncSockJsConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncSockJsConfig.xml new file mode 100644 index 0000000000..815b787be2 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-SyncSockJsConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-UnsubscribeInterceptTypeConfig.xml b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-UnsubscribeInterceptTypeConfig.xml new file mode 100644 index 0000000000..28586d746c --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests-UnsubscribeInterceptTypeConfig.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/controllers.xml b/config/src/test/resources/org/springframework/security/config/websocket/controllers.xml new file mode 100644 index 0000000000..782a8b59c5 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/controllers.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/sync.xml b/config/src/test/resources/org/springframework/security/config/websocket/sync.xml new file mode 100644 index 0000000000..a085b97b00 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/sync.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/websocket-sockjs.xml b/config/src/test/resources/org/springframework/security/config/websocket/websocket-sockjs.xml new file mode 100644 index 0000000000..c0feabb920 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/websocket-sockjs.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/websocket/websocket.xml b/config/src/test/resources/org/springframework/security/config/websocket/websocket.xml new file mode 100644 index 0000000000..c0f0204c57 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/websocket/websocket.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + +