diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java index 2068874408..aa95ed89a5 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2020 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. @@ -75,8 +75,8 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented -@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, SpringWebSocketImportSelector.class, - OAuth2ImportSelector.class, HttpSecurityConfiguration.class }) +@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, + HttpSecurityConfiguration.class }) @EnableGlobalAuthentication @Configuration public @interface EnableWebSecurity { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/SpringWebSocketImportSelector.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/SpringWebSocketImportSelector.java deleted file mode 100644 index 2d7ad6abd8..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/SpringWebSocketImportSelector.java +++ /dev/null @@ -1,43 +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.configuration; - -import org.springframework.context.annotation.ImportSelector; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.util.ClassUtils; - -/** - * Used by {@link EnableWebSecurity} to conditionally import - * {@link org.springframework.security.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfiguration} - * when the AbstractWebSocketHandler is present on the classpath. - * - * @author Josh Cummings - * @since 5.7 - */ -class SpringWebSocketImportSelector implements ImportSelector { - - @Override - public String[] selectImports(AnnotationMetadata importingClassMetadata) { - if (!ClassUtils.isPresent("org.springframework.web.socket.handler.AbstractWebSocketHandler", - getClass().getClassLoader())) { - return new String[0]; - } - return new String[] { - "org.springframework.security.config.annotation.web.socket.WebSocketMessageBrokerSecurityConfiguration" }; - } - -} diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/messaging/AuthorizationManagerMessageMatcherRegistry.java b/config/src/main/java/org/springframework/security/config/annotation/web/messaging/AuthorizationManagerMessageMatcherRegistry.java deleted file mode 100644 index b291552258..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/messaging/AuthorizationManagerMessageMatcherRegistry.java +++ /dev/null @@ -1,354 +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.messaging; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -import org.springframework.context.ApplicationContext; -import org.springframework.messaging.Message; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler; -import org.springframework.security.authorization.AuthenticatedAuthorizationManager; -import org.springframework.security.authorization.AuthorityAuthorizationManager; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationManager; -import org.springframework.security.messaging.access.intercept.MessageAuthorizationContext; -import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager; -import org.springframework.security.messaging.util.matcher.MessageMatcher; -import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher; -import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.Assert; -import org.springframework.util.PathMatcher; - -/** - * Allows mapping security constraints using {@link MessageMatcher} to authorization - * managers. - * - * @author Josh Cummings - * @since 5.7 - */ -public final class AuthorizationManagerMessageMatcherRegistry { - - private final MessageMatcherDelegatingAuthorizationManager.Builder builder = MessageMatcherDelegatingAuthorizationManager - .builder(); - - private final ApplicationContext context; - - private PathMatcher pathMatcher; - - public AuthorizationManagerMessageMatcherRegistry(ApplicationContext context) { - this.context = context; - } - - /** - * Maps any {@link Message} to a security expression. - * @return the Expression to associate - */ - public AuthorizationManagerMessageMatcherRegistry.Constraint anyMessage() { - return matchers(MessageMatcher.ANY_MESSAGE); - } - - /** - * Maps any {@link Message} that has a null SimpMessageHeaderAccessor destination - * header (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, UNSUBSCRIBE, DISCONNECT, - * DISCONNECT_ACK, OTHER) - * @return the Expression to associate - */ - public AuthorizationManagerMessageMatcherRegistry.Constraint nullDestMatcher() { - return matchers(SimpDestinationMessageMatcher.NULL_DESTINATION_MATCHER); - } - - /** - * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances. - * @param typesToMatch the {@link SimpMessageType} instance to match on - * @return the {@link Constraint} associated to the matchers. - */ - public AuthorizationManagerMessageMatcherRegistry.Constraint simpTypeMatchers(SimpMessageType... typesToMatch) { - MessageMatcher[] typeMatchers = new MessageMatcher[typesToMatch.length]; - for (int i = 0; i < typesToMatch.length; i++) { - SimpMessageType typeToMatch = typesToMatch[i]; - typeMatchers[i] = new SimpMessageTypeMatcher(typeToMatch); - } - return matchers(typeMatchers); - } - - /** - * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances without - * regard to the {@link SimpMessageType}. If no destination is found on the Message, - * then the Matcher returns false. - * @param patterns the patterns to create - * {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher} - * from. - */ - public Constraint simpDestMatchers(String... patterns) { - return simpDestMatchers(null, patterns); - } - - /** - * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that match - * on {@code SimpMessageType.MESSAGE}. If no destination is found on the Message, then - * the Matcher returns false. - * @param patterns the patterns to create - * {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher} - * from. - */ - public Constraint simpMessageDestMatchers(String... patterns) { - return simpDestMatchers(SimpMessageType.MESSAGE, patterns); - } - - /** - * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances that match - * on {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the Message, - * then the Matcher returns false. - * @param patterns the patterns to create - * {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher} - * from. - */ - public Constraint simpSubscribeDestMatchers(String... patterns) { - return simpDestMatchers(SimpMessageType.SUBSCRIBE, patterns); - } - - /** - * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances. If no - * destination is found on the Message, then the Matcher returns false. - * @param type the {@link SimpMessageType} to match on. If null, the - * {@link SimpMessageType} is not considered for matching. - * @param patterns the patterns to create - * {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher} - * from. - * @return the {@link Constraint} that is associated to the {@link MessageMatcher} - */ - private Constraint simpDestMatchers(SimpMessageType type, String... patterns) { - List> matchers = new ArrayList<>(patterns.length); - for (String pattern : patterns) { - Supplier> supplier = new PathMatcherMessageMatcherBuilder(pattern, type); - MessageMatcher matcher = new SupplierMessageMatcher(supplier); - matchers.add(matcher); - } - return new Constraint(matchers); - } - - /** - * The {@link PathMatcher} to be used with the - * {@link MessageSecurityMetadataSourceRegistry#simpDestMatchers(String...)}. The - * default is to use the default constructor of {@link AntPathMatcher}. - * @param pathMatcher the {@link PathMatcher} to use. Cannot be null. - * @return the {@link MessageSecurityMetadataSourceRegistry} for further - * customization. - */ - public AuthorizationManagerMessageMatcherRegistry simpDestPathMatcher(PathMatcher pathMatcher) { - Assert.notNull(pathMatcher, "pathMatcher cannot be null"); - this.pathMatcher = pathMatcher; - return this; - } - - /** - * Maps a {@link List} of {@link MessageMatcher} instances to a security expression. - * @param matchers the {@link MessageMatcher} instances to map. - * @return The {@link Constraint} that is associated to the {@link MessageMatcher} - * instances - */ - public Constraint matchers(MessageMatcher... matchers) { - List> builders = new ArrayList<>(matchers.length); - for (MessageMatcher matcher : matchers) { - builders.add(matcher); - } - return new Constraint(builders); - } - - public AuthorizationManager> build() { - return this.builder.build(); - } - - /** - * Represents the security constraint to be applied to the {@link MessageMatcher} - * instances. - */ - public final class Constraint { - - private final List> messageMatchers; - - /** - * Creates a new instance - * @param messageMatchers the {@link MessageMatcher} instances to map to this - * constraint - */ - private Constraint(List> messageMatchers) { - Assert.notEmpty(messageMatchers, "messageMatchers cannot be null or empty"); - this.messageMatchers = messageMatchers; - } - - /** - * Shortcut for specifying {@link Message} instances require a particular role. If - * you do not want to have "ROLE_" automatically inserted see - * {@link #hasAuthority(String)}. - * @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not - * start with "ROLE_" as this is automatically inserted. - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry hasRole(String role) { - return access(AuthorityAuthorizationManager.hasRole(role)); - } - - /** - * Shortcut for specifying {@link Message} instances require any of a number of - * roles. If you do not want to have "ROLE_" automatically inserted see - * {@link #hasAnyAuthority(String...)} - * @param roles the roles to require (i.e. USER, ADMIN, etc). Note, it should not - * start with "ROLE_" as this is automatically inserted. - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry hasAnyRole(String... roles) { - return access(AuthorityAuthorizationManager.hasAnyRole(roles)); - } - - /** - * Specify that {@link Message} instances require a particular authority. - * @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc). - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry hasAuthority(String authority) { - return access(AuthorityAuthorizationManager.hasAuthority(authority)); - } - - /** - * Specify that {@link Message} instances requires any of a number authorities. - * @param authorities the requests require at least one of the authorities (i.e. - * "ROLE_USER","ROLE_ADMIN" would mean either "ROLE_USER" or "ROLE_ADMIN" is - * required). - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry hasAnyAuthority(String... authorities) { - return access(AuthorityAuthorizationManager.hasAnyAuthority(authorities)); - } - - /** - * Specify that Messages are allowed by anyone. - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry permitAll() { - return access((authentication, context) -> new AuthorizationDecision(true)); - } - - /** - * Specify that Messages are not allowed by anyone. - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry denyAll() { - return access((authorization, context) -> new AuthorizationDecision(false)); - } - - /** - * Specify that Messages are allowed by any authenticated user. - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry authenticated() { - return access(AuthenticatedAuthorizationManager.authenticated()); - } - - /** - * Allows specifying that Messages are secured by an arbitrary expression - * @param authorizationManager the {@link AuthorizationManager} to secure the - * destinations - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customization - */ - public AuthorizationManagerMessageMatcherRegistry access( - AuthorizationManager> authorizationManager) { - for (MessageMatcher messageMatcher : this.messageMatchers) { - AuthorizationManagerMessageMatcherRegistry.this.builder.add(messageMatcher, authorizationManager); - } - return AuthorizationManagerMessageMatcherRegistry.this; - } - - } - - private static final class SupplierMessageMatcher implements MessageMatcher { - - private final Supplier> supplier; - - private volatile MessageMatcher delegate; - - SupplierMessageMatcher(Supplier> supplier) { - this.supplier = supplier; - } - - @Override - public boolean matches(Message message) { - if (this.delegate == null) { - synchronized (this.supplier) { - if (this.delegate == null) { - this.delegate = this.supplier.get(); - } - } - } - return this.delegate.matches(message); - } - - } - - private final class PathMatcherMessageMatcherBuilder implements Supplier> { - - private final String pattern; - - private final SimpMessageType type; - - private PathMatcherMessageMatcherBuilder(String pattern, SimpMessageType type) { - this.pattern = pattern; - this.type = type; - } - - private PathMatcher resolvePathMatcher() { - if (AuthorizationManagerMessageMatcherRegistry.this.pathMatcher != null) { - return AuthorizationManagerMessageMatcherRegistry.this.pathMatcher; - } - if (AuthorizationManagerMessageMatcherRegistry.this.context - .getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0) { - return AuthorizationManagerMessageMatcherRegistry.this.context - .getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher(); - } - return new AntPathMatcher(); - } - - @Override - public MessageMatcher get() { - PathMatcher pathMatcher = resolvePathMatcher(); - if (this.type == null) { - return new SimpDestinationMessageMatcher(this.pattern, pathMatcher); - } - if (SimpMessageType.MESSAGE == this.type) { - return SimpDestinationMessageMatcher.createMessageMatcher(this.pattern, pathMatcher); - } - if (SimpMessageType.SUBSCRIBE == this.type) { - return SimpDestinationMessageMatcher.createSubscribeMatcher(this.pattern, pathMatcher); - } - throw new IllegalStateException(this.type + " is not supported since it does not have a destination"); - } - - } - -} diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java b/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java index 74bd6c812c..eee7e34f36 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * 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. @@ -43,9 +43,7 @@ import org.springframework.util.StringUtils; * * @author Rob Winch * @since 4.0 - * @deprecated Use {@link AuthorizationManagerMessageMatcherRegistry} instead */ -@Deprecated public class MessageSecurityMetadataSourceRegistry { private static final String permitAll = "permitAll"; 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 index 759c446117..60139cd59a 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2019 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. @@ -81,15 +81,9 @@ import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsSe * * @author Rob Winch * @since 4.0 - * @see WebSocketMessageBrokerSecurityConfiguration - * @deprecated Use - * {@link org.springframework.security.config.annotation.web.configuration.EnableWebSecurity} - * and see {@link WebSocketMessageBrokerSecurityConfiguration} for additional usage - * information instead */ @Order(Ordered.HIGHEST_PRECEDENCE + 100) @Import(ObjectPostProcessorConfiguration.class) -@Deprecated public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer implements SmartInitializingSingleton { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java deleted file mode 100644 index 37cd48d3c8..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java +++ /dev/null @@ -1,34 +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 org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; -import org.springframework.security.config.annotation.web.messaging.AuthorizationManagerMessageMatcherRegistry; - -@Configuration(proxyBeanMethods = false) -final class MessageMatcherAuthorizationManagerConfiguration { - - @Bean - @Scope("prototype") - AuthorizationManagerMessageMatcherRegistry authorizationManagerMessageMatcherRegistry(ApplicationContext context) { - return new AuthorizationManagerMessageMatcherRegistry(context); - } - -} diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfiguration.java deleted file mode 100644 index d8ded1edb2..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfiguration.java +++ /dev/null @@ -1,211 +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.Arrays; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -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.config.ChannelRegistration; -import org.springframework.messaging.support.ChannelInterceptor; -import org.springframework.security.authorization.AuthenticatedAuthorizationManager; -import org.springframework.security.authorization.AuthorizationManager; -import org.springframework.security.authorization.SpringAuthorizationEventPublisher; -import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor; -import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager; -import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver; -import org.springframework.security.messaging.context.SecurityContextChannelInterceptor; -import org.springframework.security.messaging.util.matcher.MessageMatcher; -import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor; -import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor; -import org.springframework.util.Assert; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -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
- * @EnableWebSecurity
- * public class WebSocketSecurityConfig {
- *
- * 	@Bean
- * 	AuthorizationManager<Message<?>> (AuthorizationManagerMessageMatcherRegistry messages) {
- * 		messages.simpDestMatchers("/user/queue/errors").permitAll()
- * 				.simpDestMatchers("/admin/**").hasRole("ADMIN").anyMessage()
- * 				.authenticated();
- *
- *		return messages.build();
- * 	}
- * }
- * 
- * - * @author Josh Cummings - * @since 5.7 - */ -@Order(Ordered.HIGHEST_PRECEDENCE + 100) -@Import(MessageMatcherAuthorizationManagerConfiguration.class) -final class WebSocketMessageBrokerSecurityConfiguration - implements WebSocketMessageBrokerConfigurer, SmartInitializingSingleton { - - private static final String SIMPLE_URL_HANDLER_MAPPING_BEAN_NAME = "stompWebSocketHandlerMapping"; - - private static final AuthorizationManager> ANY_MESSAGE_AUTHENTICATED = MessageMatcherDelegatingAuthorizationManager - .builder().add(MessageMatcher.ANY_MESSAGE, AuthenticatedAuthorizationManager.authenticated()).build(); - - private ChannelInterceptor securityContextChannelInterceptor = new SecurityContextChannelInterceptor(); - - private ChannelInterceptor csrfChannelInterceptor = new CsrfChannelInterceptor(); - - private AuthorizationChannelInterceptor authorizationChannelInterceptor = new AuthorizationChannelInterceptor( - ANY_MESSAGE_AUTHENTICATED); - - private Consumer> interceptorsCustomizer = (interceptors) -> { - }; - - private ApplicationContext context; - - private AbstractSecurityWebSocketMessageBrokerConfigurer configurer; - - WebSocketMessageBrokerSecurityConfiguration(ApplicationContext context) { - this.context = context; - } - - @Override - public void addArgumentResolvers(List argumentResolvers) { - if (this.configurer != null) { - return; - } - argumentResolvers.add(new AuthenticationPrincipalArgumentResolver()); - } - - @Override - public void configureClientInboundChannel(ChannelRegistration registration) { - if (this.configurer != null) { - return; - } - this.authorizationChannelInterceptor - .setAuthorizationEventPublisher(new SpringAuthorizationEventPublisher(this.context)); - List interceptors = new ArrayList<>(Arrays.asList(this.securityContextChannelInterceptor, - this.csrfChannelInterceptor, this.authorizationChannelInterceptor)); - this.interceptorsCustomizer.accept(interceptors); - registration.interceptors(interceptors.toArray(new ChannelInterceptor[0])); - } - - @Autowired(required = false) - void setSecurityContextChannelInterceptor(SecurityContextChannelInterceptor interceptor) { - this.securityContextChannelInterceptor = interceptor; - } - - @Autowired(required = false) - void setCsrfChannelInterceptor(CsrfChannelInterceptor csrfChannelInterceptor) { - this.csrfChannelInterceptor = csrfChannelInterceptor; - } - - @Autowired(required = false) - void setAuthorizationManager(AuthorizationManager> authorizationManager) { - this.authorizationChannelInterceptor = new AuthorizationChannelInterceptor(authorizationManager); - } - - @Autowired(required = false) - void setInterceptorsCustomizer(Consumer> interceptorsCustomizer) { - this.interceptorsCustomizer = interceptorsCustomizer; - } - - @Autowired(required = false) - @Deprecated - void setAbstractSecurityWebSocketMessageBrokerConfigurer( - AbstractSecurityWebSocketMessageBrokerConfigurer configurer) { - this.configurer = configurer; - } - - @Override - public void afterSingletonsInstantiated() { - if (this.configurer != null) { - return; - } - SimpleUrlHandlerMapping mapping = getBeanOrNull(SIMPLE_URL_HANDLER_MAPPING_BEAN_NAME, - SimpleUrlHandlerMapping.class); - if (mapping == null) { - return; - } - configureCsrf(mapping); - } - - private T getBeanOrNull(String name, Class type) { - Map beans = this.context.getBeansOfType(type); - return beans.get(name); - } - - private void configureCsrf(SimpleUrlHandlerMapping mapping) { - 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 " + SIMPLE_URL_HANDLER_MAPPING_BEAN_NAME + " is expected to contain mappings to either a " - + "SockJsHttpRequestHandler or a WebSocketHttpRequestHandler but got " + object); - } - } - } - - 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); - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationDocTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationDocTests.java deleted file mode 100644 index 73135841c4..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationDocTests.java +++ /dev/null @@ -1,176 +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.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.authorization.AuthorizationManager; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.messaging.AuthorizationManagerMessageMatcherRegistry; -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 WebSocketMessageBrokerSecurityConfigurationDocTests { - - 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 - @EnableWebSecurity - static class WebSocketSecurityConfig { - - @Bean - AuthorizationManager> authorizationManager(AuthorizationManagerMessageMatcherRegistry 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> - return messages.build(); - } - - } - - @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/WebSocketMessageBrokerSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java deleted file mode 100644 index d308ced90d..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java +++ /dev/null @@ -1,796 +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.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.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.ChannelInterceptor; -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.authentication.TestingAuthenticationToken; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationManager; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.messaging.AuthorizationManagerMessageMatcherRegistry; -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.intercept.AuthorizationChannelInterceptor; -import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor; -import org.springframework.security.messaging.access.intercept.MessageAuthorizationContext; -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.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.config.annotation.WebSocketMessageBrokerConfigurer; -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.assertj.core.api.Assertions.fail; - -public class WebSocketMessageBrokerSecurityConfigurationTests { - - 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(); - Stream> interceptors = ((AbstractMessageChannel) messageChannel) - .getInterceptors().stream().map(ChannelInterceptor::getClass); - assertThat(interceptors).contains(CsrfChannelInterceptor.class); - } - - @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); - AbstractMessageChannel messageChannel = clientInboundChannel(); - AuthorizationManager> authorizationManager = this.context.getBean(AuthorizationManager.class); - for (ChannelInterceptor interceptor : messageChannel.getInterceptors()) { - if (interceptor instanceof AuthorizationChannelInterceptor) { - assertThat(ReflectionTestUtils.getField(interceptor, "preSendAuthorizationManager")) - .isSameAs(authorizationManager); - return; - } - } - fail("did not find AuthorizationChannelInterceptor"); - } - - @Test - public void securityContextChannelInterceptorDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - Stream> interceptors = ((AbstractMessageChannel) messageChannel) - .getInterceptors().stream().map(ChannelInterceptor::getClass); - assertThat(interceptors).contains(SecurityContextChannelInterceptor.class); - } - - @Test - public void inboundChannelSecurityDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - Stream> interceptors = ((AbstractMessageChannel) messageChannel) - .getInterceptors().stream().map(ChannelInterceptor::getClass); - assertThat(interceptors).contains(AuthorizationChannelInterceptor.class); - } - - @Test - public void usingLegacyThenNewFiltersNotUsed() { - loadConfig(UsingLegacyConfigurerConfig.class); - AbstractMessageChannel messageChannel = clientInboundChannel(); - List> interceptors = messageChannel.getInterceptors().stream() - .map(ChannelInterceptor::getClass).collect(Collectors.toList()); - assertThat(interceptors).contains(ChannelSecurityInterceptor.class); - assertThat(interceptors).doesNotContain(AuthorizationChannelInterceptor.class); - } - - private void assertHandshake(HttpServletRequest request) { - TestHandshakeHandler handshakeHandler = this.context.getBean(TestHandshakeHandler.class); - assertThat(handshakeHandler.attributes.get(CsrfToken.class.getName())).isSameAs(this.token); - assertThat(handshakeHandler.attributes.get(this.sessionAttr)) - .isEqualTo(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(CsrfToken.class.getName(), 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 T clientInboundChannel() { - return (T) 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 - @EnableWebSecurity - @Import(SyncExecutorConfig.class) - static class MsmsRegistryCustomPatternMatcherConfig implements WebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.setPathMatcher(new AntPathMatcher(".")); - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - // @formatter:off - @Bean - AuthorizationManager> authorizationManager(AuthorizationManagerMessageMatcherRegistry messages) { - messages - .simpDestMatchers("/app/a.*").permitAll() - .anyMessage().denyAll(); - - return messages.build(); - } - // @formatter:on - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @EnableWebSecurity - @Import(SyncExecutorConfig.class) - static class OverrideMsmsRegistryCustomPatternMatcherConfig implements WebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.setPathMatcher(new AntPathMatcher(".")); - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - // @formatter:off - @Bean - AuthorizationManager> authorizationManager(AuthorizationManagerMessageMatcherRegistry messages) { - messages - .simpDestPathMatcher(new AntPathMatcher()) - .simpDestMatchers("/app/a/*").permitAll() - .anyMessage().denyAll(); - return messages.build(); - } - // @formatter:on - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @EnableWebSecurity - @Import(SyncExecutorConfig.class) - static class DefaultPatternMatcherConfig implements WebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - // @formatter:off - @Bean - AuthorizationManager> authorizationManager(AuthorizationManagerMessageMatcherRegistry messages) { - messages - .simpDestMatchers("/app/a/*").permitAll() - .anyMessage().denyAll(); - - return messages.build(); - } - // @formatter:on - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @EnableWebSecurity - @Import(SyncExecutorConfig.class) - static class CustomExpressionConfig implements WebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - AuthorizationManager> authorizationManager() { - return (authentication, message) -> { - Authentication auth = authentication.get(); - return new AuthorizationDecision(auth != null && !"rob".equals(auth.getName())); - }; - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Controller - static class MyController { - - String authenticationPrincipal; - - MyCustomArgument myCustomArgument; - - @MessageMapping("/authentication") - void authentication(@AuthenticationPrincipal String un) { - this.authenticationPrincipal = un; - } - - @MessageMapping("/myCustom") - 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 - @EnableWebSecurity - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class SockJsSecurityConfig implements WebSocketMessageBrokerConfigurer { - - @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 - @Bean - AuthorizationManager> authorizationManager(AuthorizationManagerMessageMatcherRegistry messages, - SecurityCheck security) { - AuthorizationManager> beanResolver = - (authentication, context) -> new AuthorizationDecision(security.check()); - messages - .simpDestMatchers("/permitAll/**").permitAll() - .simpDestMatchers("/beanResolver/**").access(beanResolver) - .anyMessage().denyAll(); - return messages.build(); - } - // @formatter:on - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - MyController myController() { - return new MyController(); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - @Bean - SecurityCheck security() { - return new SecurityCheck(); - } - - static class SecurityCheck { - - private boolean check; - - boolean check() { - this.check = !this.check; - return this.check; - } - - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class NoInboundSecurityConfig implements WebSocketMessageBrokerConfigurer { - - @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 - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - MyController myController() { - return new MyController(); - } - - } - - @Configuration - @Import(SockJsSecurityConfig.class) - static class CsrfDisabledSockJsSecurityConfig { - - @Bean - Consumer> channelInterceptorCustomizer() { - return (interceptors) -> interceptors.remove(1); - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class WebSocketSecurityConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/websocket") - .setHandshakeHandler(testHandshakeHandler()) - .addInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Bean - AuthorizationManager> authorizationManager(AuthorizationManagerMessageMatcherRegistry messages) { - // @formatter:off - messages - .simpDestMatchers("/permitAll/**").permitAll() - .anyMessage().denyAll(); - // @formatter:on - return messages.build(); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSecurity - @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) - @EnableWebSecurity - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class SockJsProxylessSecurityConfig implements WebSocketMessageBrokerConfigurer { - - 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 - void setContext(ApplicationContext context) { - this.context = context; - } - - // @formatter:off - @Bean - AuthorizationManager> authorizationManager(AuthorizationManagerMessageMatcherRegistry messages) { - messages - .anyMessage().denyAll(); - return messages.build(); - } - // @formatter:on - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - static class SyncExecutorConfig { - - @Bean - static SyncExecutorSubscribableChannelPostProcessor postProcessor() { - return new SyncExecutorSubscribableChannelPostProcessor(); - } - - } - -} diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/expression/EvaluationContextPostProcessor.java b/messaging/src/main/java/org/springframework/security/messaging/access/expression/EvaluationContextPostProcessor.java index baedbf632d..ef7a10f438 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/expression/EvaluationContextPostProcessor.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/expression/EvaluationContextPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2019 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. @@ -27,10 +27,7 @@ import org.springframework.expression.EvaluationContext; * * @author Daniel Bustamante Ospina * @since 5.2 - * @deprecated Since {@link MessageExpressionVoter} is deprecated, there is no more need - * for this class */ -@Deprecated interface EvaluationContextPostProcessor { /** diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/expression/ExpressionBasedMessageSecurityMetadataSourceFactory.java b/messaging/src/main/java/org/springframework/security/messaging/access/expression/ExpressionBasedMessageSecurityMetadataSourceFactory.java index 33e3a52df3..a819ce4cd3 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/expression/ExpressionBasedMessageSecurityMetadataSourceFactory.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/expression/ExpressionBasedMessageSecurityMetadataSourceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2019 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. @@ -35,11 +35,7 @@ import org.springframework.security.messaging.util.matcher.MessageMatcher; * * @author Rob Winch * @since 4.0 - * @deprecated Use - * {@link org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager} - * instead */ -@Deprecated public final class ExpressionBasedMessageSecurityMetadataSourceFactory { private ExpressionBasedMessageSecurityMetadataSourceFactory() { diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttribute.java b/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttribute.java index 6e2cbbb7c1..ffa96a22aa 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttribute.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2019 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. @@ -32,11 +32,7 @@ import org.springframework.util.Assert; * @author Rob Winch * @author Daniel Bustamante Ospina * @since 4.0 - * @deprecated Use - * {@link org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager} - * instead */ -@Deprecated @SuppressWarnings("serial") class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor> { diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionVoter.java b/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionVoter.java index 2fc1b1c835..b097df8c1e 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionVoter.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionVoter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2019 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. @@ -37,11 +37,7 @@ import org.springframework.util.Assert; * @author Rob Winch * @author Daniel Bustamante Ospina * @since 4.0 - * @deprecated Use - * {@link org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager} - * instead */ -@Deprecated public class MessageExpressionVoter implements AccessDecisionVoter> { private SecurityExpressionHandler> expressionHandler = new DefaultMessageSecurityExpressionHandler<>(); diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java deleted file mode 100644 index c0b12847e6..0000000000 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java +++ /dev/null @@ -1,95 +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.messaging.access.intercept; - -import java.util.function.Supplier; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.log.LogMessage; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.support.ChannelInterceptor; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationEventPublisher; -import org.springframework.security.authorization.AuthorizationManager; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.util.Assert; - -/** - * Authorizes {@link Message} resources using the provided {@link AuthorizationManager} - * - * @author Josh Cummings - * @since 5.7 - */ -public final class AuthorizationChannelInterceptor implements ChannelInterceptor { - - static final Supplier AUTHENTICATION_SUPPLIER = () -> { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null) { - throw new AuthenticationCredentialsNotFoundException( - "An Authentication object was not found in the SecurityContext"); - } - return authentication; - }; - - private final Log logger = LogFactory.getLog(this.getClass()); - - private final AuthorizationManager> preSendAuthorizationManager; - - private AuthorizationEventPublisher eventPublisher; - - /** - * Creates a new instance - * @param preSendAuthorizationManager the {@link AuthorizationManager} to use. Cannot - * be null. - * - */ - public AuthorizationChannelInterceptor(AuthorizationManager> preSendAuthorizationManager) { - Assert.notNull(preSendAuthorizationManager, "preSendAuthorizationManager cannot be null"); - this.preSendAuthorizationManager = preSendAuthorizationManager; - } - - @Override - public Message preSend(Message message, MessageChannel channel) { - this.logger.debug(LogMessage.of(() -> "Authorizing message send")); - AuthorizationDecision decision = this.preSendAuthorizationManager.check(AUTHENTICATION_SUPPLIER, message); - this.eventPublisher.publishAuthorizationEvent(AUTHENTICATION_SUPPLIER, message, decision); - if (decision == null || !decision.isGranted()) { // default deny - this.logger.debug(LogMessage.of(() -> "Failed to authorize message with authorization manager " - + this.preSendAuthorizationManager + " and decision " + decision)); - throw new AccessDeniedException("Access Denied"); - } - this.logger.debug(LogMessage.of(() -> "Authorized message send")); - return message; - } - - /** - * Use this {@link AuthorizationEventPublisher} to publish the - * {@link AuthorizationManager} result. - * @param eventPublisher - */ - public void setAuthorizationEventPublisher(AuthorizationEventPublisher eventPublisher) { - Assert.notNull(eventPublisher, "eventPublisher cannot be null"); - this.eventPublisher = eventPublisher; - } - -} diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/ChannelSecurityInterceptor.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/ChannelSecurityInterceptor.java index a0e2f370ab..9fe9f7117f 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/ChannelSecurityInterceptor.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/ChannelSecurityInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * 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. @@ -36,9 +36,7 @@ import org.springframework.util.Assert; * * @author Rob Winch * @since 4.0 - * @deprecated Use {@link AuthorizationChannelInterceptor} instead */ -@Deprecated public final class ChannelSecurityInterceptor extends AbstractSecurityInterceptor implements ChannelInterceptor { private static final ThreadLocal tokenHolder = new ThreadLocal<>(); diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/DefaultMessageSecurityMetadataSource.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/DefaultMessageSecurityMetadataSource.java index ff896789af..6e3eb8ba41 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/DefaultMessageSecurityMetadataSource.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/DefaultMessageSecurityMetadataSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * 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. @@ -40,9 +40,7 @@ import org.springframework.security.messaging.util.matcher.MessageMatcher; * @since 4.0 * @see ChannelSecurityInterceptor * @see ExpressionBasedMessageSecurityMetadataSourceFactory - * @deprecated Use {@link MessageMatcherDelegatingAuthorizationManager} instead */ -@Deprecated public final class DefaultMessageSecurityMetadataSource implements MessageSecurityMetadataSource { private final Map, Collection> messageMap; diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageAuthorizationContext.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageAuthorizationContext.java deleted file mode 100644 index 43c750d2d5..0000000000 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageAuthorizationContext.java +++ /dev/null @@ -1,75 +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.messaging.access.intercept; - -import java.util.Collections; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.messaging.Message; - -/** - * An {@link Message} authorization context. - * - * @author Josh Cummings - * @since 5.7 - */ -public final class MessageAuthorizationContext { - - private final Message message; - - private final Map variables; - - /** - * Creates an instance. - * @param message the {@link HttpServletRequest} to use - */ - public MessageAuthorizationContext(Message message) { - this(message, Collections.emptyMap()); - } - - /** - * Creates an instance. - * @param message the {@link HttpServletRequest} to use - * @param variables a map containing key-value pairs representing extracted variable - * names and variable values - */ - public MessageAuthorizationContext(Message message, Map variables) { - this.message = message; - this.variables = variables; - } - - /** - * Returns the {@link HttpServletRequest}. - * @return the {@link HttpServletRequest} to use - */ - public Message getMessage() { - return this.message; - } - - /** - * Returns the extracted variable values where the key is the variable name and the - * value is the variable value. - * @return a map containing key-value pairs representing extracted variable names and - * variable values - */ - public Map getVariables() { - return this.variables; - } - -} diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java deleted file mode 100644 index b855e36ed0..0000000000 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java +++ /dev/null @@ -1,136 +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.messaging.access.intercept; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.log.LogMessage; -import org.springframework.messaging.Message; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationManager; -import org.springframework.security.core.Authentication; -import org.springframework.security.messaging.util.matcher.MessageMatcher; -import org.springframework.security.messaging.util.matcher.MessageMatcherEntry; -import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher; -import org.springframework.util.Assert; - -/** - * An {@link AuthorizationManager} which delegates to a specific - * {@link AuthorizationManager} based on a {@link MessageMatcher} evaluation. - * - * @author Josh Cummings - * @since 5.7 - */ -public final class MessageMatcherDelegatingAuthorizationManager implements AuthorizationManager> { - - private final Log logger = LogFactory.getLog(getClass()); - - private final List>>> mappings; - - private MessageMatcherDelegatingAuthorizationManager( - List>>> mappings) { - Assert.notEmpty(mappings, "mappings cannot be empty"); - this.mappings = mappings; - } - - /** - * Delegates to a specific {@link AuthorizationManager} based on a - * {@link MessageMatcher} evaluation. - * @param authentication the {@link Supplier} of the {@link Authentication} to check - * @param message the {@link Message} to check - * @return an {@link AuthorizationDecision}. If there is no {@link MessageMatcher} - * matching the message, or the {@link AuthorizationManager} could not decide, then - * null is returned - */ - @Override - public AuthorizationDecision check(Supplier authentication, Message message) { - if (this.logger.isTraceEnabled()) { - this.logger.trace(LogMessage.format("Authorizing message")); - } - for (MessageMatcherEntry>> mapping : this.mappings) { - MessageMatcher matcher = mapping.getMessageMatcher(); - MessageAuthorizationContext authorizationContext = authorizationContext(matcher, message); - if (authorizationContext != null) { - AuthorizationManager> manager = mapping.getEntry(); - if (this.logger.isTraceEnabled()) { - this.logger.trace(LogMessage.format("Checking authorization on message using %s", manager)); - } - return manager.check(authentication, authorizationContext); - } - } - this.logger.trace("Abstaining since did not find matching MessageMatcher"); - return null; - } - - private MessageAuthorizationContext authorizationContext(MessageMatcher matcher, Message message) { - if (!matcher.matches((Message) message)) { - return null; - } - if (matcher instanceof SimpDestinationMessageMatcher) { - SimpDestinationMessageMatcher simp = (SimpDestinationMessageMatcher) matcher; - return new MessageAuthorizationContext<>(message, simp.extractPathVariables(message)); - } - return new MessageAuthorizationContext<>(message); - } - - /** - * Creates a builder for {@link MessageMatcherDelegatingAuthorizationManager}. - * @return the new {@link MessageMatcherDelegatingAuthorizationManager.Builder} - * instance - */ - public static Builder builder() { - return new Builder(); - } - - /** - * A builder for {@link MessageMatcherDelegatingAuthorizationManager}. - */ - public static final class Builder { - - private final List>>> mappings = new ArrayList<>(); - - /** - * Maps a {@link MessageMatcher} to an {@link AuthorizationManager}. - * @param matcher the {@link MessageMatcher} to use - * @param manager the {@link AuthorizationManager} to use - * @return the {@link MessageMatcherDelegatingAuthorizationManager.Builder} for - * further customizations - */ - public MessageMatcherDelegatingAuthorizationManager.Builder add(MessageMatcher matcher, - AuthorizationManager> manager) { - Assert.notNull(matcher, "matcher cannot be null"); - Assert.notNull(manager, "manager cannot be null"); - this.mappings.add(new MessageMatcherEntry<>(matcher, manager)); - return this; - } - - /** - * Creates a {@link MessageMatcherDelegatingAuthorizationManager} instance. - * @return the {@link MessageMatcherDelegatingAuthorizationManager} instance - */ - public MessageMatcherDelegatingAuthorizationManager build() { - return new MessageMatcherDelegatingAuthorizationManager(this.mappings); - } - - } - -} diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageSecurityMetadataSource.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageSecurityMetadataSource.java index ee3a30f9b4..acf6565c45 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageSecurityMetadataSource.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageSecurityMetadataSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * 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. @@ -26,9 +26,7 @@ import org.springframework.security.access.SecurityMetadataSource; * @since 4.0 * @see ChannelSecurityInterceptor * @see DefaultMessageSecurityMetadataSource - * @deprecated Use {@link MessageMatcherDelegatingAuthorizationManager} instead */ -@Deprecated public interface MessageSecurityMetadataSource extends SecurityMetadataSource { } diff --git a/messaging/src/main/java/org/springframework/security/messaging/util/matcher/MessageMatcherEntry.java b/messaging/src/main/java/org/springframework/security/messaging/util/matcher/MessageMatcherEntry.java deleted file mode 100644 index e5366638e0..0000000000 --- a/messaging/src/main/java/org/springframework/security/messaging/util/matcher/MessageMatcherEntry.java +++ /dev/null @@ -1,44 +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.messaging.util.matcher; - -/** - * A rich object for associating a {@link MessageMatcher} to another object. - * - * @author Josh Cummings - * @since 5.7 - */ -public class MessageMatcherEntry { - - private final MessageMatcher messageMatcher; - - private final T entry; - - public MessageMatcherEntry(MessageMatcher requestMatcher, T entry) { - this.messageMatcher = requestMatcher; - this.entry = entry; - } - - public MessageMatcher getMessageMatcher() { - return this.messageMatcher; - } - - public T getEntry() { - return this.entry; - } - -}