mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-12 13:23:29 +00:00
Use PathPatternMessageMatcher By Default
Issue gh-17501
This commit is contained in:
parent
ff7359b54a
commit
684775b46a
@ -16,29 +16,24 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.socket;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Fallback;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
||||
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcherFactory;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
final class MessageMatcherAuthorizationManagerConfiguration {
|
||||
|
||||
@Bean
|
||||
@Fallback
|
||||
PathPatternMessageMatcherBuilderFactoryBean messageMatcherBuilderFactoryBean() {
|
||||
return new PathPatternMessageMatcherBuilderFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder(
|
||||
ApplicationContext context) {
|
||||
MessageMatcherFactory.setApplicationContext(context);
|
||||
if (MessageMatcherFactory.usesPathPatterns()) {
|
||||
return MessageMatcherDelegatingAuthorizationManager.builder();
|
||||
}
|
||||
return MessageMatcherDelegatingAuthorizationManager.builder()
|
||||
.simpDestPathMatcher(
|
||||
() -> (context.getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0)
|
||||
? context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher()
|
||||
: new AntPathMatcher());
|
||||
MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder() {
|
||||
return MessageMatcherDelegatingAuthorizationManager.builder();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,9 +23,6 @@ import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
@Deprecated
|
||||
public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatcher<?>>, ApplicationContextAware {
|
||||
@ -36,8 +33,6 @@ public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatch
|
||||
|
||||
private final String path;
|
||||
|
||||
private PathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
public MessageMatcherFactoryBean(String path) {
|
||||
this(path, null);
|
||||
}
|
||||
@ -49,16 +44,7 @@ public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatch
|
||||
|
||||
@Override
|
||||
public MessageMatcher<?> getObject() throws Exception {
|
||||
if (this.builder != null) {
|
||||
return this.builder.matcher(this.method, this.path);
|
||||
}
|
||||
if (this.method == SimpMessageType.SUBSCRIBE) {
|
||||
return SimpDestinationMessageMatcher.createSubscribeMatcher(this.path, this.pathMatcher);
|
||||
}
|
||||
if (this.method == SimpMessageType.MESSAGE) {
|
||||
return SimpDestinationMessageMatcher.createMessageMatcher(this.path, this.pathMatcher);
|
||||
}
|
||||
return new SimpDestinationMessageMatcher(this.path, this.pathMatcher);
|
||||
return this.builder.matcher(this.method, this.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -66,13 +52,9 @@ public final class MessageMatcherFactoryBean implements FactoryBean<MessageMatch
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setPathMatcher(PathMatcher pathMatcher) {
|
||||
this.pathMatcher = pathMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.builder = context.getBeanProvider(PathPatternMessageMatcher.Builder.class).getIfUnique();
|
||||
this.builder = context.getBean(PathPatternMessageMatcher.Builder.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,9 +31,9 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
@ -56,6 +56,7 @@ import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.http.MessageMatcherFactoryBean;
|
||||
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
@ -134,7 +135,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
|
||||
private static final String TYPE_ATTR = "type";
|
||||
|
||||
private static final String PATH_MATCHER_BEAN_NAME = "springSecurityMessagePathMatcher";
|
||||
private static final String MESSAGE_MATCHER_BUILDER_BEAN_NAME = "HttpConfigurationBuilder-pathPatternMessageMatcherBuilder";
|
||||
|
||||
/**
|
||||
* @param element
|
||||
@ -144,13 +145,17 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
@Override
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String id = element.getAttribute(ID_ATTR);
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(MESSAGE_MATCHER_BUILDER_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder pathPatternMessageMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(PathPatternMessageMatcherBuilderFactoryBean.class);
|
||||
pathPatternMessageMatcherBuilder.setFallback(true);
|
||||
BeanDefinition bean = pathPatternMessageMatcherBuilder.getBeanDefinition();
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(bean, MESSAGE_MATCHER_BUILDER_BEAN_NAME));
|
||||
}
|
||||
String inSecurityInterceptorName = parseAuthorization(element, parserContext);
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
if (StringUtils.hasText(id)) {
|
||||
registry.registerAlias(inSecurityInterceptorName, id);
|
||||
if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
|
||||
registry.registerBeanDefinition(PATH_MATCHER_BEAN_NAME, new RootBeanDefinition(AntPathMatcher.class));
|
||||
}
|
||||
}
|
||||
else {
|
||||
boolean sameOriginDisabled = Boolean.parseBoolean(element.getAttribute(DISABLED_ATTR));
|
||||
@ -286,7 +291,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
+ " with a pattern because the type does not have a destination.", interceptMessage);
|
||||
}
|
||||
}
|
||||
matcher.addPropertyValue("pathMatcher", new RuntimeBeanReference("springSecurityMessagePathMatcher"));
|
||||
return matcher.getBeanDefinition();
|
||||
}
|
||||
|
||||
@ -342,13 +346,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
}
|
||||
argResolvers.add(beanDefinition);
|
||||
bd.getPropertyValues().add(CUSTOM_ARG_RESOLVERS_PROP, argResolvers);
|
||||
if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
|
||||
PropertyValue pathMatcherProp = bd.getPropertyValues().getPropertyValue("pathMatcher");
|
||||
Object pathMatcher = (pathMatcherProp != null) ? pathMatcherProp.getValue() : null;
|
||||
if (pathMatcher instanceof BeanReference) {
|
||||
registry.registerAlias(((BeanReference) pathMatcher).getBeanName(), PATH_MATCHER_BEAN_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CSRF_HANDSHAKE_HANDLER_CLASSES.contains(beanClassName)) {
|
||||
addCsrfTokenHandshakeInterceptor(bd);
|
||||
@ -376,9 +373,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
interceptors.addAll(currentInterceptors);
|
||||
}
|
||||
inboundChannel.getPropertyValues().add(INTERCEPTORS_PROP, interceptors);
|
||||
if (!registry.containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
|
||||
registry.registerBeanDefinition(PATH_MATCHER_BEAN_NAME, new RootBeanDefinition(AntPathMatcher.class));
|
||||
}
|
||||
}
|
||||
|
||||
private void addCsrfTokenHandshakeInterceptor(BeanDefinition bd) {
|
||||
|
@ -45,6 +45,7 @@ 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.PathContainer;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.messaging.Message;
|
||||
@ -70,6 +71,7 @@ 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.observation.SecurityObservationSettings;
|
||||
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
@ -99,6 +101,7 @@ 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 org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@ -507,6 +510,13 @@ public class WebSocketMessageBrokerSecurityConfigurationTests {
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class MsmsRegistryCustomPatternMatcherConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Bean
|
||||
PathPatternMessageMatcherBuilderFactoryBean messageMatcherBuilder() {
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
parser.setPathOptions(PathContainer.Options.MESSAGE_ROUTE);
|
||||
return new PathPatternMessageMatcherBuilderFactoryBean(parser);
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
@ -518,7 +528,6 @@ public class WebSocketMessageBrokerSecurityConfigurationTests {
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.setPathMatcher(new AntPathMatcher("."));
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/app");
|
||||
}
|
||||
@ -567,7 +576,6 @@ public class WebSocketMessageBrokerSecurityConfigurationTests {
|
||||
@Bean
|
||||
AuthorizationManager<Message<?>> authorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
|
||||
messages
|
||||
.simpDestPathMatcher(new AntPathMatcher())
|
||||
.simpDestMatchers("/app/a/*").permitAll()
|
||||
.anyMessage().denyAll();
|
||||
return messages.build();
|
||||
|
@ -23,7 +23,6 @@ import org.springframework.expression.Expression;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@ -42,7 +41,7 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
|
||||
|
||||
private final Expression authorizeExpression;
|
||||
|
||||
private final MessageMatcher<?> matcher;
|
||||
private final MessageMatcher<Object> matcher;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
@ -53,7 +52,7 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
|
||||
Assert.notNull(authorizeExpression, "authorizeExpression cannot be null");
|
||||
Assert.notNull(matcher, "matcher cannot be null");
|
||||
this.authorizeExpression = authorizeExpression;
|
||||
this.matcher = matcher;
|
||||
this.matcher = (MessageMatcher<Object>) matcher;
|
||||
}
|
||||
|
||||
Expression getAuthorizeExpression() {
|
||||
@ -72,12 +71,9 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon
|
||||
|
||||
@Override
|
||||
public EvaluationContext postProcess(EvaluationContext ctx, Message<?> message) {
|
||||
if (this.matcher instanceof SimpDestinationMessageMatcher) {
|
||||
Map<String, String> variables = ((SimpDestinationMessageMatcher) this.matcher)
|
||||
.extractPathVariables(message);
|
||||
for (Map.Entry<String, String> entry : variables.entrySet()) {
|
||||
ctx.setVariable(entry.getKey(), entry.getValue());
|
||||
}
|
||||
Map<String, String> variables = this.matcher.matcher(message).getVariables();
|
||||
for (Map.Entry<String, String> entry : variables.entrySet()) {
|
||||
ctx.setVariable(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ import java.util.function.Supplier;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
@ -33,15 +36,10 @@ import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.authorization.SingleResultAuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcherFactory;
|
||||
import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
|
||||
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.CollectionUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
public final class MessageMatcherDelegatingAuthorizationManager implements AuthorizationManager<Message<?>> {
|
||||
|
||||
@ -99,12 +97,11 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
/**
|
||||
* A builder for {@link MessageMatcherDelegatingAuthorizationManager}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
public static final class Builder implements ApplicationContextAware {
|
||||
|
||||
private final List<Entry<AuthorizationManager<MessageAuthorizationContext<?>>>> mappings = new ArrayList<>();
|
||||
|
||||
@Deprecated
|
||||
private Supplier<PathMatcher> pathMatcher = AntPathMatcher::new;
|
||||
private PathPatternMessageMatcher.Builder messageMatcherBuilder = PathPatternMessageMatcher.withDefaults();
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
@ -142,11 +139,9 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
|
||||
* {@link PathPatternMessageMatcher} if the application has configured a
|
||||
* {@link PathPatternMessageMatcher.Builder} bean) instances without regard to the
|
||||
* {@link SimpMessageType}. If no destination is found on the Message, then the
|
||||
* Matcher returns false.
|
||||
* Maps a {@link List} of {@link PathPatternMessageMatcher}s 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 {@code MessageMatcher}s from.
|
||||
*/
|
||||
public Builder.Constraint simpDestMatchers(String... patterns) {
|
||||
@ -154,10 +149,8 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
|
||||
* {@link PathPatternMessageMatcher} if the application has configured a
|
||||
* {@link PathPatternMessageMatcher.Builder} bean) instances that match on
|
||||
* {@code SimpMessageType.MESSAGE}. If no destination is found on the Message,
|
||||
* Maps a {@link List} of {@link PathPatternMessageMatcher}s 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 {@code MessageMatcher}s from.
|
||||
*/
|
||||
@ -166,11 +159,9 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
|
||||
* {@link PathPatternMessageMatcher} if the application has configured a
|
||||
* {@link PathPatternMessageMatcher.Builder} bean) instances that match on
|
||||
* {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the Message,
|
||||
* then the Matcher returns false.
|
||||
* Maps a {@link List} of {@link PathPatternMessageMatcher}s 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 {@code MessageMatcher}s from.
|
||||
*/
|
||||
public Builder.Constraint simpSubscribeDestMatchers(String... patterns) {
|
||||
@ -178,10 +169,8 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or
|
||||
* {@link PathPatternMessageMatcher} if the application has configured a
|
||||
* {@link PathPatternMessageMatcher.Builder} bean) instances. If no destination is
|
||||
* found on the Message, then the Matcher returns false.
|
||||
* Maps a {@link List} of {@link PathPatternMessageMatcher} 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 {@code MessageMatcher}s from.
|
||||
@ -191,44 +180,12 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
private Builder.Constraint simpDestMatchers(SimpMessageType type, String... patterns) {
|
||||
List<MessageMatcher<?>> matchers = new ArrayList<>(patterns.length);
|
||||
for (String pattern : patterns) {
|
||||
MessageMatcher<Object> matcher = MessageMatcherFactory.usesPathPatterns()
|
||||
? MessageMatcherFactory.matcher(type, pattern)
|
||||
: new LazySimpDestinationMessageMatcher(pattern, type);
|
||||
MessageMatcher<Object> matcher = this.messageMatcherBuilder.matcher(type, pattern);
|
||||
matchers.add(matcher);
|
||||
}
|
||||
return new Builder.Constraint(matchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link PathMatcher} to be used with the
|
||||
* {@link Builder#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 Builder} for further customization.
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder simpDestPathMatcher(PathMatcher pathMatcher) {
|
||||
Assert.notNull(pathMatcher, "pathMatcher cannot be null");
|
||||
this.pathMatcher = () -> pathMatcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link PathMatcher} to be used with the
|
||||
* {@link Builder#simpDestMatchers(String...)}. Use this method to delay the
|
||||
* computation or lookup of the {@link PathMatcher}.
|
||||
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
|
||||
* @return the {@link Builder} for further customization.
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder simpDestPathMatcher(Supplier<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.
|
||||
@ -248,6 +205,12 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
return new MessageMatcherDelegatingAuthorizationManager(this.mappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.messageMatcherBuilder = context.getBeanProvider(PathPatternMessageMatcher.Builder.class)
|
||||
.getIfUnique(PathPatternMessageMatcher::withDefaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the security constraint to be applied to the {@link MessageMatcher}
|
||||
* instances.
|
||||
@ -379,39 +342,6 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho
|
||||
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private final class LazySimpDestinationMessageMatcher implements MessageMatcher<Object> {
|
||||
|
||||
private final Supplier<SimpDestinationMessageMatcher> delegate;
|
||||
|
||||
private LazySimpDestinationMessageMatcher(String pattern, SimpMessageType type) {
|
||||
this.delegate = SingletonSupplier.of(() -> {
|
||||
PathMatcher pathMatcher = Builder.this.pathMatcher.get();
|
||||
if (type == null) {
|
||||
return new SimpDestinationMessageMatcher(pattern, pathMatcher);
|
||||
}
|
||||
if (SimpMessageType.MESSAGE == type) {
|
||||
return SimpDestinationMessageMatcher.createMessageMatcher(pattern, pathMatcher);
|
||||
}
|
||||
if (SimpMessageType.SUBSCRIBE == type) {
|
||||
return SimpDestinationMessageMatcher.createSubscribeMatcher(pattern, pathMatcher);
|
||||
}
|
||||
throw new IllegalStateException(type + " is not supported since it does not have a destination");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Message<?> message) {
|
||||
return this.delegate.get().matches(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchResult matcher(Message<?> message) {
|
||||
return this.delegate.get().matcher(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class Entry<T> {
|
||||
|
@ -28,7 +28,7 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.security.messaging.util.matcher.MessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
|
||||
import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
@ -81,7 +81,7 @@ public class MessageExpressionConfigAttributeTests {
|
||||
|
||||
@Test
|
||||
public void postProcessContext() {
|
||||
SimpDestinationMessageMatcher matcher = new SimpDestinationMessageMatcher("/topics/{topic}/**");
|
||||
PathPatternMessageMatcher matcher = PathPatternMessageMatcher.withDefaults().matcher("/topics/{topic}/**");
|
||||
// @formatter:off
|
||||
Message<?> message = MessageBuilder.withPayload("M")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "/topics/someTopic/sub1")
|
||||
|
@ -78,6 +78,7 @@ public class MessageExpressionVoterTests {
|
||||
@Test
|
||||
public void voteGranted() {
|
||||
given(this.expression.getValue(any(EvaluationContext.class), eq(Boolean.class))).willReturn(true);
|
||||
given(this.matcher.matcher(any())).willCallRealMethod();
|
||||
assertThat(this.voter.vote(this.authentication, this.message, this.attributes))
|
||||
.isEqualTo(AccessDecisionVoter.ACCESS_GRANTED);
|
||||
}
|
||||
@ -85,6 +86,7 @@ public class MessageExpressionVoterTests {
|
||||
@Test
|
||||
public void voteDenied() {
|
||||
given(this.expression.getValue(any(EvaluationContext.class), eq(Boolean.class))).willReturn(false);
|
||||
given(this.matcher.matcher(any())).willCallRealMethod();
|
||||
assertThat(this.voter.vote(this.authentication, this.message, this.attributes))
|
||||
.isEqualTo(AccessDecisionVoter.ACCESS_DENIED);
|
||||
}
|
||||
@ -127,6 +129,7 @@ public class MessageExpressionVoterTests {
|
||||
given(this.expressionHandler.createEvaluationContext(this.authentication, this.message))
|
||||
.willReturn(this.evaluationContext);
|
||||
given(this.expression.getValue(this.evaluationContext, Boolean.class)).willReturn(true);
|
||||
given(this.matcher.matcher(any())).willCallRealMethod();
|
||||
assertThat(this.voter.vote(this.authentication, this.message, this.attributes))
|
||||
.isEqualTo(AccessDecisionVoter.ACCESS_GRANTED);
|
||||
verify(this.expressionHandler).createEvaluationContext(this.authentication, this.message);
|
||||
|
@ -37,10 +37,11 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
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.MessageMatcherFactory;
|
||||
import org.springframework.security.messaging.util.matcher.PathPatternMessageMatcher;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
@ -58,7 +59,7 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
Mockito.when(this.context.getBeanProvider(PathPatternMessageMatcher.Builder.class)).thenReturn(this.provider);
|
||||
MessageMatcherFactory.setApplicationContext(this.context);
|
||||
Mockito.when(this.provider.getIfUnique(any())).thenReturn(PathPatternMessageMatcher.withDefaults());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -135,8 +136,7 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
void checkWhenMessageTypeAndPathPatternMatches() {
|
||||
Mockito.when(this.provider.getIfUnique()).thenReturn(PathPatternMessageMatcher.withDefaults());
|
||||
MessageMatcherFactory.setApplicationContext(this.context);
|
||||
Mockito.when(this.provider.getIfUnique(any())).thenReturn(PathPatternMessageMatcher.withDefaults());
|
||||
AuthorizationManager<Message<?>> authorizationManager = builder().simpMessageDestMatchers("/destination")
|
||||
.permitAll()
|
||||
.simpSubscribeDestMatchers("/destination")
|
||||
@ -154,10 +154,32 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
|
||||
assertThat(authorizationManager.authorize(mock(Supplier.class), message2).isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkWhenMessageTypeAndPathPatternMatchesCaseInsensitive() {
|
||||
PathPatternParser pathPatternParser = new PathPatternParser();
|
||||
pathPatternParser.setCaseSensitive(false);
|
||||
PathPatternMessageMatcher.Builder messageMatcherBuilder = PathPatternMessageMatcher
|
||||
.withPathPatternParser(pathPatternParser);
|
||||
Mockito.when(this.provider.getIfUnique(any())).thenReturn(messageMatcherBuilder);
|
||||
AuthorizationManager<Message<?>> authorizationManager = builder().simpMessageDestMatchers("/desTinaTion")
|
||||
.permitAll()
|
||||
.simpSubscribeDestMatchers("/desTinaTion")
|
||||
.denyAll()
|
||||
.anyMessage()
|
||||
.denyAll()
|
||||
.build();
|
||||
MessageHeaders headers = new MessageHeaders(Map.of(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER,
|
||||
SimpMessageType.MESSAGE, SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination"));
|
||||
Message<?> message = new GenericMessage<>(new Object(), headers);
|
||||
assertThat(authorizationManager.authorize(mock(Supplier.class), message).isGranted()).isTrue();
|
||||
MessageHeaders headers2 = new MessageHeaders(Map.of(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER,
|
||||
SimpMessageType.SUBSCRIBE, SimpMessageHeaderAccessor.DESTINATION_HEADER, "/destination"));
|
||||
Message<?> message2 = new GenericMessage<>(new Object(), headers2);
|
||||
assertThat(authorizationManager.authorize(mock(Supplier.class), message2).isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkPatternMismatch() {
|
||||
Mockito.when(this.provider.getIfUnique()).thenReturn(PathPatternMessageMatcher.withDefaults());
|
||||
MessageMatcherFactory.setApplicationContext(this.context);
|
||||
AuthorizationManager<Message<?>> authorizationManager = builder().simpDestMatchers("/destination/*")
|
||||
.permitAll()
|
||||
.anyMessage()
|
||||
@ -170,7 +192,10 @@ public final class MessageMatcherDelegatingAuthorizationManagerTests {
|
||||
}
|
||||
|
||||
private MessageMatcherDelegatingAuthorizationManager.Builder builder() {
|
||||
return MessageMatcherDelegatingAuthorizationManager.builder();
|
||||
MessageMatcherDelegatingAuthorizationManager.Builder builder = MessageMatcherDelegatingAuthorizationManager
|
||||
.builder();
|
||||
builder.setApplicationContext(this.context);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private Builder variable(String name) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user