diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelAccessPolicy.java b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelAccessPolicy.java
new file mode 100644
index 0000000000..96c72f01cf
--- /dev/null
+++ b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelAccessPolicy.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2002-2008 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
+ *
+ * http://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.integration.security.channel;
+
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Creates the {@link ConfigAttributeDefinition}s for secured channel
+ * send and receive operations based on simple String values.
+ */
+public class ChannelAccessPolicy {
+
+ private final ConfigAttributeDefinition configAttributeDefinitionForSend;
+
+ private final ConfigAttributeDefinition configAttributeDefinitionForReceive;
+
+
+ /**
+ * Create an access policy instance. The provided 'sendAccess' and 'receiveAccess'
+ * values may be a single String or a comma-delimited list of values. All whitespace
+ * will be trimmed. A null value indicates that the policy does not
+ * apply for either send or receive access type. At most one of the values may be null.
+ */
+ public ChannelAccessPolicy(String sendAccess, String receiveAccess) {
+ Assert.isTrue(sendAccess != null || receiveAccess != null,
+ "At least one of 'sendAccess' and 'receiveAccess' must not be null.");
+ String[] sendValues = StringUtils.trimArrayElements(
+ StringUtils.commaDelimitedListToStringArray(sendAccess));
+ String[] receiveValues = StringUtils.trimArrayElements(
+ StringUtils.commaDelimitedListToStringArray(receiveAccess));
+ this.configAttributeDefinitionForSend = (sendValues.length > 0)
+ ? new ConfigAttributeDefinition(sendValues) : null;
+ this.configAttributeDefinitionForReceive = (receiveValues.length > 0)
+ ? new ConfigAttributeDefinition(receiveValues) : null;
+ }
+
+
+ public ConfigAttributeDefinition getConfigAttributeDefinitionForSend() {
+ return this.configAttributeDefinitionForSend;
+ }
+
+ public ConfigAttributeDefinition getConfigAttributeDefinitionForReceive() {
+ return this.configAttributeDefinitionForReceive;
+ }
+
+}
diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelInvocation.java b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelInvocation.java
new file mode 100644
index 0000000000..98cc6dadbf
--- /dev/null
+++ b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelInvocation.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2002-2008 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
+ *
+ * http://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.integration.security.channel;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.integration.channel.MessageChannel;
+import org.springframework.integration.message.Message;
+import org.springframework.util.Assert;
+
+/**
+ * Secured object for {@link ChannelSecurityInterceptor}. Maintains a reference
+ * to the original {@link MethodInvocation} instance and provides convenient
+ * access to the secured {@link MessageChannel}. If the intercepted invocation
+ * is a send operation, the {@link Message} is also available.
+ *
+ * @author Mark Fisher
+ */
+public class ChannelInvocation {
+
+ private final MessageChannel channel;
+
+ private final Message> message;
+
+ private final MethodInvocation methodInvocation;
+
+
+ /**
+ * @param methodInvocation the intercepted MethodInvocation instance
+ */
+ public ChannelInvocation(MethodInvocation methodInvocation) {
+ Assert.notNull(methodInvocation, "MethodInvocation must not be null");
+ Assert.isAssignable(MessageChannel.class, methodInvocation.getThis().getClass(),
+ "MethodInvocation must be on a MessageChannel");
+ this.channel = (MessageChannel) methodInvocation.getThis();
+ if (methodInvocation.getMethod().getName().equals("send")) {
+ if (methodInvocation.getArguments().length < 1 || !(methodInvocation.getArguments()[0] instanceof Message)) {
+ throw new IllegalStateException("expected a Message as the first parameter of the channel's send method");
+ }
+ this.message = (Message>) methodInvocation.getArguments()[0];
+ }
+ else {
+ this.message = null;
+ }
+ this.methodInvocation = methodInvocation;
+ }
+
+
+ public MessageChannel getChannel() {
+ return this.channel;
+ }
+
+ public Message> getMessage() {
+ return this.message;
+ }
+
+ public MethodInvocation getMethodInvocation() {
+ return this.methodInvocation;
+ }
+
+ public boolean isSend() {
+ return "send".equals(this.methodInvocation.getMethod().getName());
+ }
+
+ public boolean isReceive() {
+ return "receive".equals(this.methodInvocation.getMethod().getName());
+ }
+
+}
diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelInvocationDefinitionSource.java b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelInvocationDefinitionSource.java
new file mode 100644
index 0000000000..603774e524
--- /dev/null
+++ b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelInvocationDefinitionSource.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2002-2008 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
+ *
+ * http://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.integration.security.channel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.springframework.integration.channel.MessageChannel;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.intercept.ObjectDefinitionSource;
+import org.springframework.util.Assert;
+
+/**
+ * The {@link ObjectDefinitionSource} implementation for secured {@link MessageChannel}s.
+ *
+ * @author Mark Fisher
+ */
+public class ChannelInvocationDefinitionSource implements ObjectDefinitionSource {
+
+ private final Map patternMappings =
+ new LinkedHashMap();
+
+
+ public void addPatternMapping(Pattern pattern, ChannelAccessPolicy accessPolicy) {
+ this.patternMappings.put(pattern, accessPolicy);
+ }
+
+ public Set getPatterns() {
+ return this.patternMappings.keySet();
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean supports(Class clazz) {
+ return ChannelInvocation.class.isAssignableFrom(clazz);
+ }
+
+ @SuppressWarnings("unchecked")
+ public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
+ Assert.isAssignable(ChannelInvocation.class, object.getClass());
+ ChannelInvocation invocation = (ChannelInvocation) object;
+ String channelName = invocation.getChannel().getName();
+ List attributes = new ArrayList();
+ for (Map.Entry mapping : this.patternMappings.entrySet()) {
+ Pattern pattern = mapping.getKey();
+ ChannelAccessPolicy accessPolicy = mapping.getValue();
+ if (pattern.matcher(channelName).matches()) {
+ if (invocation.isSend()) {
+ ConfigAttributeDefinition definition = accessPolicy.getConfigAttributeDefinitionForSend();
+ if (definition != null) {
+ attributes.addAll(definition.getConfigAttributes());
+ }
+ }
+ else if (invocation.isReceive()) {
+ ConfigAttributeDefinition definition = accessPolicy.getConfigAttributeDefinitionForReceive();
+ if (definition != null) {
+ attributes.addAll(definition.getConfigAttributes());
+ }
+ }
+ }
+ }
+ return new ConfigAttributeDefinition(attributes);
+ }
+
+ public Collection> getConfigAttributeDefinitions() {
+ Set definitions = new HashSet();
+ for (ChannelAccessPolicy accessPolicy : this.patternMappings.values()) {
+ ConfigAttributeDefinition sendDefinition = accessPolicy.getConfigAttributeDefinitionForSend();
+ if (sendDefinition != null) {
+ definitions.add(sendDefinition);
+ }
+ ConfigAttributeDefinition receiveDefinition = accessPolicy.getConfigAttributeDefinitionForReceive();
+ if (receiveDefinition != null) {
+ definitions.add(receiveDefinition);
+ }
+ }
+ return definitions;
+ }
+
+}
diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelSecurityInterceptor.java b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelSecurityInterceptor.java
new file mode 100644
index 0000000000..3d6728917c
--- /dev/null
+++ b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/ChannelSecurityInterceptor.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002-2008 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
+ *
+ * http://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.integration.security.channel;
+
+import java.lang.reflect.Method;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.security.intercept.AbstractSecurityInterceptor;
+import org.springframework.security.intercept.InterceptorStatusToken;
+import org.springframework.security.intercept.ObjectDefinitionSource;
+import org.springframework.util.Assert;
+
+/**
+ * An AOP interceptor that enforces authorization for MessageChannel send and/or receive calls.
+ *
+ * @author Mark Fisher
+ */
+public class ChannelSecurityInterceptor extends AbstractSecurityInterceptor implements MethodInterceptor {
+
+ private final ChannelInvocationDefinitionSource objectDefinitionSource;
+
+
+ public ChannelSecurityInterceptor(ChannelInvocationDefinitionSource objectDefinitionSource) {
+ Assert.notNull(objectDefinitionSource, "objectDefinitionSource must not be null");
+ this.objectDefinitionSource = objectDefinitionSource;
+ }
+
+
+ @Override
+ public Class> getSecureObjectClass() {
+ return ChannelInvocation.class;
+ }
+
+ @Override
+ public ObjectDefinitionSource obtainObjectDefinitionSource() {
+ return this.objectDefinitionSource;
+ }
+
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ Method method = invocation.getMethod();
+ if (method.getName().equals("send") || method.getName().equals("receive")) {
+ return this.invokeWithAuthorizationCheck(invocation);
+ }
+ return invocation.proceed();
+ }
+
+ private Object invokeWithAuthorizationCheck(MethodInvocation methodInvocation) throws Throwable {
+ Object returnValue = null;
+ InterceptorStatusToken token = super.beforeInvocation(new ChannelInvocation(methodInvocation));
+ try {
+ returnValue = methodInvocation.proceed();
+ }
+ finally {
+ returnValue = super.afterInvocation(token, returnValue);
+ }
+ return returnValue;
+ }
+
+}
diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/SecurityEnforcingChannelInterceptor.java b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/SecurityEnforcingChannelInterceptor.java
deleted file mode 100644
index eb84abb4ae..0000000000
--- a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/channel/SecurityEnforcingChannelInterceptor.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2002-2008 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
- *
- * http://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.integration.security.channel;
-
-import org.springframework.integration.channel.MessageChannel;
-import org.springframework.integration.channel.interceptor.ChannelInterceptorAdapter;
-import org.springframework.integration.message.Message;
-import org.springframework.security.AccessDecisionManager;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationCredentialsNotFoundException;
-import org.springframework.security.ConfigAttributeDefinition;
-import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.util.Assert;
-
-/**
- * Delegates to the provided instance of {@link AccessDecisionManager} to
- * enforce the security on the send and receive calls of the {@link MessageChannel}.
- *
- * @author Jonas Partner
- * @author Mark Fisher
- */
-public class SecurityEnforcingChannelInterceptor extends ChannelInterceptorAdapter {
-
- private final AccessDecisionManager accessDecisionManger;
-
- private volatile ConfigAttributeDefinition sendSecurityAttributes;
-
- private volatile ConfigAttributeDefinition receiveSecurityAttributes;
-
-
- public SecurityEnforcingChannelInterceptor(AccessDecisionManager accessDecisionManager) {
- Assert.notNull(accessDecisionManager, "AccessDecisionManager must not be null");
- this.accessDecisionManger = accessDecisionManager;
- }
-
-
- public ConfigAttributeDefinition getSendSecurityAttributes() {
- return this.sendSecurityAttributes;
- }
-
- public void setSendSecurityAttributes(ConfigAttributeDefinition sendSecurityAttributes) {
- this.sendSecurityAttributes = sendSecurityAttributes;
- }
-
- public ConfigAttributeDefinition getReceiveSecurityAttributes() {
- return this.receiveSecurityAttributes;
- }
-
- public void setReceiveSecurityAttributes(ConfigAttributeDefinition receiveSecurityAttributes) {
- this.receiveSecurityAttributes = receiveSecurityAttributes;
- }
-
- @Override
- public Message> preSend(Message> message, MessageChannel channel) {
- this.checkSend(channel);
- return message;
- }
-
- @Override
- public boolean preReceive(MessageChannel channel) {
- this.checkReceive(channel);
- return super.preReceive(channel);
- }
-
- private void checkSend(MessageChannel channel) {
- this.checkPermission(channel, this.sendSecurityAttributes);
- }
-
- private void checkReceive(MessageChannel channel) {
- this.checkPermission(channel, this.receiveSecurityAttributes);
- }
-
- private void checkPermission(MessageChannel messageChannel, ConfigAttributeDefinition securityAttributes) {
- if (securityAttributes != null) {
- Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
- if (authentication == null) {
- throw new AuthenticationCredentialsNotFoundException(
- "No Authentication object available. Consider enabling the SecurityPropagatingBeanPostProcessor.");
- }
- this.accessDecisionManger.decide(authentication, messageChannel, securityAttributes);
- }
- }
-
-}
diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorBeanPostProcessor.java b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorBeanPostProcessor.java
new file mode 100644
index 0000000000..a7f636817a
--- /dev/null
+++ b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorBeanPostProcessor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2002-2008 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
+ *
+ * http://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.integration.security.config;
+
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.integration.channel.MessageChannel;
+import org.springframework.integration.security.channel.ChannelInvocationDefinitionSource;
+import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
+import org.springframework.util.Assert;
+
+/**
+ * A {@link BeanPostProcessor} that proxies {@link MessageChannel}s to apply a {@link ChannelSecurityInterceptor}.
+ *
+ * @author Mark Fisher
+ */
+public class ChannelSecurityInterceptorBeanPostProcessor implements BeanPostProcessor {
+
+ private final ChannelSecurityInterceptor interceptor;
+
+
+ public ChannelSecurityInterceptorBeanPostProcessor(ChannelSecurityInterceptor interceptor) {
+ Assert.notNull(interceptor, "interceptor must not be null");
+ this.interceptor = interceptor;
+ }
+
+
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof MessageChannel && shouldProxy((MessageChannel) bean,
+ (ChannelInvocationDefinitionSource) this.interceptor.obtainObjectDefinitionSource())) {
+ ProxyFactory proxyFactory = new ProxyFactory(bean);
+ proxyFactory.addAdvisor(new DefaultPointcutAdvisor(this.interceptor));
+ return proxyFactory.getProxy();
+ }
+ return bean;
+ }
+
+ private boolean shouldProxy(MessageChannel channel, ChannelInvocationDefinitionSource definitionSource) {
+ Assert.notNull(channel.getName(), "channel name must not be null");
+ Set patterns = ((ChannelInvocationDefinitionSource) this.interceptor.obtainObjectDefinitionSource()).getPatterns();
+ for (Pattern pattern : patterns) {
+ if (pattern.matcher(channel.getName()).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/SecuredChannelsParser.java b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/SecuredChannelsParser.java
index 9ad93250b2..74ae346d31 100644
--- a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/SecuredChannelsParser.java
+++ b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/SecuredChannelsParser.java
@@ -16,34 +16,37 @@
package org.springframework.integration.security.config;
-import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Element;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.integration.security.ChannelInterceptorRegisteringBeanPostProcessor;
-import org.springframework.integration.security.channel.SecurityEnforcingChannelInterceptor;
-import org.springframework.security.ConfigAttributeDefinition;
-import org.springframework.security.context.SecurityContext;
+import org.springframework.integration.ConfigurationException;
+import org.springframework.integration.channel.MessageChannel;
+import org.springframework.integration.config.IntegrationNamespaceUtils;
+import org.springframework.integration.security.channel.ChannelAccessPolicy;
+import org.springframework.integration.security.channel.ChannelInvocationDefinitionSource;
+import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
import org.springframework.util.StringUtils;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
+import org.springframework.util.xml.DomUtils;
/**
- * Determines {@link SecurityContext} propagation behaviour for the parent
- * element channel, and creates a {@link SecurityEnforcingChannelInterceptor} to
- * control send and receive access if send-access and/or receive-access is
- * specified.
+ * Creates a {@link ChannelSecurityInterceptor} to control send and receive access,
+ * and creates a {@link ChannelSecurityInterceptorBeanPostProcessor} to apply the
+ * interceptor to {@link MessageChannel}s whose names match the specified patterns.
*
* @author Jonas Partner
+ * @author Mark Fisher
*/
public class SecuredChannelsParser extends AbstractSingleBeanDefinitionParser {
- public SecuredChannelsParser() {
- super();
+ @Override
+ protected Class> getBeanClass(Element element) {
+ return ChannelSecurityInterceptorBeanPostProcessor.class;
}
@Override
@@ -51,61 +54,33 @@ public class SecuredChannelsParser extends AbstractSingleBeanDefinitionParser {
return true;
}
- @Override
- protected boolean shouldGenerateIdAsFallback() {
- return true;
- }
-
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
- String receiveAccess = element.getAttribute("receive-access");
- String sendAccess = element.getAttribute("send-access");
- String accessDecisionManager = element.getAttribute("access-decision-manager");
-
- BeanDefinition interceptorBeanDefinition = createSecurityEnforcingChannelInterceptor(accessDecisionManager,
- sendAccess, receiveAccess);
-
- List patternList = processPatterns(element.getElementsByTagNameNS(element.getNamespaceURI(),
- "channel-name-pattern"));
-
- builder.getBeanDefinition().setBeanClass(ChannelInterceptorRegisteringBeanPostProcessor.class);
- builder.getBeanDefinition().getConstructorArgumentValues().addGenericArgumentValue(
- new ValueHolder(interceptorBeanDefinition));
- builder.getBeanDefinition().getConstructorArgumentValues()
- .addGenericArgumentValue(new ValueHolder(patternList));
-
+ ChannelInvocationDefinitionSource objectDefinitionSource = this.parseObjectDefinitionSource(element);
+ BeanDefinitionBuilder interceptorBuilder = BeanDefinitionBuilder.genericBeanDefinition(ChannelSecurityInterceptor.class);
+ interceptorBuilder.addConstructorArgValue(objectDefinitionSource);
+ IntegrationNamespaceUtils.setReferenceIfAttributeDefined(interceptorBuilder, element, "authentication-manager");
+ IntegrationNamespaceUtils.setReferenceIfAttributeDefined(interceptorBuilder, element, "access-decision-manager");
+ String interceptorBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(
+ interceptorBuilder.getBeanDefinition(), parserContext.getRegistry());
+ builder.addConstructorArgReference(interceptorBeanName);
}
- protected List processPatterns(NodeList patternList) {
- List patterns = new ArrayList();
- for (int i = 0; i < patternList.getLength(); i++) {
- Element patternElement = (Element) patternList.item(i);
- patterns.add(patternElement.getTextContent());
- }
- return patterns;
- }
- protected BeanDefinition createSecurityEnforcingChannelInterceptor(String accessDecisionManager, String sendAccess,
- String receiveAccess) {
- if (!StringUtils.hasText(accessDecisionManager)) {
- accessDecisionManager = "accessDecisionManager";
+ @SuppressWarnings("unchecked")
+ private ChannelInvocationDefinitionSource parseObjectDefinitionSource(Element element) {
+ ChannelInvocationDefinitionSource objectDefinitionSource = new ChannelInvocationDefinitionSource();
+ List accessPolicyElements = (List) DomUtils.getChildElementsByTagName(element, "access-policy");
+ for (Element accessPolicyElement : accessPolicyElements) {
+ Pattern pattern = Pattern.compile(accessPolicyElement.getAttribute("pattern"));
+ String sendAccess = accessPolicyElement.getAttribute("send-access");
+ String receiveAccess = accessPolicyElement.getAttribute("receive-access");
+ if (!StringUtils.hasText(sendAccess) && !StringUtils.hasText(receiveAccess)) {
+ throw new ConfigurationException("At least one of 'send-access' or 'receive-access' must be provided.");
+ }
+ objectDefinitionSource.addPatternMapping(pattern, new ChannelAccessPolicy(sendAccess, receiveAccess));
}
- BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
- .genericBeanDefinition(SecurityEnforcingChannelInterceptor.class);
- beanDefinitionBuilder.addConstructorArgReference(accessDecisionManager);
-
- if (StringUtils.hasText(sendAccess)) {
- ConfigAttributeDefinition sendDefinition = new ConfigAttributeDefinition(StringUtils.tokenizeToStringArray(
- sendAccess, ","));
- beanDefinitionBuilder.addPropertyValue("sendSecurityAttributes", sendDefinition);
- }
- if (StringUtils.hasText(receiveAccess)) {
- ConfigAttributeDefinition receiveDefinition = new ConfigAttributeDefinition(StringUtils
- .tokenizeToStringArray(receiveAccess, ","));
- beanDefinitionBuilder.addPropertyValue("receiveSecurityAttributes", receiveDefinition);
- }
- return beanDefinitionBuilder.getBeanDefinition();
-
+ return objectDefinitionSource;
}
}
diff --git a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/spring-integration-security-1.0.xsd b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/spring-integration-security-1.0.xsd
index b15fb1f8f0..3fe6054ec9 100644
--- a/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/spring-integration-security-1.0.xsd
+++ b/org.springframework.integration.security/src/main/java/org/springframework/integration/security/config/spring-integration-security-1.0.xsd
@@ -1,10 +1,9 @@
-
-
@@ -18,14 +17,24 @@
-
+
-
-
+
+
+
+
+ Defines the security access policy for send and/or receive invocations based on a Message Channel name pattern.
+
+
+
+
+
+
+
diff --git a/org.springframework.integration.security/src/main/resources/META-INF/spring.handlers b/org.springframework.integration.security/src/main/resources/META-INF/spring.handlers
index 340dbcfb29..9ee913c503 100644
--- a/org.springframework.integration.security/src/main/resources/META-INF/spring.handlers
+++ b/org.springframework.integration.security/src/main/resources/META-INF/spring.handlers
@@ -1 +1 @@
-http\://www.springframework.org/schema/integration-security=org.springframework.integration.security.config.IntegrationSecurityNamespaceHandler
\ No newline at end of file
+http\://www.springframework.org/schema/integration/security=org.springframework.integration.security.config.IntegrationSecurityNamespaceHandler
\ No newline at end of file
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelAdapterSecurityIntegrationTests-context.xml b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelAdapterSecurityIntegrationTests-context.xml
index 03cce3b527..35a983afb8 100644
--- a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelAdapterSecurityIntegrationTests-context.xml
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelAdapterSecurityIntegrationTests-context.xml
@@ -1,26 +1,30 @@
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+ http://www.springframework.org/schema/security
+ http://www.springframework.org/schema/security/spring-security-2.0.xsd
+ http://www.springframework.org/schema/integration
+ http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
+ http://www.springframework.org/schema/integration/security
+ http://www.springframework.org/schema/integration/spring-integration-security-1.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-2.5.xsd">
-
- secured.*
+
+
-
+
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorBeanPostProcessorTests.java b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorBeanPostProcessorTests.java
new file mode 100644
index 0000000000..b6f867b30c
--- /dev/null
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorBeanPostProcessorTests.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2002-2008 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
+ *
+ * http://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.integration.security.channel;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.integration.channel.MessageChannel;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.security.config.ChannelSecurityInterceptorBeanPostProcessor;
+
+/**
+ * @author Mark Fisher
+ */
+public class ChannelSecurityInterceptorBeanPostProcessorTests {
+
+ @Test
+ public void securedChannelIsProxied() {
+ ChannelInvocationDefinitionSource objectDefinitionSource = new ChannelInvocationDefinitionSource();
+ objectDefinitionSource.addPatternMapping(Pattern.compile("secured.*"), new ChannelAccessPolicy("ROLE_ADMIN", null));
+ ChannelSecurityInterceptor interceptor = new ChannelSecurityInterceptor(objectDefinitionSource);
+ ChannelSecurityInterceptorBeanPostProcessor postProcessor = new ChannelSecurityInterceptorBeanPostProcessor(interceptor);
+ QueueChannel securedChannel = new QueueChannel();
+ securedChannel.setBeanName("securedChannel");
+ MessageChannel postProcessedChannel = (MessageChannel) postProcessor.postProcessAfterInitialization(securedChannel, "securedChannel");
+ assertTrue(AopUtils.isAopProxy(postProcessedChannel));
+ }
+
+ @Test
+ public void nonsecuredChannelIsNotProxied() {
+ ChannelInvocationDefinitionSource objectDefinitionSource = new ChannelInvocationDefinitionSource();
+ objectDefinitionSource.addPatternMapping(Pattern.compile("secured.*"), new ChannelAccessPolicy("ROLE_ADMIN", null));
+ ChannelSecurityInterceptor interceptor = new ChannelSecurityInterceptor(objectDefinitionSource);
+ ChannelSecurityInterceptorBeanPostProcessor postProcessor = new ChannelSecurityInterceptorBeanPostProcessor(interceptor);
+ QueueChannel channel = new QueueChannel();
+ channel.setBeanName("testChannel");
+ MessageChannel postProcessedChannel = (MessageChannel) postProcessor.postProcessAfterInitialization(channel, "testChannel");
+ assertFalse(AopUtils.isAopProxy(postProcessedChannel));
+ }
+
+}
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorTests.java b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorTests.java
new file mode 100644
index 0000000000..41b3f10e97
--- /dev/null
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorTests.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2002-2008 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
+ *
+ * http://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.integration.security.channel;
+
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+import org.junit.After;
+import org.junit.Test;
+
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.integration.channel.MessageChannel;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.message.StringMessage;
+import org.springframework.integration.security.SecurityTestUtil;
+import org.springframework.security.AccessDeniedException;
+import org.springframework.security.AuthenticationException;
+import org.springframework.security.MockAuthenticationManager;
+import org.springframework.security.context.SecurityContext;
+import org.springframework.security.context.SecurityContextHolder;
+import org.springframework.security.vote.AffirmativeBased;
+import org.springframework.security.vote.RoleVoter;
+
+/**
+ * @author Mark Fisher
+ */
+public class ChannelSecurityInterceptorTests {
+
+ @After
+ public void clearSecurityContext() {
+ SecurityContextHolder.clearContext();
+ }
+
+ @Test(expected = AuthenticationException.class)
+ public void securedSendWithoutAuthentication() throws Exception {
+ MessageChannel channel = getSecuredChannel("ROLE_ADMIN");
+ channel.send(new StringMessage("test"));
+ }
+
+ @Test(expected = AccessDeniedException.class)
+ public void securedSendWithoutRole() throws Exception {
+ MessageChannel channel = getSecuredChannel("ROLE_ADMIN");
+ SecurityContext context = SecurityTestUtil.createContext("test", "pwd", "ROLE_USER");
+ SecurityContextHolder.setContext(context);
+ channel.send(new StringMessage("test"));
+ }
+
+ @Test
+ public void securedSendWithRole() throws Exception {
+ MessageChannel channel = getSecuredChannel("ROLE_ADMIN");
+ SecurityContext context = SecurityTestUtil.createContext("test", "pwd", "ROLE_ADMIN");
+ SecurityContextHolder.setContext(context);
+ channel.send(new StringMessage("test"));
+ }
+
+
+ private static MessageChannel getSecuredChannel(String role) throws Exception {
+ QueueChannel channel = new QueueChannel();
+ channel.setBeanName("securedChannel");
+ ProxyFactory proxyFactory = new ProxyFactory(channel);
+ proxyFactory.addAdvice(createInterceptor(role));
+ return (MessageChannel) proxyFactory.getProxy();
+ }
+
+ private static ChannelSecurityInterceptor createInterceptor(String role) throws Exception {
+ ChannelInvocationDefinitionSource objectDefinitionSource = new ChannelInvocationDefinitionSource();
+ objectDefinitionSource.addPatternMapping(Pattern.compile("secured.*"), new ChannelAccessPolicy(role, null));
+ ChannelSecurityInterceptor interceptor = new ChannelSecurityInterceptor(objectDefinitionSource);
+ AffirmativeBased accessDecisionManager = new AffirmativeBased();
+ accessDecisionManager.setDecisionVoters(Collections.singletonList(new RoleVoter()));
+ accessDecisionManager.afterPropertiesSet();
+ interceptor.setAccessDecisionManager(accessDecisionManager);
+ interceptor.setAuthenticationManager(new MockAuthenticationManager(true));
+ interceptor.afterPropertiesSet();
+ return interceptor;
+ }
+
+}
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/SecurityEnforcingChannelInterceptorTests.java b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/SecurityEnforcingChannelInterceptorTests.java
deleted file mode 100644
index 48a3c94f4a..0000000000
--- a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/channel/SecurityEnforcingChannelInterceptorTests.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2002-2008 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
- *
- * http://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.integration.security.channel;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import org.springframework.integration.channel.QueueChannel;
-import org.springframework.integration.message.StringMessage;
-import org.springframework.integration.security.channel.SecurityEnforcingChannelInterceptor;
-import org.springframework.security.AccessDecisionManager;
-import org.springframework.security.AccessDeniedException;
-import org.springframework.security.Authentication;
-import org.springframework.security.ConfigAttribute;
-import org.springframework.security.ConfigAttributeDefinition;
-import org.springframework.security.GrantedAuthorityImpl;
-import org.springframework.security.InsufficientAuthenticationException;
-import org.springframework.security.context.SecurityContextHolder;
-import org.springframework.security.providers.TestingAuthenticationToken;
-
-/**
- * @author Jonas Partner
- */
-public class SecurityEnforcingChannelInterceptorTests {
-
- private QueueChannel channel;
-
- private SecurityEnforcingChannelInterceptor securityChannelInterceptor;
-
-
- @Before
- public void setUp() {
- channel = new QueueChannel();
- SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(
- "stub", "passwd", new GrantedAuthorityImpl[] {}));
- }
-
- @After
- public void clearSecurityContext(){
- SecurityContextHolder.clearContext();
- }
-
- @Test(expected = AccessDeniedException.class)
- public void testSendSecuredAndAccessDenied() {
- try {
- Runnable decision = new Runnable() {
- public void run() {
- throw new AccessDeniedException("nope");
- }
- };
- this.registerInterceptor(new ConfigurableAccessDecisionManager(decision));
- this.securityChannelInterceptor.setSendSecurityAttributes(new ConfigAttributeDefinition("ROLE_ADMIN"));
- this.channel.send(new StringMessage("test"));
- }
- finally {
- assertEquals("Wrong message count after refused send.", 0, channel.clear().size());
- }
- }
-
- @Test
- public void testUnsecuredSend() {
- this.registerInterceptor(new ConfigurableAccessDecisionManager(null));
- this.channel.send(new StringMessage("test"));
- assertEquals("Wrong message count after send.", 1,channel.clear().size());
- }
-
- @Test
- public void testSendSecuredAndAllowed() {
- Runnable decision = new Runnable() {
- public void run() {
- }
- };
- this.registerInterceptor(new ConfigurableAccessDecisionManager(decision));
- this.securityChannelInterceptor.setSendSecurityAttributes(new ConfigAttributeDefinition("ROLE_ADMIN"));
- this.channel.send(new StringMessage("test"));
- assertEquals("Wrong message count after send", 1, channel.clear().size());
- }
-
- @Test
- public void testReceiveSecuredAndAllowed() {
- Runnable decision = new Runnable() {
- public void run() {
- }
- };
- this.registerInterceptor(new ConfigurableAccessDecisionManager(decision));
- this.securityChannelInterceptor.setReceiveSecurityAttributes(new ConfigAttributeDefinition("ROLE_ADMIN"));
- this.channel.receive(0);
- }
-
- @Test(expected = AccessDeniedException.class)
- public void testReceiveSecuredAndAccessDenied() {
- Runnable decision = new Runnable() {
- public void run() {
- throw new AccessDeniedException("nope");
- }
- };
- this.registerInterceptor(new ConfigurableAccessDecisionManager(decision));
- this.securityChannelInterceptor.setReceiveSecurityAttributes(new ConfigAttributeDefinition("ROLE_ADMIN"));
- this.channel.receive(0);
- }
-
- @Test
- public void testReceiveUnsecured() {
- Runnable decision = new Runnable() {
- public void run() {
- throw new AccessDeniedException("nope");
- }
- };
- this.registerInterceptor(new ConfigurableAccessDecisionManager(decision));
- this.channel.receive(0);
- }
-
-
- private void registerInterceptor(AccessDecisionManager accessDecisionManager) {
- securityChannelInterceptor = new SecurityEnforcingChannelInterceptor(accessDecisionManager);
- channel.addInterceptor(securityChannelInterceptor);
- }
-
-
- private static class ConfigurableAccessDecisionManager implements AccessDecisionManager {
-
- private Runnable decisionRunner;
-
- public ConfigurableAccessDecisionManager(Runnable decision) {
- this.decisionRunner = decision;
- }
-
- public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)
- throws AccessDeniedException, InsufficientAuthenticationException {
- this.decisionRunner.run();
- }
-
- public boolean supports(ConfigAttribute attribute) {
- return true;
- }
-
- @SuppressWarnings("unchecked")
- public boolean supports(Class clazz) {
- return true;
- }
- }
-
-}
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests-context.xml b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests-context.xml
index ab678e83c0..ece1a49cdb 100644
--- a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests-context.xml
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests-context.xml
@@ -1,36 +1,29 @@
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+ http://www.springframework.org/schema/security
+ http://www.springframework.org/schema/security/spring-security-2.0.xsd
+ http://www.springframework.org/schema/integration
+ http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
+ http://www.springframework.org/schema/integration/security
+ http://www.springframework.org/schema/integration/spring-integration-security-1.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-2.5.xsd">
-
- adminRequiredForSend
+
+
+
+
+
+
-
- adminOrUserRequiredForSend
-
-
-
- adminRequiredForReceive
-
-
-
- adminOrUserRequiredForReceive
-
-
-
- adminForSendAndReceive
-
-
-
\ No newline at end of file
+
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests.java b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests.java
index 39db3112db..ee28a85dc0 100644
--- a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests.java
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecuredChannelsParserTests.java
@@ -16,25 +16,42 @@
package org.springframework.integration.security.config;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
import org.junit.Before;
import org.junit.Test;
+import org.springframework.aop.Advisor;
+import org.springframework.aop.framework.Advised;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.DirectFieldAccessor;
import org.springframework.integration.channel.AbstractPollableChannel;
import org.springframework.integration.channel.ChannelInterceptor;
+import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.selector.MessageSelector;
-import org.springframework.integration.security.channel.SecurityEnforcingChannelInterceptor;
-import org.springframework.security.SecurityConfig;
+import org.springframework.integration.security.channel.ChannelAccessPolicy;
+import org.springframework.integration.security.channel.ChannelInvocationDefinitionSource;
+import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
+import org.springframework.security.ConfigAttribute;
+import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
/**
* @author Jonas Partner
+ * @author Mark Fisher
*/
@ContextConfiguration
public class SecuredChannelsParserTests extends AbstractJUnit4SpringContextTests {
@@ -48,67 +65,125 @@ public class SecuredChannelsParserTests extends AbstractJUnit4SpringContextTests
@Test
public void testAdminRequiredForSend() {
- applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(messageChannel,
- "adminRequiredForSend");
- assertEquals("Wrong count of interceptors ", 1, messageChannel.interceptors.size());
- SecurityEnforcingChannelInterceptor interceptor = (SecurityEnforcingChannelInterceptor) messageChannel.interceptors
- .get(0);
- assertTrue("ROLE_ADMIN not found as send attribute", interceptor.getSendSecurityAttributes().contains(
- new SecurityConfig("ROLE_ADMIN")));
- assertNull("Receive security attribute were not null", interceptor.getReceiveSecurityAttributes());
+ String beanName = "adminRequiredForSend";
+ messageChannel.setBeanName(beanName);
+ MessageChannel proxy = (MessageChannel) applicationContext.getAutowireCapableBeanFactory()
+ .applyBeanPostProcessorsAfterInitialization(messageChannel, beanName);
+ assertTrue("Channel was not proxied", AopUtils.isAopProxy(proxy));
+ Advisor[] advisors = ((Advised) proxy).getAdvisors();
+ assertEquals("Wrong number of interceptors", 1, advisors.length);
+ ChannelSecurityInterceptor interceptor = (ChannelSecurityInterceptor) advisors[0].getAdvice();
+ ChannelAccessPolicy policy = this.retrievePolicyForPatternString(beanName, interceptor);
+ assertNotNull("Pattern '" + beanName + "' is not included in mappings", policy);
+ ConfigAttributeDefinition sendDefinition = policy.getConfigAttributeDefinitionForSend();
+ ConfigAttributeDefinition receiveDefinition = policy.getConfigAttributeDefinitionForReceive();
+ assertTrue("ROLE_ADMIN not found as send attribute", this.getRolesFromDefintion(sendDefinition).contains("ROLE_ADMIN"));
+ assertNull("Policy applies to receive", receiveDefinition);
}
@Test
public void testAdminOrUserRequiredForSend() {
- applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(messageChannel,
- "adminOrUserRequiredForSend");
- assertEquals("Wrong count of interceptors ", 1, messageChannel.interceptors.size());
- SecurityEnforcingChannelInterceptor interceptor = (SecurityEnforcingChannelInterceptor) messageChannel.interceptors
- .get(0);
- assertTrue("ROLE_ADMIN not found as send attribute", interceptor.getSendSecurityAttributes().contains(
- new SecurityConfig("ROLE_ADMIN")));
- assertTrue("ROLE_USER not found as send attribute", interceptor.getSendSecurityAttributes().contains(
- new SecurityConfig("ROLE_USER")));
- assertNull("Receive security attribute were not null", interceptor.getReceiveSecurityAttributes());
+ String beanName = "adminOrUserRequiredForSend";
+ messageChannel.setBeanName(beanName);
+ MessageChannel proxy = (MessageChannel) applicationContext.getAutowireCapableBeanFactory()
+ .applyBeanPostProcessorsAfterInitialization(messageChannel, beanName);
+ assertTrue("Channel was not proxied", AopUtils.isAopProxy(proxy));
+ Advisor[] advisors = ((Advised) proxy).getAdvisors();
+ assertEquals("Wrong number of interceptors", 1, advisors.length);
+ ChannelSecurityInterceptor interceptor = (ChannelSecurityInterceptor) advisors[0].getAdvice();
+ ChannelAccessPolicy policy = this.retrievePolicyForPatternString(beanName, interceptor);
+ assertNotNull("Pattern '" + beanName + "' is not included in mappings", policy);
+ ConfigAttributeDefinition sendDefinition = policy.getConfigAttributeDefinitionForSend();
+ ConfigAttributeDefinition receiveDefinition = policy.getConfigAttributeDefinitionForReceive();
+ Collection sendRoles = this.getRolesFromDefintion(sendDefinition);
+ assertTrue("ROLE_ADMIN not found as send attribute", sendRoles.contains("ROLE_ADMIN"));
+ assertTrue("ROLE_USER not found as send attribute", sendRoles.contains("ROLE_USER"));
+ assertNull("Policy applies to receive", receiveDefinition);
}
@Test
public void testAdminRequiredForReceive() {
- applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(messageChannel,
- "adminRequiredForReceive");
- assertEquals("Wrong count of interceptors ", 1, messageChannel.interceptors.size());
- SecurityEnforcingChannelInterceptor interceptor = (SecurityEnforcingChannelInterceptor) messageChannel.interceptors
- .get(0);
- assertTrue("ROLE_ADMIN not found as receive attribute", interceptor.getReceiveSecurityAttributes().contains(
- new SecurityConfig("ROLE_ADMIN")));
- assertNull("Send security attribute were not null", interceptor.getSendSecurityAttributes());
+ String beanName = "adminRequiredForReceive";
+ messageChannel.setBeanName(beanName);
+ MessageChannel proxy = (MessageChannel) applicationContext.getAutowireCapableBeanFactory()
+ .applyBeanPostProcessorsAfterInitialization(messageChannel, beanName);
+ assertTrue("Channel was not proxied", AopUtils.isAopProxy(proxy));
+ Advisor[] advisors = ((Advised) proxy).getAdvisors();
+ assertEquals("Wrong number of interceptors", 1, advisors.length);
+ ChannelSecurityInterceptor interceptor = (ChannelSecurityInterceptor) advisors[0].getAdvice();
+ ChannelAccessPolicy policy = this.retrievePolicyForPatternString(beanName, interceptor);
+ assertNotNull("Pattern '" + beanName + "' is not included in mappings", policy);
+ ConfigAttributeDefinition sendDefinition = policy.getConfigAttributeDefinitionForSend();
+ ConfigAttributeDefinition receiveDefinition = policy.getConfigAttributeDefinitionForReceive();
+ Collection receiveRoles = this.getRolesFromDefintion(receiveDefinition);
+ assertTrue("ROLE_ADMIN not found as receive attribute", receiveRoles.contains("ROLE_ADMIN"));
+ assertNull("Policy applies to send", sendDefinition);
}
@Test
public void testAdminOrUserRequiredForReceive() {
- applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(messageChannel,
- "adminOrUserRequiredForReceive");
- assertEquals("Wrong count of interceptors ", 1, messageChannel.interceptors.size());
- SecurityEnforcingChannelInterceptor interceptor = (SecurityEnforcingChannelInterceptor) messageChannel.interceptors
- .get(0);
- assertTrue("ROLE_ADMIN not found as receive attribute", interceptor.getReceiveSecurityAttributes().contains(
- new SecurityConfig("ROLE_ADMIN")));
- assertTrue("ROLE_USER not found as receive attribute", interceptor.getReceiveSecurityAttributes().contains(
- new SecurityConfig("ROLE_USER")));
- assertNull("Send security attribute were not null", interceptor.getSendSecurityAttributes());
+ String beanName = "adminOrUserRequiredForReceive";
+ messageChannel.setBeanName(beanName);
+ MessageChannel proxy = (MessageChannel) applicationContext.getAutowireCapableBeanFactory()
+ .applyBeanPostProcessorsAfterInitialization(messageChannel, beanName);
+ assertTrue("Channel was not proxied", AopUtils.isAopProxy(proxy));
+ Advisor[] advisors = ((Advised) proxy).getAdvisors();
+ assertEquals("Wrong number of interceptors", 1, advisors.length);
+ ChannelSecurityInterceptor interceptor = (ChannelSecurityInterceptor) advisors[0].getAdvice();
+ ChannelAccessPolicy policy = this.retrievePolicyForPatternString(beanName, interceptor);
+ assertNotNull("Pattern '" + beanName + "' is not included in mappings", policy);
+ ConfigAttributeDefinition sendDefinition = policy.getConfigAttributeDefinitionForSend();
+ ConfigAttributeDefinition receiveDefinition = policy.getConfigAttributeDefinitionForReceive();
+ Collection receiveRoles = this.getRolesFromDefintion(receiveDefinition);
+ assertTrue("ROLE_ADMIN not found as receive attribute", receiveRoles.contains("ROLE_ADMIN"));
+ assertTrue("ROLE_USER not found as receive attribute", receiveRoles.contains("ROLE_USER"));
+ assertNull("Policy applies to send", sendDefinition);
}
@Test
public void testAdminRequiredForSendAndReceive() {
- applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(messageChannel,
- "adminForSendAndReceive");
- assertEquals("Wrong count of interceptors ", 1, messageChannel.interceptors.size());
- SecurityEnforcingChannelInterceptor interceptor = (SecurityEnforcingChannelInterceptor) messageChannel.interceptors
- .get(0);
- assertTrue("ROLE_ADMIN not found as receive attribute", interceptor.getReceiveSecurityAttributes().contains(
- new SecurityConfig("ROLE_ADMIN")));
- assertTrue("ROLE_USER not found as send attribute", interceptor.getSendSecurityAttributes().contains(
- new SecurityConfig("ROLE_ADMIN")));
+ String beanName = "adminRequiredForSendAndReceive";
+ messageChannel.setBeanName(beanName);
+ MessageChannel proxy = (MessageChannel) applicationContext.getAutowireCapableBeanFactory()
+ .applyBeanPostProcessorsAfterInitialization(messageChannel, beanName);
+ assertTrue("Channel was not proxied", AopUtils.isAopProxy(proxy));
+ Advisor[] advisors = ((Advised) proxy).getAdvisors();
+ assertEquals("Wrong number of interceptors", 1, advisors.length);
+ ChannelSecurityInterceptor interceptor = (ChannelSecurityInterceptor) advisors[0].getAdvice();
+ ChannelAccessPolicy policy = this.retrievePolicyForPatternString(beanName, interceptor);
+ assertNotNull("Pattern '" + beanName + "' is not included in mappings", policy);
+ ConfigAttributeDefinition sendDefinition = policy.getConfigAttributeDefinitionForSend();
+ ConfigAttributeDefinition receiveDefinition = policy.getConfigAttributeDefinitionForReceive();
+ assertNotNull("Pattern does not apply to 'send'", sendDefinition);
+ assertNotNull("Pattern does not apply to 'receive'", receiveDefinition);
+ Collection sendRoles = this.getRolesFromDefintion(sendDefinition);
+ Collection receiveRoles = this.getRolesFromDefintion(receiveDefinition);
+ assertTrue("ROLE_ADMIN not found in send attributes", sendRoles.contains("ROLE_ADMIN"));
+ assertTrue("ROLE_ADMIN not found in receive attributes", receiveRoles.contains("ROLE_ADMIN"));
+ }
+
+
+ @SuppressWarnings("unchecked")
+ private ChannelAccessPolicy retrievePolicyForPatternString(String patternString, ChannelSecurityInterceptor interceptor) {
+ DirectFieldAccessor accessor = new DirectFieldAccessor((ChannelInvocationDefinitionSource) interceptor.obtainObjectDefinitionSource());
+ Map policies = (Map) accessor.getPropertyValue("patternMappings");
+ for (Map.Entry entry : policies.entrySet()) {
+ if (entry.getKey().pattern().equals(patternString)) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Collection getRolesFromDefintion(ConfigAttributeDefinition definition) {
+ Set roles = new HashSet();
+ Collection configAttributes = definition.getConfigAttributes();
+ for (Object next : configAttributes) {
+ ConfigAttribute attribute = (ConfigAttribute) next;
+ roles.add(attribute.getAttribute());
+ }
+ return roles;
}
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecurityPropagatingChannelsParserTests-noPropagationByDefaultContext.xml b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecurityPropagatingChannelsParserTests-noPropagationByDefaultContext.xml
index 05b56af744..7e69006344 100644
--- a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecurityPropagatingChannelsParserTests-noPropagationByDefaultContext.xml
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/SecurityPropagatingChannelsParserTests-noPropagationByDefaultContext.xml
@@ -1,6 +1,6 @@
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/commonSecurityConfiguration.xml b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/commonSecurityConfiguration.xml
index 38dcb8617a..af53461114 100644
--- a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/commonSecurityConfiguration.xml
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/config/commonSecurityConfiguration.xml
@@ -11,6 +11,8 @@
+
+
diff --git a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/endpoint/EndpointSecurityIntegrationTests-context.xml b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/endpoint/EndpointSecurityIntegrationTests-context.xml
index 94a4a54f0d..ba6b88dbcc 100644
--- a/org.springframework.integration.security/src/test/java/org/springframework/integration/security/endpoint/EndpointSecurityIntegrationTests-context.xml
+++ b/org.springframework.integration.security/src/test/java/org/springframework/integration/security/endpoint/EndpointSecurityIntegrationTests-context.xml
@@ -1,6 +1,6 @@