diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java index e9fef676c6..6fac21acc3 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java @@ -51,6 +51,8 @@ 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.AnonymousAuthenticationToken; +import org.springframework.security.authentication.RememberMeAuthenticationToken; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; @@ -58,6 +60,7 @@ import org.springframework.security.config.annotation.SecurityContextChangedList 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.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor; import org.springframework.security.messaging.access.intercept.MessageAuthorizationContext; @@ -93,7 +96,7 @@ public class WebSocketMessageBrokerSecurityConfigurationTests { AnnotationConfigWebApplicationContext context; - TestingAuthenticationToken messageUser; + Authentication messageUser; CsrfToken token; @@ -311,6 +314,56 @@ public class WebSocketMessageBrokerSecurityConfigurationTests { assertThat(interceptors).contains(AuthorizationChannelInterceptor.class); } + @Test + public void sendMessageWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenAccessDeniedException() { + loadConfig(WebSocketSecurityConfig.class); + this.messageUser = new RememberMeAuthenticationToken("key", "user", + AuthorityUtils.createAuthorityList("ROLE_USER")); + assertThatExceptionOfType(MessageDeliveryException.class) + .isThrownBy(() -> clientInboundChannel().send(message("/fullyAuthenticated"))) + .withCauseInstanceOf(AccessDeniedException.class); + } + + @Test + public void sendMessageWhenFullyAuthenticatedConfiguredAndUserThenPasses() { + loadConfig(WebSocketSecurityConfig.class); + clientInboundChannel().send(message("/fullyAuthenticated")); + } + + @Test + public void sendMessageWhenRememberMeConfiguredAndNoUserThenAccessDeniedException() { + loadConfig(WebSocketSecurityConfig.class); + this.messageUser = null; + assertThatExceptionOfType(MessageDeliveryException.class) + .isThrownBy(() -> clientInboundChannel().send(message("/rememberMe"))) + .withCauseInstanceOf(AccessDeniedException.class); + } + + @Test + public void sendMessageWhenRememberMeConfiguredAndRememberMeTokenThenPasses() { + loadConfig(WebSocketSecurityConfig.class); + this.messageUser = new RememberMeAuthenticationToken("key", "user", + AuthorityUtils.createAuthorityList("ROLE_USER")); + clientInboundChannel().send(message("/rememberMe")); + } + + @Test + public void sendMessageWhenAnonymousConfiguredAndAnonymousUserThenPasses() { + loadConfig(WebSocketSecurityConfig.class); + this.messageUser = new AnonymousAuthenticationToken("key", "user", + AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")); + clientInboundChannel().send(message("/anonymous")); + } + + @Test + public void sendMessageWhenAnonymousConfiguredAndLoggedInUserThenAccessDeniedException() { + loadConfig(WebSocketSecurityConfig.class); + assertThatExceptionOfType(MessageDeliveryException.class) + .isThrownBy(() -> clientInboundChannel().send(message("/anonymous"))) + .withCauseInstanceOf(AccessDeniedException.class); + + } + private void assertHandshake(HttpServletRequest request) { TestHandshakeHandler handshakeHandler = this.context.getBean(TestHandshakeHandler.class); assertThat(handshakeHandler.attributes.get(CsrfToken.class.getName())).isSameAs(this.token); @@ -708,6 +761,9 @@ public class WebSocketMessageBrokerSecurityConfigurationTests { messages .simpDestMatchers("/permitAll/**").permitAll() .simpDestMatchers("/authenticated/**").authenticated() + .simpDestMatchers("/fullyAuthenticated/**").fullyAuthenticated() + .simpDestMatchers("/rememberMe/**").rememberMe() + .simpDestMatchers("/anonymous/**").anonymous() .anyMessage().denyAll(); // @formatter:on return messages.build(); 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 index 57b06c008e..32d2a09016 100644 --- 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 @@ -332,6 +332,34 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho return access(AuthenticatedAuthorizationManager.authenticated()); } + /** + * Specify that Messages are allowed by users who have authenticated and were + * not "remembered". + * @return the {@link Builder} for further customization + * @since 5.8 + */ + public Builder fullyAuthenticated() { + return access(AuthenticatedAuthorizationManager.fullyAuthenticated()); + } + + /** + * Specify that Messages are allowed by users that have been remembered. + * @return the {@link Builder} for further customization + * @since 5.8 + */ + public Builder rememberMe() { + return access(AuthenticatedAuthorizationManager.rememberMe()); + } + + /** + * Specify that Messages are allowed by anonymous users. + * @return the {@link Builder} for further customization + * @since 5.8 + */ + public Builder anonymous() { + return access(AuthenticatedAuthorizationManager.anonymous()); + } + /** * Allows specifying that Messages are secured by an arbitrary expression * @param authorizationManager the {@link AuthorizationManager} to secure the