();
+ for (String receiveAccessValue : receiveAccess) {
+ configAttributeDefinitionForReceive.add(new SecurityConfig(receiveAccessValue));
+ }
+ }
+ else {
+ configAttributeDefinitionForReceive = Collections.emptySet();
}
}
diff --git a/spring-integration-security/src/main/java/org/springframework/integration/security/channel/SecuredChannel.java b/spring-integration-security/src/main/java/org/springframework/integration/security/channel/SecuredChannel.java
new file mode 100644
index 0000000000..4a9c551cb4
--- /dev/null
+++ b/spring-integration-security/src/main/java/org/springframework/integration/security/channel/SecuredChannel.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 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.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation to be applied for the {@link org.springframework.messaging.MessageChannel} bean definition
+ * from JavaConfig - on {@link @Bean} method level.
+ *
+ * Applies the {@link ChannelSecurityInterceptor}(s) using provided {@link #interceptor()} bean name(s).
+ *
+ * The {@link #sendAccess()} and {@link #receiveAccess()} policies are populated to the
+ * {@link ChannelSecurityInterceptor}(s) from the {@code ChannelSecurityInterceptorBeanPostProcessor}.
+ *
+ * @author Artem Bilan
+ * @since 4.2
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SecuredChannel {
+
+ String[] interceptor();
+
+ String[] sendAccess() default {};
+
+ String[] receiveAccess() default {};
+
+}
diff --git a/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorBeanPostProcessor.java b/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorBeanPostProcessor.java
index 1e590d5d4e..2d77084777 100644
--- a/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorBeanPostProcessor.java
+++ b/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorBeanPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -16,16 +16,19 @@
package org.springframework.integration.security.config;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
-import org.springframework.aop.framework.Advised;
-import org.springframework.aop.framework.ProxyFactory;
-import org.springframework.aop.support.AopUtils;
-import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.aop.Advisor;
+import org.springframework.aop.TargetSource;
+import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
+import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.integration.security.channel.ChannelAccessPolicy;
import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
import org.springframework.integration.security.channel.ChannelSecurityMetadataSource;
import org.springframework.messaging.MessageChannel;
@@ -37,40 +40,61 @@ import org.springframework.messaging.MessageChannel;
* @author Oleg Zhurakousky
* @author Artem Bilan
*/
-public class ChannelSecurityInterceptorBeanPostProcessor implements BeanPostProcessor {
+@SuppressWarnings("serial")
+public class ChannelSecurityInterceptorBeanPostProcessor extends AbstractAutoProxyCreator {
- private final Collection securityInterceptors;
+ private final Map> securityInterceptorMappings;
- public ChannelSecurityInterceptorBeanPostProcessor(Collection securityInterceptors) {
- this.securityInterceptors = securityInterceptors;
+ private final Map> accessPolicyMapping;
+
+ public ChannelSecurityInterceptorBeanPostProcessor(Map> securityInterceptorMappings) {
+ this(securityInterceptorMappings, null);
}
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- return bean;
+ public ChannelSecurityInterceptorBeanPostProcessor(Map> securityInterceptorMappings,
+ Map> accessPolicyMapping) {
+ this.securityInterceptorMappings = securityInterceptorMappings;//NOSONAR (inconsistent sync)
+ this.accessPolicyMapping = accessPolicyMapping;//NOSONAR (inconsistent sync)
}
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof MessageChannel) {
- for (ChannelSecurityInterceptor securityInterceptor : this.securityInterceptors) {
- ChannelSecurityMetadataSource channelSecurityMetadataSource =
- (ChannelSecurityMetadataSource) securityInterceptor.obtainSecurityMetadataSource();
- if (this.shouldProxy(beanName, channelSecurityMetadataSource)) {
- if (AopUtils.isAopProxy(bean) && bean instanceof Advised) {
- ((Advised) bean).addAdvisor(new DefaultPointcutAdvisor(securityInterceptor));
- }
- else {
- ProxyFactory proxyFactory = new ProxyFactory(bean);
- proxyFactory.addAdvisor(new DefaultPointcutAdvisor(securityInterceptor));
- bean = proxyFactory.getProxy();
- }
- }
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) {
+ if (this.accessPolicyMapping != null
+ && bean instanceof ChannelSecurityInterceptor
+ && accessPolicyMapping.containsKey(beanName)) {
+ Map accessPolicies = this.accessPolicyMapping.get(beanName);
+ ChannelSecurityMetadataSource securityMetadataSource =
+ (ChannelSecurityMetadataSource) ((ChannelSecurityInterceptor) bean).obtainSecurityMetadataSource();
+ for (Map.Entry entry : accessPolicies.entrySet()) {
+ securityMetadataSource.addPatternMapping(entry.getKey(), entry.getValue());
}
}
return bean;
}
- private boolean shouldProxy(String beanName, ChannelSecurityMetadataSource channelSecurityMetadataSource) {
- Set patterns = channelSecurityMetadataSource.getPatterns();
+ @Override
+ protected Object[] getAdvicesAndAdvisorsForBean(Class> beanClass, String beanName,
+ TargetSource customTargetSource) throws BeansException {
+ if (MessageChannel.class.isAssignableFrom(beanClass)) {
+ List interceptors = new ArrayList();
+ for (Map.Entry> entry : this.securityInterceptorMappings.entrySet()) {
+ if (isMatch(beanName, entry.getValue())) {
+ DefaultBeanFactoryPointcutAdvisor channelSecurityInterceptor
+ = new DefaultBeanFactoryPointcutAdvisor();
+ channelSecurityInterceptor.setAdviceBeanName(entry.getKey());
+ channelSecurityInterceptor.setBeanFactory(getBeanFactory());
+ interceptors.add(channelSecurityInterceptor);
+ }
+ }
+ if (!interceptors.isEmpty()) {
+ return interceptors.toArray();
+ }
+ }
+
+ return DO_NOT_PROXY;
+ }
+
+ private boolean isMatch(String beanName, Set patterns) {
for (Pattern pattern : patterns) {
if (pattern.matcher(beanName).matches()) {
return true;
diff --git a/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorFactoryBean.java b/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorFactoryBean.java
index 2ed5d438f7..f350b4cac3 100644
--- a/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorFactoryBean.java
+++ b/spring-integration-security/src/main/java/org/springframework/integration/security/config/ChannelSecurityInterceptorFactoryBean.java
@@ -40,7 +40,10 @@ import org.springframework.util.Assert;
*
* @author Artem Bilan
* @since 4.0
+ * @deprecated in favor of direct {@link ChannelSecurityInterceptor} usage and
+ * {@link org.springframework.integration.security.channel.SecuredChannel} annotation.
*/
+@Deprecated
public class ChannelSecurityInterceptorFactoryBean implements FactoryBean, BeanNameAware, BeanFactoryAware {
private final ChannelSecurityInterceptor interceptor = new ChannelSecurityInterceptor(new ChannelSecurityMetadataSource());
diff --git a/spring-integration-security/src/main/java/org/springframework/integration/security/config/SecurityIntegrationConfigurationInitializer.java b/spring-integration-security/src/main/java/org/springframework/integration/security/config/SecurityIntegrationConfigurationInitializer.java
index aa3491bd7d..bb8717b88f 100644
--- a/spring-integration-security/src/main/java/org/springframework/integration/security/config/SecurityIntegrationConfigurationInitializer.java
+++ b/spring-integration-security/src/main/java/org/springframework/integration/security/config/SecurityIntegrationConfigurationInitializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2015 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.
@@ -16,23 +16,24 @@
package org.springframework.integration.security.config;
-import java.lang.reflect.Method;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.core.type.MethodMetadata;
-import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.integration.config.IntegrationConfigurationInitializer;
+import org.springframework.integration.security.channel.ChannelAccessPolicy;
import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.StringUtils;
+import org.springframework.integration.security.channel.DefaultChannelAccessPolicy;
+import org.springframework.integration.security.channel.SecuredChannel;
/**
* The Integration Security infrastructure {@code beanFactory} initializer.
@@ -46,45 +47,75 @@ public class SecurityIntegrationConfigurationInitializer implements IntegrationC
ChannelSecurityInterceptorBeanPostProcessor.class.getName();
@Override
+ @SuppressWarnings("unchecked")
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
- List securityInterceptors = new ManagedList();
+ Map> securityInterceptors = new ManagedMap>();
+ Map> policies = new HashMap>();
for (String beanName : registry.getBeanDefinitionNames()) {
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
- String beanClassName = beanDefinition.getBeanClassName();
- Class> clazz = null;
- if (StringUtils.hasText(beanClassName)) {
- try {
- clazz = ClassUtils.forName(beanClassName, beanFactory.getBeanClassLoader());
- }
- catch (ClassNotFoundException e) {
- throw new CannotLoadBeanClassException(this.toString(), beanName, beanClassName, e);
- }
- }
- else if (beanDefinition instanceof AnnotatedBeanDefinition
- && beanDefinition.getSource() instanceof MethodMetadata) {
- MethodMetadata beanMethod = (MethodMetadata) beanDefinition.getSource();
- if (beanMethod instanceof StandardMethodMetadata) {
- Method method = ((StandardMethodMetadata) beanMethod).getIntrospectedMethod();
- clazz = method.getReturnType();
- }
- }
+ if (ChannelSecurityInterceptor.class.getName().equals(beanDefinition.getBeanClassName())) {
+ BeanDefinition metadataSource = (BeanDefinition) beanDefinition.getConstructorArgumentValues()
+ .getIndexedArgumentValue(0, BeanDefinition.class)
+ .getValue();
- if (clazz != null &&
- (ChannelSecurityInterceptor.class.isAssignableFrom(clazz)
- || ChannelSecurityInterceptorFactoryBean.class.isAssignableFrom(clazz))) {
- securityInterceptors.add(beanDefinition);
+ Map value = (Map) metadataSource.getConstructorArgumentValues()
+ .getIndexedArgumentValue(0, Map.class)
+ .getValue();
+ ManagedSet patterns = new ManagedSet();
+ if (!securityInterceptors.containsKey(beanName)) {
+ securityInterceptors.put(beanName, patterns);
+ }
+ else {
+ patterns = securityInterceptors.get(beanName);
+ }
+ patterns.addAll(value.keySet());
+ }
+ else if (beanDefinition instanceof AnnotatedBeanDefinition) {
+ if (beanDefinition.getSource() instanceof MethodMetadata) {
+ MethodMetadata beanMethod = (MethodMetadata) beanDefinition.getSource();
+ String annotationType = SecuredChannel.class.getName();
+ if (beanMethod.isAnnotated(annotationType)) {
+ Map securedAttributes = beanMethod.getAnnotationAttributes(annotationType);
+ String[] interceptors = (String[]) securedAttributes.get("interceptor");
+ String[] sendAccess = (String[]) securedAttributes.get("sendAccess");
+ String[] receiveAccess = (String[]) securedAttributes.get("receiveAccess");
+ ChannelAccessPolicy accessPolicy = new DefaultChannelAccessPolicy(sendAccess, receiveAccess);
+ for (String interceptor : interceptors) {
+ ManagedSet patterns = new ManagedSet();
+ if (!securityInterceptors.containsKey(interceptor)) {
+ securityInterceptors.put(interceptor, patterns);
+ }
+ else {
+ patterns = securityInterceptors.get(interceptor);
+ }
+ patterns.add(beanName);
+
+ Map mapping = new HashMap();
+ if (!policies.containsKey(interceptor)) {
+ policies.put(interceptor, mapping);
+ }
+ else {
+ mapping = policies.get(interceptor);
+ }
+ mapping.put(Pattern.compile(beanName), accessPolicy);
+ }
+ }
+ }
}
}
if (!securityInterceptors.isEmpty()) {
- BeanDefinition securityPostProcessorBd =
+
+ BeanDefinitionBuilder builder =
BeanDefinitionBuilder.rootBeanDefinition(ChannelSecurityInterceptorBeanPostProcessor.class)
- .addConstructorArgValue(securityInterceptors)
- .getBeanDefinition();
- registry.registerBeanDefinition(CHANNEL_SECURITY_INTERCEPTOR_BPP_BEAN_NAME, securityPostProcessorBd);
+ .addConstructorArgValue(securityInterceptors);
+ if (!policies.isEmpty()) {
+ builder.addConstructorArgValue(policies);
+ }
+ registry.registerBeanDefinition(CHANNEL_SECURITY_INTERCEPTOR_BPP_BEAN_NAME, builder.getBeanDefinition());
}
}
diff --git a/spring-integration-security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorBeanPostProcessorTests.java b/spring-integration-security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorBeanPostProcessorTests.java
deleted file mode 100644
index e5c744e0af..0000000000
--- a/spring-integration-security/src/test/java/org/springframework/integration/security/channel/ChannelSecurityInterceptorBeanPostProcessorTests.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2002-2014 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.Arrays;
-import java.util.regex.Pattern;
-
-import org.junit.Test;
-
-import org.springframework.aop.support.AopUtils;
-import org.springframework.integration.channel.QueueChannel;
-import org.springframework.integration.security.config.ChannelSecurityInterceptorBeanPostProcessor;
-import org.springframework.messaging.MessageChannel;
-
-/**
- * @author Mark Fisher
- * @author Artem Bilan
- */
-public class ChannelSecurityInterceptorBeanPostProcessorTests {
-
- @Test
- public void securedChannelIsProxied() throws Exception {
- ChannelSecurityMetadataSource securityMetadataSource = new ChannelSecurityMetadataSource();
- securityMetadataSource.addPatternMapping(Pattern.compile("secured.*"),
- new DefaultChannelAccessPolicy("ROLE_ADMIN", null));
-
- ChannelSecurityInterceptor interceptor = new ChannelSecurityInterceptor(securityMetadataSource);
-
- ChannelSecurityInterceptorBeanPostProcessor postProcessor =
- new ChannelSecurityInterceptorBeanPostProcessor(Arrays.asList(interceptor));
-
- QueueChannel securedChannel = new QueueChannel();
- securedChannel.setBeanName("securedChannel");
- MessageChannel postProcessedChannel =
- (MessageChannel) postProcessor.postProcessAfterInitialization(securedChannel, "securedChannel");
- assertTrue(AopUtils.isAopProxy(postProcessedChannel));
- }
-
- @Test
- public void nonsecuredChannelIsNotProxied() throws Exception {
- ChannelSecurityMetadataSource securityMetadataSource = new ChannelSecurityMetadataSource();
- securityMetadataSource.addPatternMapping(Pattern.compile("secured.*"),
- new DefaultChannelAccessPolicy("ROLE_ADMIN", null));
-
- ChannelSecurityInterceptor interceptor = new ChannelSecurityInterceptor(securityMetadataSource);
-
- ChannelSecurityInterceptorBeanPostProcessor postProcessor =
- new ChannelSecurityInterceptorBeanPostProcessor(Arrays.asList(interceptor));
-
- QueueChannel channel = new QueueChannel();
- channel.setBeanName("testChannel");
- MessageChannel postProcessedChannel =
- (MessageChannel) postProcessor.postProcessAfterInitialization(channel, "testChannel");
- assertFalse(AopUtils.isAopProxy(postProcessedChannel));
- }
-
-}
diff --git a/spring-integration-security/src/test/java/org/springframework/integration/security/config/ChannelSecurityInterceptorFactoryBeanTests.java b/spring-integration-security/src/test/java/org/springframework/integration/security/config/ChannelSecurityInterceptorSecuredChannelAnnotationTests.java
similarity index 82%
rename from spring-integration-security/src/test/java/org/springframework/integration/security/config/ChannelSecurityInterceptorFactoryBeanTests.java
rename to spring-integration-security/src/test/java/org/springframework/integration/security/config/ChannelSecurityInterceptorSecuredChannelAnnotationTests.java
index 96d8f91488..f2b4ee41df 100644
--- a/spring-integration-security/src/test/java/org/springframework/integration/security/config/ChannelSecurityInterceptorFactoryBeanTests.java
+++ b/spring-integration-security/src/test/java/org/springframework/integration/security/config/ChannelSecurityInterceptorSecuredChannelAnnotationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2015 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.
@@ -30,10 +30,14 @@ import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.security.SecurityTestUtils;
import org.springframework.integration.security.TestHandler;
+import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
+import org.springframework.integration.security.channel.SecuredChannel;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.support.GenericMessage;
+import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -48,7 +52,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
-public class ChannelSecurityInterceptorFactoryBeanTests {
+public class ChannelSecurityInterceptorSecuredChannelAnnotationTests {
@Autowired
MessageChannel securedChannel;
@@ -133,11 +137,13 @@ public class ChannelSecurityInterceptorFactoryBeanTests {
public static class ContextConfiguration {
@Bean
+ @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = {"ROLE_ADMIN", "ROLE_PRESIDENT"})
public SubscribableChannel securedChannel() {
return new DirectChannel();
}
@Bean
+ @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = {"ROLE_ADMIN", "ROLE_PRESIDENT"})
public SubscribableChannel securedChannel2() {
return new DirectChannel();
}
@@ -157,9 +163,12 @@ public class ChannelSecurityInterceptorFactoryBeanTests {
}
@Bean
- public ChannelSecurityInterceptorFactoryBean channelSecurityInterceptor() {
- return new ChannelSecurityInterceptorFactoryBean()
- .accessPolicy("securedChannel.*", "ROLE_ADMIN, ROLE_PRESIDENT");
+ public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager,
+ AccessDecisionManager accessDecisionManager) {
+ ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor();
+ channelSecurityInterceptor.setAuthenticationManager(authenticationManager);
+ channelSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
+ return channelSecurityInterceptor;
}
}
diff --git a/src/reference/asciidoc/security.adoc b/src/reference/asciidoc/security.adoc
index e93e049d6f..73ac688d86 100644
--- a/src/reference/asciidoc/security.adoc
+++ b/src/reference/asciidoc/security.adoc
@@ -55,8 +55,14 @@ Where this is not the case references to the appropriate beans can be configured
----
-Starting with _version 4.0_, the same configuration is available when using `@Configuration` classes, by declaring a `ChannelSecurityInterceptorFactoryBean`.
-This class delegates all options for the `ChannelSecurityInterceptor` with a _builder_ pattern:
+Starting with _version 4.2_, the `@SecuredChannel` annotation is available, replacing the deprecated
+`ChannelSecurityInterceptorFactoryBean`, which was introduced in _version 4.0_ for Java & Annotation
+configuration in `@Configuration` classes.
+The `ChannelSecurityInterceptorFactoryBean` has been deprecated to
+avoid the possibility of undesired early load for dependent beans from the `BeanFactory` during the `ApplicationContext` initialization
+phase.
+
+With the `@SecuredChannel` annotation, the Java configuration variant of the XML configuration above is:
[source,java]
----
@@ -64,22 +70,26 @@ This class delegates all options for the `ChannelSecurityInterceptor` with a _bu
@EnableIntegration
public class ContextConfiguration {
- @Autowired
- private AuthenticationManager authenticationManager;
-
- @Autowired
- private AccessDecisionManager accessDecisionManager;
-
@Bean
- public ChannelSecurityInterceptorFactoryBean channelSecurityInterceptor() {
- return new ChannelSecurityInterceptorFactoryBean()
- .authenticationManager(this.authenticationManager)
- .accessDecisionManager(this.accessDecisionManager)
- .accessPolicy("admin.*", "ROLE_ADMIN")
- .accessPolicy("user.*", null, "ROLE_USER");
- }
+ @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = "ROLE_ADMIN")
+ public SubscribableChannel adminChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean
+ @SecuredChannel(interceptor = "channelSecurityInterceptor", receiveAccess = "ROLE_USER")
+ public SubscribableChannel userChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean
+ public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager,
+ AccessDecisionManager accessDecisionManager) {
+ ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor();
+ channelSecurityInterceptor.setAuthenticationManager(authenticationManager);
+ channelSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
+ return channelSecurityInterceptor;
+ }
+
}
----
-
-NOTE: The `@EnableIntegration` annotation is required to provide the Spring Integration infrastructure (including Security) to the Application Context.
-In addition this `FactoryBean` falls back to `AuthenticationManager` and `AccessDecisionManager` beans with names `authenticationManager` and `accessDecisionManager` respectively, if they aren't provided in the `ChannelSecurityInterceptorFactoryBean` bean definition.
diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc
index 31acafc5f7..c6dc75a273 100644
--- a/src/reference/asciidoc/whats-new.adoc
+++ b/src/reference/asciidoc/whats-new.adoc
@@ -22,6 +22,13 @@ For complete details, see <>.
The `MongoDbMetadataStore` is now available. For more information, see <>.
+[[x4.2-secured-channel-annotation]]
+==== SecuredChannel Annotation
+
+The `@SecuredChannel` annotation has been introduced, replacing the deprecated `ChannelSecurityInterceptorFactoryBean`.
+For more information, see <>.
+
+
[[x4.2-general]]
=== General Changes