SEC-2996: Suport configuring SecurityExpressionHandler<Message<Object>>
This commit is contained in:
@@ -25,11 +25,14 @@ import org.springframework.messaging.support.GenericMessage
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.config.AbstractXmlConfigTests
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
|
||||
import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot;
|
||||
import org.springframework.security.web.csrf.CsrfToken
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken
|
||||
import org.springframework.security.web.csrf.InvalidCsrfTokenException
|
||||
@@ -432,6 +435,29 @@ class WebSocketMessageBrokerConfigTests extends AbstractXmlConfigTests {
|
||||
createAppContext()
|
||||
}
|
||||
|
||||
def 'custom expressions'() {
|
||||
setup:
|
||||
bean('expressionHandler', DenyRobMessageSecurityExpressionHandler)
|
||||
websocket {
|
||||
'expression-handler' (ref: 'expressionHandler') {}
|
||||
'intercept-message'(pattern:'/**',access:'denyRob()')
|
||||
}
|
||||
|
||||
when: 'message is sent with user'
|
||||
clientInboundChannel.send(message('/message'))
|
||||
|
||||
then: 'access is allowed to custom expression'
|
||||
noExceptionThrown()
|
||||
|
||||
when:
|
||||
messageUser = new TestingAuthenticationToken('rob', 'pass', 'ROLE_USER')
|
||||
clientInboundChannel.send(message('/message'))
|
||||
|
||||
then:
|
||||
def e = thrown(MessageDeliveryException)
|
||||
e.cause instanceof AccessDeniedException
|
||||
}
|
||||
|
||||
def getClientInboundChannel() {
|
||||
appContext.getBean("clientInboundChannel")
|
||||
}
|
||||
@@ -442,7 +468,6 @@ class WebSocketMessageBrokerConfigTests extends AbstractXmlConfigTests {
|
||||
}
|
||||
|
||||
def message(SimpMessageHeaderAccessor headers, String destination) {
|
||||
messageUser = new TestingAuthenticationToken('user','pass','ROLE_USER')
|
||||
headers.sessionId = '123'
|
||||
headers.sessionAttributes = [:]
|
||||
headers.destination = destination
|
||||
@@ -518,4 +543,18 @@ class WebSocketMessageBrokerConfigTests extends AbstractXmlConfigTests {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class DenyRobMessageSecurityExpressionHandler extends DefaultMessageSecurityExpressionHandler<Object> {
|
||||
@Override
|
||||
protected SecurityExpressionOperations createSecurityExpressionRoot(
|
||||
Authentication authentication,
|
||||
Message<Object> invocation) {
|
||||
return new MessageSecurityExpressionRoot(authentication, invocation) {
|
||||
public boolean denyRob() {
|
||||
Authentication auth = getAuthentication();
|
||||
return auth != null && !"rob".equals(auth.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,14 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.socket;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -36,9 +44,14 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletConfig;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
|
||||
import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
||||
@@ -57,14 +70,6 @@ import org.springframework.web.socket.server.support.HttpSessionHandshakeInterce
|
||||
import org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler;
|
||||
import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
@@ -389,6 +394,74 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customExpression()
|
||||
throws Exception {
|
||||
loadConfig(CustomExpressionConfig.class);
|
||||
|
||||
clientInboundChannel().send(message("/denyRob"));
|
||||
|
||||
this.messageUser = new TestingAuthenticationToken("rob", "password", "ROLE_USER");
|
||||
try {
|
||||
clientInboundChannel().send(message("/denyRob"));
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (MessageDeliveryException expected) {
|
||||
assertThat(expected.getCause()).isInstanceOf(AccessDeniedException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class CustomExpressionConfig extends
|
||||
AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
// @formatter:off
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry
|
||||
.addEndpoint("/other")
|
||||
.setHandshakeHandler(testHandshakeHandler());
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
// @formatter:off
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages
|
||||
.anyMessage().access("denyRob()");
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
@Bean
|
||||
public SecurityExpressionHandler<Message<Object>> messageSecurityExpressionHandler() {
|
||||
return new DefaultMessageSecurityExpressionHandler<Object>() {
|
||||
@Override
|
||||
protected SecurityExpressionOperations createSecurityExpressionRoot(
|
||||
Authentication authentication,
|
||||
Message<Object> invocation) {
|
||||
return new MessageSecurityExpressionRoot(authentication, invocation) {
|
||||
public boolean denyRob() {
|
||||
Authentication auth = getAuthentication();
|
||||
return auth != null && !"rob".equals(auth.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/app");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestHandshakeHandler testHandshakeHandler() {
|
||||
return new TestHandshakeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertHandshake(HttpServletRequest request) {
|
||||
TestHandshakeHandler handshakeHandler = context
|
||||
.getBean(TestHandshakeHandler.class);
|
||||
@@ -597,6 +670,7 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages
|
||||
.simpDestMatchers("/permitAll/**").permitAll()
|
||||
.simpDestMatchers("/customExpression/**").access("denyRob")
|
||||
.anyMessage().denyAll();
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
Reference in New Issue
Block a user