/* * Copyright 2002-2016 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.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; 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; /** * A {@link BeanPostProcessor} that proxies {@link MessageChannel}s to apply a {@link ChannelSecurityInterceptor}. * * @author Mark Fisher * @author Oleg Zhurakousky * @author Artem Bilan */ @SuppressWarnings("serial") public class ChannelSecurityInterceptorBeanPostProcessor extends AbstractAutoProxyCreator { private final Map<String, Set<Pattern>> securityInterceptorMappings; private final Map<String, Map<Pattern, ChannelAccessPolicy>> accessPolicyMapping; public ChannelSecurityInterceptorBeanPostProcessor(Map<String, Set<Pattern>> securityInterceptorMappings) { this(securityInterceptorMappings, null); } public ChannelSecurityInterceptorBeanPostProcessor(Map<String, Set<Pattern>> securityInterceptorMappings, Map<String, Map<Pattern, ChannelAccessPolicy>> accessPolicyMapping) { this.securityInterceptorMappings = securityInterceptorMappings; //NOSONAR (inconsistent sync) this.accessPolicyMapping = accessPolicyMapping; //NOSONAR (inconsistent sync) } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { if (this.accessPolicyMapping != null && bean instanceof ChannelSecurityInterceptor && this.accessPolicyMapping.containsKey(beanName)) { Map<Pattern, ChannelAccessPolicy> accessPolicies = this.accessPolicyMapping.get(beanName); ChannelSecurityMetadataSource securityMetadataSource = (ChannelSecurityMetadataSource) ((ChannelSecurityInterceptor) bean).obtainSecurityMetadataSource(); for (Map.Entry<Pattern, ChannelAccessPolicy> entry : accessPolicies.entrySet()) { securityMetadataSource.addPatternMapping(entry.getKey(), entry.getValue()); } } return bean; } @Override protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException { if (MessageChannel.class.isAssignableFrom(beanClass)) { List<Advisor> interceptors = new ArrayList<Advisor>(); for (Map.Entry<String, Set<Pattern>> 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<Pattern> patterns) { for (Pattern pattern : patterns) { if (pattern.matcher(beanName).matches()) { return true; } } return false; } }