diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java deleted file mode 100644 index cd2baed7335..00000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2002-2022 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.config.annotation.web.socket; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; -import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler; -import org.springframework.messaging.simp.config.ChannelRegistration; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.expression.SecurityExpressionHandler; -import org.springframework.security.access.vote.AffirmativeBased; -import org.springframework.security.config.ObjectPostProcessor; -import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler; -import org.springframework.security.messaging.access.expression.MessageExpressionVoter; -import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor; -import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource; -import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver; -import org.springframework.security.messaging.context.SecurityContextChannelInterceptor; -import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor; -import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.Assert; -import org.springframework.util.PathMatcher; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; -import org.springframework.web.socket.server.HandshakeInterceptor; -import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler; -import org.springframework.web.socket.sockjs.SockJsService; -import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler; -import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService; - -/** - * Allows configuring WebSocket Authorization. - * - *

- * For example: - *

- * - *
- * @Configuration
- * public class WebSocketSecurityConfig extends
- * 		AbstractSecurityWebSocketMessageBrokerConfigurer {
- *
- * 	@Override
- * 	protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
- * 		messages.simpDestMatchers("/user/queue/errors").permitAll()
- * 				.simpDestMatchers("/admin/**").hasRole("ADMIN").anyMessage()
- * 				.authenticated();
- * 	}
- * }
- * 
- * - * @author Rob Winch - * @since 4.0 - * @see WebSocketMessageBrokerSecurityConfiguration - * @deprecated Use {@link EnableWebSocketSecurity} instead - */ -@Order(Ordered.HIGHEST_PRECEDENCE + 100) -@Import(ObjectPostProcessorConfiguration.class) -@Deprecated -public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer - implements WebSocketMessageBrokerConfigurer, SmartInitializingSingleton { - - private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry(); - - private SecurityExpressionHandler> defaultExpressionHandler = new DefaultMessageSecurityExpressionHandler<>(); - - private SecurityExpressionHandler> expressionHandler; - - private ApplicationContext context; - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - } - - @Override - public void addArgumentResolvers(List argumentResolvers) { - argumentResolvers.add(new AuthenticationPrincipalArgumentResolver()); - } - - @Override - public final void configureClientInboundChannel(ChannelRegistration registration) { - ChannelSecurityInterceptor inboundChannelSecurity = this.context.getBean(ChannelSecurityInterceptor.class); - registration.interceptors(this.context.getBean(SecurityContextChannelInterceptor.class)); - if (!sameOriginDisabled()) { - registration.interceptors(this.context.getBean(CsrfChannelInterceptor.class)); - } - if (this.inboundRegistry.containsMapping()) { - registration.interceptors(inboundChannelSecurity); - } - customizeClientInboundChannel(registration); - } - - private PathMatcher getDefaultPathMatcher() { - try { - return this.context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher(); - } - catch (NoSuchBeanDefinitionException ex) { - return new AntPathMatcher(); - } - } - - /** - *

- * Determines if a CSRF token is required for connecting. This protects against remote - * sites from connecting to the application and being able to read/write data over the - * connection. The default is false (the token is required). - *

- *

- * Subclasses can override this method to disable CSRF protection - *

- * @return false if a CSRF token is required for connecting, else true - */ - protected boolean sameOriginDisabled() { - return false; - } - - /** - * Allows subclasses to customize the configuration of the {@link ChannelRegistration} - * . - * @param registration the {@link ChannelRegistration} to customize - */ - protected void customizeClientInboundChannel(ChannelRegistration registration) { - } - - @Bean - public CsrfChannelInterceptor csrfChannelInterceptor() { - return new CsrfChannelInterceptor(); - } - - @Bean - public ChannelSecurityInterceptor inboundChannelSecurity( - MessageSecurityMetadataSource messageSecurityMetadataSource) { - ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor( - messageSecurityMetadataSource); - MessageExpressionVoter voter = new MessageExpressionVoter<>(); - voter.setExpressionHandler(getMessageExpressionHandler()); - List> voters = new ArrayList<>(); - voters.add(voter); - AffirmativeBased manager = new AffirmativeBased(voters); - channelSecurityInterceptor.setAccessDecisionManager(manager); - return channelSecurityInterceptor; - } - - @Bean - public SecurityContextChannelInterceptor securityContextChannelInterceptor() { - return new SecurityContextChannelInterceptor(); - } - - @Bean - public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() { - this.inboundRegistry.expressionHandler(getMessageExpressionHandler()); - configureInbound(this.inboundRegistry); - return this.inboundRegistry.createMetadataSource(); - } - - /** - * @param messages - */ - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - } - - @Autowired - public void setApplicationContext(ApplicationContext context) { - this.context = context; - } - - @Deprecated - public void setMessageExpessionHandler(List>> expressionHandlers) { - setMessageExpressionHandler(expressionHandlers); - } - - @Autowired(required = false) - public void setMessageExpressionHandler(List>> expressionHandlers) { - if (expressionHandlers.size() == 1) { - this.expressionHandler = expressionHandlers.get(0); - } - } - - @Autowired(required = false) - public void setObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { - this.defaultExpressionHandler = objectPostProcessor.postProcess(this.defaultExpressionHandler); - } - - private SecurityExpressionHandler> getMessageExpressionHandler() { - if (this.expressionHandler == null) { - return this.defaultExpressionHandler; - } - return this.expressionHandler; - } - - @Override - public void afterSingletonsInstantiated() { - if (sameOriginDisabled()) { - return; - } - String beanName = "stompWebSocketHandlerMapping"; - SimpleUrlHandlerMapping mapping = this.context.getBean(beanName, SimpleUrlHandlerMapping.class); - Map mappings = mapping.getHandlerMap(); - for (Object object : mappings.values()) { - if (object instanceof SockJsHttpRequestHandler) { - setHandshakeInterceptors((SockJsHttpRequestHandler) object); - } - else if (object instanceof WebSocketHttpRequestHandler) { - setHandshakeInterceptors((WebSocketHttpRequestHandler) object); - } - else { - throw new IllegalStateException("Bean " + beanName + " is expected to contain mappings to either a " - + "SockJsHttpRequestHandler or a WebSocketHttpRequestHandler but got " + object); - } - } - if (this.inboundRegistry.containsMapping() && !this.inboundRegistry.isSimpDestPathMatcherConfigured()) { - PathMatcher pathMatcher = getDefaultPathMatcher(); - this.inboundRegistry.simpDestPathMatcher(pathMatcher); - } - } - - private void setHandshakeInterceptors(SockJsHttpRequestHandler handler) { - SockJsService sockJsService = handler.getSockJsService(); - Assert.state(sockJsService instanceof TransportHandlingSockJsService, - () -> "sockJsService must be instance of TransportHandlingSockJsService got " + sockJsService); - TransportHandlingSockJsService transportHandlingSockJsService = (TransportHandlingSockJsService) sockJsService; - List handshakeInterceptors = transportHandlingSockJsService.getHandshakeInterceptors(); - List interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1); - interceptorsToSet.add(new CsrfTokenHandshakeInterceptor()); - interceptorsToSet.addAll(handshakeInterceptors); - transportHandlingSockJsService.setHandshakeInterceptors(interceptorsToSet); - } - - private void setHandshakeInterceptors(WebSocketHttpRequestHandler handler) { - List handshakeInterceptors = handler.getHandshakeInterceptors(); - List interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1); - interceptorsToSet.add(new CsrfTokenHandshakeInterceptor()); - interceptorsToSet.addAll(handshakeInterceptors); - handler.setHandshakeInterceptors(interceptorsToSet); - } - - private static class WebSocketMessageSecurityMetadataSourceRegistry extends MessageSecurityMetadataSourceRegistry { - - @Override - public MessageSecurityMetadataSource createMetadataSource() { - return super.createMetadataSource(); - } - - @Override - protected boolean containsMapping() { - return super.containsMapping(); - } - - @Override - protected boolean isSimpDestPathMatcherConfigured() { - return super.isSimpDestPathMatcherConfigured(); - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerDocTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerDocTests.java deleted file mode 100644 index 6c3849d55ff..00000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerDocTests.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2002-2016 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.config.annotation.web.socket; - -import java.util.HashMap; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageDeliveryException; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.mock.web.MockServletConfig; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.web.csrf.CsrfToken; -import org.springframework.security.web.csrf.DefaultCsrfToken; -import org.springframework.stereotype.Controller; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; - -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -public class AbstractSecurityWebSocketMessageBrokerConfigurerDocTests { - - AnnotationConfigWebApplicationContext context; - - TestingAuthenticationToken messageUser; - - CsrfToken token; - - String sessionAttr; - - @BeforeEach - public void setup() { - this.token = new DefaultCsrfToken("header", "param", "token"); - this.sessionAttr = "sessionAttr"; - this.messageUser = new TestingAuthenticationToken("user", "pass", "ROLE_USER"); - } - - @AfterEach - public void cleanup() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void securityMappings() { - loadConfig(WebSocketSecurityConfig.class); - clientInboundChannel().send(message("/user/queue/errors", SimpMessageType.SUBSCRIBE)); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/denyAll", SimpMessageType.MESSAGE))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - private void loadConfig(Class... configs) { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.register(configs); - this.context.register(WebSocketConfig.class, SyncExecutorConfig.class); - this.context.setServletConfig(new MockServletConfig()); - this.context.refresh(); - } - - private MessageChannel clientInboundChannel() { - return this.context.getBean("clientInboundChannel", MessageChannel.class); - } - - private Message message(String destination, SimpMessageType type) { - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(type); - return message(headers, destination); - } - - private Message message(SimpMessageHeaderAccessor headers, String destination) { - headers.setSessionId("123"); - headers.setSessionAttributes(new HashMap<>()); - if (destination != null) { - headers.setDestination(destination); - } - if (this.messageUser != null) { - headers.setUser(this.messageUser); - } - return new GenericMessage<>("hi", headers.getMessageHeaders()); - } - - @Controller - static class MyController { - - @MessageMapping("/authentication") - void authentication(@AuthenticationPrincipal String un) { - // ... do something ... - } - - } - - @Configuration - static class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages.nullDestMatcher() - .authenticated() - // <1> - .simpSubscribeDestMatchers("/user/queue/errors") - .permitAll() - // <2> - .simpDestMatchers("/app/**") - .hasRole("USER") - // <3> - .simpSubscribeDestMatchers("/user/**", "/topic/friends/*") - .hasRole("USER") // <4> - .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE) - .denyAll() // <5> - .anyMessage() - .denyAll(); // <6> - } - - } - - @Configuration - @EnableWebSocketMessageBroker - static class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/chat").withSockJS(); - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - MyController myController() { - return new MyController(); - } - - } - - @Configuration - static class SyncExecutorConfig { - - @Bean - static SyncExecutorSubscribableChannelPostProcessor postProcessor() { - return new SyncExecutorSubscribableChannelPostProcessor(); - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java deleted file mode 100644 index 89af68e9da4..00000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright 2002-2023 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.config.annotation.web.socket; - -import java.util.HashMap; -import java.util.Map; - -import jakarta.servlet.http.HttpServletRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.MethodParameter; -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -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.config.MessageBrokerRegistry; -import org.springframework.messaging.support.AbstractMessageChannel; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.mock.web.MockServletConfig; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.access.expression.SecurityExpressionHandler; -import org.springframework.security.access.expression.SecurityExpressionOperations; -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler; -import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot; -import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor; -import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource; -import org.springframework.security.messaging.context.SecurityContextChannelInterceptor; -import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor; -import org.springframework.security.web.csrf.CsrfToken; -import org.springframework.security.web.csrf.DefaultCsrfToken; -import org.springframework.security.web.csrf.DeferredCsrfToken; -import org.springframework.security.web.csrf.MissingCsrfTokenException; -import org.springframework.stereotype.Controller; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.util.AntPathMatcher; -import org.springframework.web.HttpRequestHandler; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -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.sockjs.transport.handler.SockJsWebSocketHandler; -import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCsrfToken; - -public class AbstractSecurityWebSocketMessageBrokerConfigurerTests { - - AnnotationConfigWebApplicationContext context; - - TestingAuthenticationToken messageUser; - - CsrfToken token; - - String sessionAttr; - - @BeforeEach - public void setup() { - this.token = new DefaultCsrfToken("header", "param", "token"); - this.sessionAttr = "sessionAttr"; - this.messageUser = new TestingAuthenticationToken("user", "pass", "ROLE_USER"); - } - - @AfterEach - public void cleanup() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void simpleRegistryMappings() { - loadConfig(SockJsSecurityConfig.class); - clientInboundChannel().send(message("/permitAll")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/denyAll"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void annonymousSupported() { - loadConfig(SockJsSecurityConfig.class); - this.messageUser = null; - clientInboundChannel().send(message("/permitAll")); - } - - // gh-3797 - @Test - public void beanResolver() { - loadConfig(SockJsSecurityConfig.class); - this.messageUser = null; - clientInboundChannel().send(message("/beanResolver")); - } - - @Test - public void addsAuthenticationPrincipalResolver() { - loadConfig(SockJsSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - Message message = message("/permitAll/authentication"); - messageChannel.send(message); - assertThat(this.context.getBean(MyController.class).authenticationPrincipal) - .isEqualTo((String) this.messageUser.getPrincipal()); - } - - @Test - public void addsAuthenticationPrincipalResolverWhenNoAuthorization() { - loadConfig(NoInboundSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - Message message = message("/permitAll/authentication"); - messageChannel.send(message); - assertThat(this.context.getBean(MyController.class).authenticationPrincipal) - .isEqualTo((String) this.messageUser.getPrincipal()); - } - - @Test - public void addsCsrfProtectionWhenNoAuthorization() { - loadConfig(NoInboundSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MessageChannel messageChannel = clientInboundChannel(); - assertThatExceptionOfType(MessageDeliveryException.class).isThrownBy(() -> messageChannel.send(message)) - .withCauseInstanceOf(MissingCsrfTokenException.class); - } - - @Test - public void csrfProtectionForConnect() { - loadConfig(SockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MessageChannel messageChannel = clientInboundChannel(); - assertThatExceptionOfType(MessageDeliveryException.class).isThrownBy(() -> messageChannel.send(message)) - .withCauseInstanceOf(MissingCsrfTokenException.class); - } - - @Test - public void csrfProtectionDisabledForConnect() { - loadConfig(CsrfDisabledSockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/permitAll/connect"); - MessageChannel messageChannel = clientInboundChannel(); - messageChannel.send(message); - } - - @Test - public void csrfProtectionDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - CsrfChannelInterceptor csrfChannelInterceptor = this.context.getBean(CsrfChannelInterceptor.class); - assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()).contains(csrfChannelInterceptor); - } - - @Test - public void messagesConnectUseCsrfTokenHandshakeInterceptor() throws Exception { - loadConfig(SockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MockHttpServletRequest request = sockjsHttpRequest("/chat"); - HttpRequestHandler handler = handler(request); - handler.handleRequest(request, new MockHttpServletResponse()); - assertHandshake(request); - } - - @Test - public void messagesConnectUseCsrfTokenHandshakeInterceptorMultipleMappings() throws Exception { - loadConfig(SockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MockHttpServletRequest request = sockjsHttpRequest("/other"); - HttpRequestHandler handler = handler(request); - handler.handleRequest(request, new MockHttpServletResponse()); - assertHandshake(request); - } - - @Test - public void messagesConnectWebSocketUseCsrfTokenHandshakeInterceptor() throws Exception { - loadConfig(WebSocketSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MockHttpServletRequest request = websocketHttpRequest("/websocket"); - HttpRequestHandler handler = handler(request); - handler.handleRequest(request, new MockHttpServletResponse()); - assertHandshake(request); - } - - @Test - public void msmsRegistryCustomPatternMatcher() { - loadConfig(MsmsRegistryCustomPatternMatcherConfig.class); - clientInboundChannel().send(message("/app/a.b")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/app/a.b.c"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void overrideMsmsRegistryCustomPatternMatcher() { - loadConfig(OverrideMsmsRegistryCustomPatternMatcherConfig.class); - clientInboundChannel().send(message("/app/a/b")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/app/a/b/c"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void defaultPatternMatcher() { - loadConfig(DefaultPatternMatcherConfig.class); - clientInboundChannel().send(message("/app/a/b")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/app/a/b/c"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void customExpression() { - loadConfig(CustomExpressionConfig.class); - clientInboundChannel().send(message("/denyRob")); - this.messageUser = new TestingAuthenticationToken("rob", "password", "ROLE_USER"); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/denyRob"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void channelSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() { - loadConfig(SockJsProxylessSecurityConfig.class); - ChannelSecurityInterceptor channelSecurityInterceptor = this.context.getBean(ChannelSecurityInterceptor.class); - MessageSecurityMetadataSource messageSecurityMetadataSource = this.context - .getBean(MessageSecurityMetadataSource.class); - assertThat(channelSecurityInterceptor.obtainSecurityMetadataSource()).isSameAs(messageSecurityMetadataSource); - } - - @Test - public void securityContextChannelInterceptorDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - SecurityContextChannelInterceptor securityContextChannelInterceptor = this.context - .getBean(SecurityContextChannelInterceptor.class); - assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()) - .contains(securityContextChannelInterceptor); - } - - @Test - public void inboundChannelSecurityDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - ChannelSecurityInterceptor inboundChannelSecurity = this.context.getBean(ChannelSecurityInterceptor.class); - assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()).contains(inboundChannelSecurity); - } - - private void assertHandshake(HttpServletRequest request) { - TestHandshakeHandler handshakeHandler = this.context.getBean(TestHandshakeHandler.class); - assertThatCsrfToken(handshakeHandler.attributes.get(CsrfToken.class.getName())).isEqualTo(this.token); - assertThat(handshakeHandler.attributes).containsEntry(this.sessionAttr, - request.getSession().getAttribute(this.sessionAttr)); - } - - private HttpRequestHandler handler(HttpServletRequest request) throws Exception { - HandlerMapping handlerMapping = this.context.getBean(HandlerMapping.class); - return (HttpRequestHandler) handlerMapping.getHandler(request).getHandler(); - } - - private MockHttpServletRequest websocketHttpRequest(String mapping) { - MockHttpServletRequest request = sockjsHttpRequest(mapping); - request.setRequestURI(mapping); - return request; - } - - private MockHttpServletRequest sockjsHttpRequest(String mapping) { - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setMethod("GET"); - request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/289/tpyx6mde/websocket"); - request.setRequestURI(mapping + "/289/tpyx6mde/websocket"); - request.getSession().setAttribute(this.sessionAttr, "sessionValue"); - request.setAttribute(DeferredCsrfToken.class.getName(), new TestDeferredCsrfToken(this.token)); - return request; - } - - private Message message(String destination) { - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); - return message(headers, destination); - } - - private Message message(SimpMessageHeaderAccessor headers, String destination) { - headers.setSessionId("123"); - headers.setSessionAttributes(new HashMap<>()); - if (destination != null) { - headers.setDestination(destination); - } - if (this.messageUser != null) { - headers.setUser(this.messageUser); - } - return new GenericMessage<>("hi", headers.getMessageHeaders()); - } - - private MessageChannel clientInboundChannel() { - return this.context.getBean("clientInboundChannel", MessageChannel.class); - } - - private void loadConfig(Class... configs) { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.register(configs); - this.context.setServletConfig(new MockServletConfig()); - this.context.refresh(); - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class MsmsRegistryCustomPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/app/a.*").permitAll() - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.setPathMatcher(new AntPathMatcher(".")); - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class OverrideMsmsRegistryCustomPatternMatcherConfig - extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestPathMatcher(new AntPathMatcher()) - .simpDestMatchers("/app/a/*").permitAll() - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.setPathMatcher(new AntPathMatcher(".")); - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class DefaultPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/app/a/*").permitAll() - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class CustomExpressionConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .anyMessage().access("denyRob()"); - } - // @formatter:on - @Bean - static SecurityExpressionHandler> messageSecurityExpressionHandler() { - return new 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()); - } - }; - } - }; - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @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 - public boolean supportsParameter(MethodParameter parameter) { - return parameter.getParameterType().isAssignableFrom(MyCustomArgument.class); - } - - @Override - public Object resolveArgument(MethodParameter parameter, Message message) { - return new MyCustomArgument(""); - } - - } - - static class TestHandshakeHandler implements HandshakeHandler { - - Map attributes; - - @Override - public 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; - WebSocketServerSockJsSession session = (WebSocketServerSockJsSession) ReflectionTestUtils - .getField(sockJs, "sockJsSession"); - this.attributes = session.getAttributes(); - } - return true; - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class SockJsSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/other").setHandshakeHandler(testHandshakeHandler()) - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - registry.addEndpoint("/chat").setHandshakeHandler(testHandshakeHandler()) - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/permitAll/**").permitAll() - .simpDestMatchers("/beanResolver/**").access("@security.check()") - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - public MyController myController() { - return new MyController(); - } - - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - @Bean - public SecurityCheck security() { - return new SecurityCheck(); - } - - static class SecurityCheck { - - private boolean check; - - public boolean check() { - this.check = !this.check; - return this.check; - } - - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class NoInboundSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/other") - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - registry.addEndpoint("/chat") - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - public MyController myController() { - return new MyController(); - } - - } - - @Configuration - static class CsrfDisabledSockJsSecurityConfig extends SockJsSecurityConfig { - - @Override - protected boolean sameOriginDisabled() { - return true; - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/websocket") - .setHandshakeHandler(testHandshakeHandler()) - .addInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - // @formatter:off - messages - .simpDestMatchers("/permitAll/**").permitAll() - .simpDestMatchers("/customExpression/**").access("denyRob") - .anyMessage().denyAll(); - // @formatter:on - } - - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration(proxyBeanMethods = false) - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class SockJsProxylessSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - private ApplicationContext context; - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/chat") - .setHandshakeHandler(this.context.getBean(TestHandshakeHandler.class)) - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Autowired - public void setContext(ApplicationContext context) { - this.context = context; - } - - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .anyMessage().denyAll(); - } - // @formatter:on - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - static class SyncExecutorConfig { - - @Bean - public static SyncExecutorSubscribableChannelPostProcessor postProcessor() { - return new SyncExecutorSubscribableChannelPostProcessor(); - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java index cf2d0358069..7e7c4420805 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java @@ -69,7 +69,6 @@ import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; import org.springframework.security.config.observation.SecurityObservationSettings; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; @@ -878,37 +877,6 @@ TestHandshakeHandler testHandshakeHandler() { } - @Configuration - @EnableWebSocketSecurity - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class UsingLegacyConfigurerConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/websocket") - .setHandshakeHandler(testHandshakeHandler()) - .addInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Override - public void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - // @formatter:off - messages - .simpDestMatchers("/permitAll/**").permitAll() - .anyMessage().denyAll(); - // @formatter:on - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - @Configuration(proxyBeanMethods = false) @EnableWebSocketSecurity @EnableWebSocketMessageBroker diff --git a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc index 736e5b15f43..a4827bac7b1 100644 --- a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc +++ b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc @@ -492,43 +492,6 @@ Xml:: ---- ====== -On the other hand, if you are using the <> and you want to allow other domains to access your site, you can disable Spring Security's protection. -For example, in Java Configuration you can use the following: - -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - ... - - @Override - protected boolean sameOriginDisabled() { - return true; - } -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfigurer() { - - // ... - - override fun sameOriginDisabled(): Boolean { - return true - } -} ----- -====== - [[websocket-expression-handler]] === Custom Expression Handler @@ -742,50 +705,3 @@ If we use XML-based configuration, we can use thexref:servlet/appendix/namespace ---- - -[[legacy-websocket-configuration]] -== Legacy WebSocket Configuration - -Before Spring Security 5.8, the way to configure messaging authorization using Java Configuration, was to extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`. -For example: - -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -public class WebSocketSecurityConfig - extends AbstractSecurityWebSocketMessageBrokerConfigurer { // <1> <2> - - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/user/**").authenticated() // <3> - } -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfigurer() { // <1> <2> - override fun configureInbound(messages: MessageSecurityMetadataSourceRegistry) { - messages.simpDestMatchers("/user/**").authenticated() // <3> - } -} ----- -====== - -This will ensure that: - -<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> -<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. -<3> Our messages require the proper authorization. Specifically, any inbound message that starts with "/user/" will require ROLE_USER. Additional details on authorization can be found in <> - -Using the legacy configuration is helpful in the event that you have a custom `SecurityExpressionHandler` that extends `AbstractSecurityExpressionHandler` and overrides `createEvaluationContextInternal` or `createSecurityExpressionRoot`. -In order to defer `Authorization` lookup, the new `AuthorizationManager` API does not invoke these when evaluating expressions. - -If you are using XML, you can use the legacy APIs simply by not using the `use-authorization-manager` element or setting it to `false`. diff --git a/etc/checkstyle/checkstyle-suppressions.xml b/etc/checkstyle/checkstyle-suppressions.xml index c1c5baf08a3..6bc4e305925 100644 --- a/etc/checkstyle/checkstyle-suppressions.xml +++ b/etc/checkstyle/checkstyle-suppressions.xml @@ -17,7 +17,6 @@ -