/*
* Copyright 2014-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.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.springframework.beans.BeansException;
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.ManagedMap;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.core.type.MethodMetadata;
import org.springframework.integration.config.IntegrationConfigurationInitializer;
import org.springframework.integration.security.channel.ChannelAccessPolicy;
import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
import org.springframework.integration.security.channel.DefaultChannelAccessPolicy;
import org.springframework.integration.security.channel.SecuredChannel;
/**
* The Integration Security infrastructure {@code beanFactory} initializer.
*
* @author Artem Bilan
* @since 4.0
*/
public class SecurityIntegrationConfigurationInitializer implements IntegrationConfigurationInitializer {
private static final String CHANNEL_SECURITY_INTERCEPTOR_BPP_BEAN_NAME =
ChannelSecurityInterceptorBeanPostProcessor.class.getName();
@Override
@SuppressWarnings("unchecked")
public void initialize(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
Map<String, ManagedSet<String>> securityInterceptors = new ManagedMap<String, ManagedSet<String>>();
Map<String, Map<Pattern, ChannelAccessPolicy>> policies = new HashMap<String, Map<Pattern, ChannelAccessPolicy>>();
for (String beanName : registry.getBeanDefinitionNames()) {
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
if (ChannelSecurityInterceptor.class.getName().equals(beanDefinition.getBeanClassName())) {
BeanDefinition metadataSource = (BeanDefinition) beanDefinition.getConstructorArgumentValues()
.getIndexedArgumentValue(0, BeanDefinition.class)
.getValue();
Map<String, ?> value = (Map<String, ?>) metadataSource.getConstructorArgumentValues()
.getIndexedArgumentValue(0, Map.class)
.getValue();
ManagedSet<String> patterns = new ManagedSet<String>();
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<String, Object> 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<String> patterns = new ManagedSet<String>();
if (!securityInterceptors.containsKey(interceptor)) {
securityInterceptors.put(interceptor, patterns);
}
else {
patterns = securityInterceptors.get(interceptor);
}
patterns.add(beanName);
Map<Pattern, ChannelAccessPolicy> mapping = new HashMap<Pattern, ChannelAccessPolicy>();
if (!policies.containsKey(interceptor)) {
policies.put(interceptor, mapping);
}
else {
mapping = policies.get(interceptor);
}
mapping.put(Pattern.compile(beanName), accessPolicy);
}
}
}
}
}
if (!securityInterceptors.isEmpty()) {
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.rootBeanDefinition(ChannelSecurityInterceptorBeanPostProcessor.class)
.addConstructorArgValue(securityInterceptors);
if (!policies.isEmpty()) {
builder.addConstructorArgValue(policies);
}
registry.registerBeanDefinition(CHANNEL_SECURITY_INTERCEPTOR_BPP_BEAN_NAME, builder.getBeanDefinition());
}
}
}