Message SecurityExpressionHandler is post processed (#3820)

Previously the SecurityExpressionHandler for message based configuration
did not have a beanResolver set.

This commit post processes the default message SecurityExpressionHandler
to ensure the beanResolver is set.

Fixes gh-3797
This commit is contained in:
Rob Winch 2016-04-19 12:21:58 -05:00 committed by Joe Grandja
parent c872a77ad1
commit a5a8aeb550
2 changed files with 45 additions and 6 deletions

View File

@ -24,6 +24,7 @@ import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
@ -33,7 +34,10 @@ import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.vote.AffirmativeBased; import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
import org.springframework.security.messaging.access.expression.MessageExpressionVoter; import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor; import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource; import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
@ -78,10 +82,13 @@ import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsSe
* @author Rob Winch * @author Rob Winch
*/ */
@Order(Ordered.HIGHEST_PRECEDENCE + 100) @Order(Ordered.HIGHEST_PRECEDENCE + 100)
@Import(ObjectPostProcessorConfiguration.class)
public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
AbstractWebSocketMessageBrokerConfigurer implements SmartInitializingSingleton { AbstractWebSocketMessageBrokerConfigurer implements SmartInitializingSingleton {
private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry(); private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry();
private SecurityExpressionHandler<Message<Object>> defaultExpressionHandler = new DefaultMessageSecurityExpressionHandler<Object>();
private SecurityExpressionHandler<Message<Object>> expressionHandler; private SecurityExpressionHandler<Message<Object>> expressionHandler;
private ApplicationContext context; private ApplicationContext context;
@ -150,9 +157,7 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor( ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
inboundMessageSecurityMetadataSource()); inboundMessageSecurityMetadataSource());
MessageExpressionVoter<Object> voter = new MessageExpressionVoter<Object>(); MessageExpressionVoter<Object> voter = new MessageExpressionVoter<Object>();
if(expressionHandler != null) { voter.setExpressionHandler(getMessageExpressionHandler());
voter.setExpressionHandler(expressionHandler);
}
List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>(); List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>();
voters.add(voter); voters.add(voter);
@ -169,9 +174,7 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
@Bean @Bean
public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() { public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() {
if(expressionHandler != null) { inboundRegistry.expressionHandler(getMessageExpressionHandler());
inboundRegistry.expressionHandler(expressionHandler);
}
configureInbound(inboundRegistry); configureInbound(inboundRegistry);
return inboundRegistry.createMetadataSource(); return inboundRegistry.createMetadataSource();
} }
@ -218,6 +221,18 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
} }
} }
@Autowired(required = false)
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
defaultExpressionHandler = objectPostProcessor.postProcess(defaultExpressionHandler);
}
private SecurityExpressionHandler<Message<Object>> getMessageExpressionHandler() {
if(expressionHandler == null) {
return defaultExpressionHandler;
}
return expressionHandler;
}
public void afterSingletonsInstantiated() { public void afterSingletonsInstantiated() {
if (sameOriginDisabled()) { if (sameOriginDisabled()) {
return; return;

View File

@ -117,6 +117,15 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
clientInboundChannel().send(message("/permitAll")); clientInboundChannel().send(message("/permitAll"));
} }
// gh-3797
@Test
public void beanResolver() {
loadConfig(SockJsSecurityConfig.class);
messageUser = null;
clientInboundChannel().send(message("/beanResolver"));
}
@Test @Test
public void addsAuthenticationPrincipalResolver() throws InterruptedException { public void addsAuthenticationPrincipalResolver() throws InterruptedException {
loadConfig(SockJsSecurityConfig.class); loadConfig(SockJsSecurityConfig.class);
@ -594,6 +603,7 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages messages
.simpDestMatchers("/permitAll/**").permitAll() .simpDestMatchers("/permitAll/**").permitAll()
.simpDestMatchers("/beanResolver/**").access("@security.check()")
.anyMessage().denyAll(); .anyMessage().denyAll();
} }
// @formatter:on // @formatter:on
@ -613,6 +623,20 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
public TestHandshakeHandler testHandshakeHandler() { public TestHandshakeHandler testHandshakeHandler() {
return new TestHandshakeHandler(); return new TestHandshakeHandler();
} }
@Bean
public SecurityCheck security() {
return new SecurityCheck();
}
static class SecurityCheck {
private boolean check;
public boolean check() {
check = !check;
return check;
}
}
} }
@Configuration @Configuration