Просмотр исходного кода

Remove MessageSecurityMetadataSourceRegistry

Issue gh-17295
Josh Cummings 1 месяц назад
Родитель
Сommit
4d3024cb49

+ 0 - 512
config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java

@@ -1,512 +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.Comparator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.springframework.messaging.Message;
-import org.springframework.messaging.simp.SimpMessageType;
-import org.springframework.security.access.expression.SecurityExpressionHandler;
-import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
-import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
-import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
-import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager;
-import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
-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;
-import org.springframework.util.StringUtils;
-
-/**
- * Allows mapping security constraints using {@link MessageMatcher} to the security
- * expressions.
- *
- * @author Rob Winch
- * @since 4.0
- * @deprecated Use {@link MessageMatcherDelegatingAuthorizationManager} instead
- */
-@Deprecated
-public class MessageSecurityMetadataSourceRegistry {
-
-	private static final String permitAll = "permitAll";
-
-	private static final String denyAll = "denyAll";
-
-	private static final String anonymous = "anonymous";
-
-	private static final String authenticated = "authenticated";
-
-	private static final String fullyAuthenticated = "fullyAuthenticated";
-
-	private static final String rememberMe = "rememberMe";
-
-	private SecurityExpressionHandler<Message<Object>> expressionHandler = new DefaultMessageSecurityExpressionHandler<>();
-
-	private final LinkedHashMap<MatcherBuilder, String> matcherToExpression = new LinkedHashMap<>();
-
-	private DelegatingPathMatcher pathMatcher = new DelegatingPathMatcher();
-
-	private boolean defaultPathMatcher = true;
-
-	/**
-	 * Maps any {@link Message} to a security expression.
-	 * @return the Expression to associate
-	 */
-	public 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 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 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. Uses
-	 * {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)} .
-	 * @return the {@link Constraint} that is associated to the {@link MessageMatcher}
-	 * @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
-	 */
-	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. Uses
-	 * {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}.
-	 * @return the {@link Constraint} that is associated to the {@link MessageMatcher}
-	 * @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
-	 */
-	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. Uses
-	 * {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}.
-	 * @return the {@link Constraint} that is associated to the {@link MessageMatcher}
-	 * @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
-	 */
-	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. Uses
-	 * {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}.
-	 * @return the {@link Constraint} that is associated to the {@link MessageMatcher}
-	 * @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
-	 */
-	private Constraint simpDestMatchers(SimpMessageType type, String... patterns) {
-		List<MatcherBuilder> matchers = new ArrayList<>(patterns.length);
-		for (String pattern : patterns) {
-			matchers.add(new PathMatcherMessageMatcherBuilder(pattern, type));
-		}
-		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 MessageSecurityMetadataSourceRegistry simpDestPathMatcher(PathMatcher pathMatcher) {
-		Assert.notNull(pathMatcher, "pathMatcher cannot be null");
-		this.pathMatcher.setPathMatcher(pathMatcher);
-		this.defaultPathMatcher = false;
-		return this;
-	}
-
-	/**
-	 * Determines if the {@link #simpDestPathMatcher(PathMatcher)} has been explicitly
-	 * set.
-	 * @return true if {@link #simpDestPathMatcher(PathMatcher)} has been explicitly set,
-	 * else false.
-	 */
-	protected boolean isSimpDestPathMatcherConfigured() {
-		return !this.defaultPathMatcher;
-	}
-
-	/**
-	 * 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<MatcherBuilder> builders = new ArrayList<>(matchers.length);
-		for (MessageMatcher<?> matcher : matchers) {
-			builders.add(new PreBuiltMatcherBuilder(matcher));
-		}
-		return new Constraint(builders);
-	}
-
-	/**
-	 * The {@link SecurityExpressionHandler} to be used. The default is to use
-	 * {@link DefaultMessageSecurityExpressionHandler}.
-	 * @param expressionHandler the {@link SecurityExpressionHandler} to use. Cannot be
-	 * null.
-	 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-	 * customization.
-	 */
-	public MessageSecurityMetadataSourceRegistry expressionHandler(
-			SecurityExpressionHandler<Message<Object>> expressionHandler) {
-		Assert.notNull(expressionHandler, "expressionHandler cannot be null");
-		this.expressionHandler = expressionHandler;
-		return this;
-	}
-
-	/**
-	 * Allows subclasses to create creating a {@link MessageSecurityMetadataSource}.
-	 *
-	 * <p>
-	 * This is not exposed so as not to confuse users of the API, which should never
-	 * invoke this method.
-	 * </p>
-	 * @return the {@link MessageSecurityMetadataSource} to use
-	 */
-	protected MessageSecurityMetadataSource createMetadataSource() {
-		LinkedHashMap<MessageMatcher<?>, String> matcherToExpression = new LinkedHashMap<>();
-		for (Map.Entry<MatcherBuilder, String> entry : this.matcherToExpression.entrySet()) {
-			matcherToExpression.put(entry.getKey().build(), entry.getValue());
-		}
-		return ExpressionBasedMessageSecurityMetadataSourceFactory
-			.createExpressionMessageMetadataSource(matcherToExpression, this.expressionHandler);
-	}
-
-	/**
-	 * Allows determining if a mapping was added.
-	 *
-	 * <p>
-	 * This is not exposed so as not to confuse users of the API, which should never need
-	 * to invoke this method.
-	 * </p>
-	 * @return true if a mapping was added, else false
-	 */
-	protected boolean containsMapping() {
-		return !this.matcherToExpression.isEmpty();
-	}
-
-	private static String hasAnyRole(String... authorities) {
-		String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_");
-		return "hasAnyRole('ROLE_" + anyAuthorities + "')";
-	}
-
-	private static String hasRole(String role) {
-		Assert.notNull(role, "role cannot be null");
-		if (role.startsWith("ROLE_")) {
-			throw new IllegalArgumentException(
-					"role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
-		}
-		return "hasRole('ROLE_" + role + "')";
-	}
-
-	private static String hasAuthority(String authority) {
-		return "hasAuthority('" + authority + "')";
-	}
-
-	private static String hasAnyAuthority(String... authorities) {
-		String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','");
-		return "hasAnyAuthority('" + anyAuthorities + "')";
-	}
-
-	/**
-	 * Represents the security constraint to be applied to the {@link MessageMatcher}
-	 * instances.
-	 */
-	public final class Constraint {
-
-		private final List<? extends MatcherBuilder> messageMatchers;
-
-		/**
-		 * Creates a new instance
-		 * @param messageMatchers the {@link MessageMatcher} instances to map to this
-		 * constraint
-		 */
-		private Constraint(List<? extends MatcherBuilder> 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 MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry hasRole(String role) {
-			return access(MessageSecurityMetadataSourceRegistry.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 MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry hasAnyRole(String... roles) {
-			return access(MessageSecurityMetadataSourceRegistry.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 MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry hasAuthority(String authority) {
-			return access(MessageSecurityMetadataSourceRegistry.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 MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry hasAnyAuthority(String... authorities) {
-			return access(MessageSecurityMetadataSourceRegistry.hasAnyAuthority(authorities));
-		}
-
-		/**
-		 * Specify that Messages are allowed by anyone.
-		 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry permitAll() {
-			return access(permitAll);
-		}
-
-		/**
-		 * Specify that Messages are allowed by anonymous users.
-		 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry anonymous() {
-			return access(anonymous);
-		}
-
-		/**
-		 * Specify that Messages are allowed by users that have been remembered.
-		 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 * @see RememberMeConfigurer
-		 */
-		public MessageSecurityMetadataSourceRegistry rememberMe() {
-			return access(rememberMe);
-		}
-
-		/**
-		 * Specify that Messages are not allowed by anyone.
-		 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry denyAll() {
-			return access(denyAll);
-		}
-
-		/**
-		 * Specify that Messages are allowed by any authenticated user.
-		 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry authenticated() {
-			return access(authenticated);
-		}
-
-		/**
-		 * Specify that Messages are allowed by users who have authenticated and were not
-		 * "remembered".
-		 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 * @see RememberMeConfigurer
-		 */
-		public MessageSecurityMetadataSourceRegistry fullyAuthenticated() {
-			return access(fullyAuthenticated);
-		}
-
-		/**
-		 * Allows specifying that Messages are secured by an arbitrary expression
-		 * @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER')
-		 * and hasRole('ROLE_SUPER')")
-		 * @return the {@link MessageSecurityMetadataSourceRegistry} for further
-		 * customization
-		 */
-		public MessageSecurityMetadataSourceRegistry access(String attribute) {
-			for (MatcherBuilder messageMatcher : this.messageMatchers) {
-				MessageSecurityMetadataSourceRegistry.this.matcherToExpression.put(messageMatcher, attribute);
-			}
-			return MessageSecurityMetadataSourceRegistry.this;
-		}
-
-	}
-
-	private static final class PreBuiltMatcherBuilder implements MatcherBuilder {
-
-		private MessageMatcher<?> matcher;
-
-		private PreBuiltMatcherBuilder(MessageMatcher<?> matcher) {
-			this.matcher = matcher;
-		}
-
-		@Override
-		public MessageMatcher<?> build() {
-			return this.matcher;
-		}
-
-	}
-
-	private final class PathMatcherMessageMatcherBuilder implements MatcherBuilder {
-
-		private final String pattern;
-
-		private final SimpMessageType type;
-
-		private PathMatcherMessageMatcherBuilder(String pattern, SimpMessageType type) {
-			this.pattern = pattern;
-			this.type = type;
-		}
-
-		@Override
-		public MessageMatcher<?> build() {
-			if (this.type == null) {
-				return new SimpDestinationMessageMatcher(this.pattern,
-						MessageSecurityMetadataSourceRegistry.this.pathMatcher);
-			}
-			if (SimpMessageType.MESSAGE == this.type) {
-				return SimpDestinationMessageMatcher.createMessageMatcher(this.pattern,
-						MessageSecurityMetadataSourceRegistry.this.pathMatcher);
-			}
-			if (SimpMessageType.SUBSCRIBE == this.type) {
-				return SimpDestinationMessageMatcher.createSubscribeMatcher(this.pattern,
-						MessageSecurityMetadataSourceRegistry.this.pathMatcher);
-			}
-			throw new IllegalStateException(this.type + " is not supported since it does not have a destination");
-		}
-
-	}
-
-	private interface MatcherBuilder {
-
-		MessageMatcher<?> build();
-
-	}
-
-	static class DelegatingPathMatcher implements PathMatcher {
-
-		private PathMatcher delegate = new AntPathMatcher();
-
-		@Override
-		public boolean isPattern(String path) {
-			return this.delegate.isPattern(path);
-		}
-
-		@Override
-		public boolean match(String pattern, String path) {
-			return this.delegate.match(pattern, path);
-		}
-
-		@Override
-		public boolean matchStart(String pattern, String path) {
-			return this.delegate.matchStart(pattern, path);
-		}
-
-		@Override
-		public String extractPathWithinPattern(String pattern, String path) {
-			return this.delegate.extractPathWithinPattern(pattern, path);
-		}
-
-		@Override
-		public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
-			return this.delegate.extractUriTemplateVariables(pattern, path);
-		}
-
-		@Override
-		public Comparator<String> getPatternComparator(String path) {
-			return this.delegate.getPatternComparator(path);
-		}
-
-		@Override
-		public String combine(String pattern1, String pattern2) {
-			return this.delegate.combine(pattern1, pattern2);
-		}
-
-		void setPathMatcher(PathMatcher pathMatcher) {
-			this.delegate = pathMatcher;
-		}
-
-	}
-
-}

+ 0 - 337
config/src/test/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistryTests.java

@@ -1,337 +0,0 @@
-/*
- * Copyright 2002-2017 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.Collection;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import org.springframework.messaging.Message;
-import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
-import org.springframework.messaging.simp.SimpMessageType;
-import org.springframework.messaging.support.MessageBuilder;
-import org.springframework.security.access.ConfigAttribute;
-import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
-import org.springframework.security.messaging.util.matcher.MessageMatcher;
-import org.springframework.util.AntPathMatcher;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.mockito.BDDMockito.given;
-
-@ExtendWith(MockitoExtension.class)
-public class MessageSecurityMetadataSourceRegistryTests {
-
-	@Mock
-	private MessageMatcher<Object> matcher;
-
-	private MessageSecurityMetadataSourceRegistry messages;
-
-	private Message<String> message;
-
-	@BeforeEach
-	public void setup() {
-		this.messages = new MessageSecurityMetadataSourceRegistry();
-		// @formatter:off
-		this.message = MessageBuilder.withPayload("Hi")
-				.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "location")
-				.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.MESSAGE)
-				.build();
-		// @formatter:on
-	}
-
-	// See
-	// https://github.com/spring-projects/spring-security/commit/3f30529039c76facf335d6ca69d18d8ae287f3f9#commitcomment-7412712
-	// https://jira.spring.io/browse/SPR-11660
-	@Test
-	public void simpDestMatchersCustom() {
-		// @formatter:off
-		this.message = MessageBuilder.withPayload("Hi")
-				.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
-				.build();
-		// @formatter:on
-		this.messages.simpDestPathMatcher(new AntPathMatcher(".")).simpDestMatchers("price.stock.*").permitAll();
-		assertThat(getAttribute()).isNull();
-		// @formatter:off
-		this.message = MessageBuilder.withPayload("Hi")
-				.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
-				.build();
-		// @formatter:on
-		this.messages.simpDestPathMatcher(new AntPathMatcher(".")).simpDestMatchers("price.stock.**").permitAll();
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void simpDestMatchersCustomSetAfterMatchersDoesNotMatter() {
-		// @formatter:off
-		this.message = MessageBuilder.withPayload("Hi")
-				.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
-				.build();
-		// @formatter:on
-		this.messages.simpDestMatchers("price.stock.*").permitAll().simpDestPathMatcher(new AntPathMatcher("."));
-		assertThat(getAttribute()).isNull();
-		// @formatter:off
-		this.message = MessageBuilder.withPayload("Hi")
-				.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
-				.build();
-		// @formatter:on
-		this.messages.simpDestMatchers("price.stock.**").permitAll().simpDestPathMatcher(new AntPathMatcher("."));
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void pathMatcherNull() {
-		assertThatIllegalArgumentException().isThrownBy(() -> this.messages.simpDestPathMatcher(null));
-	}
-
-	@Test
-	public void matchersFalse() {
-		this.messages.matchers(this.matcher).permitAll();
-		assertThat(getAttribute()).isNull();
-	}
-
-	@Test
-	public void matchersTrue() {
-		given(this.matcher.matches(this.message)).willReturn(true);
-		this.messages.matchers(this.matcher).permitAll();
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void simpDestMatchersExact() {
-		this.messages.simpDestMatchers("location").permitAll();
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void simpDestMatchersMulti() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "api/**").hasRole("ADMIN")
-				.simpDestMatchers("location").permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void simpDestMatchersRole() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").hasRole("ADMIN")
-				.anyMessage().denyAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("hasRole('ROLE_ADMIN')");
-	}
-
-	@Test
-	public void simpDestMatchersAnyRole() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").hasAnyRole("ADMIN", "ROOT")
-				.anyMessage().denyAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("hasAnyRole('ROLE_ADMIN','ROLE_ROOT')");
-	}
-
-	@Test
-	public void simpDestMatchersAuthority() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").hasAuthority("ROLE_ADMIN")
-				.anyMessage().fullyAuthenticated();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("hasAuthority('ROLE_ADMIN')");
-	}
-
-	@Test
-	public void simpDestMatchersAccess() {
-		String expected = "hasRole('ROLE_ADMIN') and fullyAuthenticated";
-		this.messages.simpDestMatchers("admin/**", "location/**").access(expected).anyMessage().denyAll();
-		assertThat(getAttribute()).isEqualTo(expected);
-	}
-
-	@Test
-	public void simpDestMatchersAnyAuthority() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_ROOT")
-				.anyMessage().denyAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("hasAnyAuthority('ROLE_ADMIN','ROLE_ROOT')");
-	}
-
-	@Test
-	public void simpDestMatchersRememberMe() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").rememberMe()
-				.anyMessage().denyAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("rememberMe");
-	}
-
-	@Test
-	public void simpDestMatchersAnonymous() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").anonymous()
-				.anyMessage().denyAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("anonymous");
-	}
-
-	@Test
-	public void simpDestMatchersFullyAuthenticated() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").fullyAuthenticated()
-				.anyMessage().denyAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("fullyAuthenticated");
-	}
-
-	@Test
-	public void simpDestMatchersDenyAll() {
-		// @formatter:off
-		this.messages
-				.simpDestMatchers("admin/**", "location/**").denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("denyAll");
-	}
-
-	@Test
-	public void simpDestMessageMatchersNotMatch() {
-		// @formatter:off
-		this.messages.
-				simpMessageDestMatchers("admin/**").denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void simpDestMessageMatchersMatch() {
-		// @formatter:off
-		this.messages
-				.simpMessageDestMatchers("location/**").denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("denyAll");
-	}
-
-	@Test
-	public void simpDestSubscribeMatchersNotMatch() {
-		// @formatter:off
-		this.messages
-				.simpSubscribeDestMatchers("location/**").denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void simpDestSubscribeMatchersMatch() {
-		// @formatter:off
-		this.message = MessageBuilder.fromMessage(this.message)
-				.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.SUBSCRIBE)
-				.build();
-		this.messages
-				.simpSubscribeDestMatchers("location/**").denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("denyAll");
-	}
-
-	@Test
-	public void nullDestMatcherNotMatches() {
-		// @formatter:off
-		this.messages
-				.nullDestMatcher().denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void nullDestMatcherMatch() {
-		// @formatter:off
-		this.message = MessageBuilder.withPayload("Hi")
-				.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.CONNECT)
-				.build();
-		this.messages
-				.nullDestMatcher().denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("denyAll");
-	}
-
-	@Test
-	public void simpTypeMatchersMatch() {
-		// @formatter:off
-		this.messages
-				.simpTypeMatchers(SimpMessageType.MESSAGE).denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("denyAll");
-	}
-
-	@Test
-	public void simpTypeMatchersMatchMulti() {
-		// @formatter:off
-		this.messages
-				.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.MESSAGE).denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("denyAll");
-	}
-
-	@Test
-	public void simpTypeMatchersNotMatch() {
-		// @formatter:off
-		this.messages
-				.simpTypeMatchers(SimpMessageType.CONNECT).denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	@Test
-	public void simpTypeMatchersNotMatchMulti() {
-		// @formatter:off
-		this.messages
-				.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.DISCONNECT).denyAll()
-				.anyMessage().permitAll();
-		// @formatter:on
-		assertThat(getAttribute()).isEqualTo("permitAll");
-	}
-
-	private String getAttribute() {
-		MessageSecurityMetadataSource source = this.messages.createMetadataSource();
-		Collection<ConfigAttribute> attrs = source.getAttributes(this.message);
-		if (attrs == null) {
-			return null;
-		}
-		assertThat(attrs).hasSize(1);
-		return attrs.iterator().next().toString();
-	}
-
-}