package org.apereo.cas.config;
import com.google.common.base.Throwables;
import net.shibboleth.utilities.java.support.velocity.SLF4JLogChute;
import net.shibboleth.utilities.java.support.xml.BasicParserPool;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
import org.apache.velocity.runtime.resource.loader.StringResourceLoader;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.support.saml.OpenSamlConfigBean;
import org.opensaml.core.xml.XMLObjectBuilderFactory;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.core.xml.io.MarshallerFactory;
import org.opensaml.core.xml.io.UnmarshallerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.ui.velocity.VelocityEngineFactoryBean;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* This is {@link CoreSamlConfiguration}.
*
* @author Misagh Moayyed
* @since 5.0.0
*/
@Configuration("coreSamlConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CoreSamlConfiguration {
private static final int POOL_SIZE = 100;
@Autowired
private CasConfigurationProperties casProperties;
@Lazy
@Bean(name = "shibboleth.VelocityEngine")
public VelocityEngineFactoryBean velocityEngineFactoryBean() {
final VelocityEngineFactoryBean bean = new VelocityEngineFactoryBean();
final Properties properties = new Properties();
properties.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, SLF4JLogChute.class.getName());
properties.put(RuntimeConstants.INPUT_ENCODING, StandardCharsets.UTF_8.name());
properties.put(RuntimeConstants.OUTPUT_ENCODING, StandardCharsets.UTF_8.name());
properties.put(RuntimeConstants.ENCODING_DEFAULT, StandardCharsets.UTF_8.name());
properties.put(RuntimeConstants.RESOURCE_LOADER, "file, classpath, string");
properties.put(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FileUtils.getTempDirectory().getAbsolutePath());
properties.put(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, Boolean.FALSE);
properties.put("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
properties.put("string.resource.loader.class", StringResourceLoader.class.getName());
properties.put("file.resource.loader.class", FileResourceLoader.class.getName());
bean.setOverrideLogging(false);
bean.setVelocityProperties(properties);
return bean;
}
@Bean(name = "shibboleth.OpenSAMLConfig")
public OpenSamlConfigBean openSamlConfigBean() {
return new OpenSamlConfigBean(parserPool());
}
@Bean(name = "shibboleth.ParserPool", initMethod = "initialize")
public BasicParserPool parserPool() {
final BasicParserPool pool = new BasicParserPool();
pool.setMaxPoolSize(POOL_SIZE);
pool.setCoalescing(true);
pool.setIgnoreComments(true);
pool.setXincludeAware(false);
pool.setExpandEntityReferences(false);
pool.setIgnoreComments(true);
pool.setNamespaceAware(true);
final Map<String, Object> attributes = new HashMap<>();
try {
final Class clazz = ClassUtils.getClass(casProperties.getSamlCore().getSecurityManager());
attributes.put("http://apache.org/xml/properties/security-manager", clazz.newInstance());
} catch (final Exception e) {
throw Throwables.propagate(e);
}
pool.setBuilderAttributes(attributes);
final Map<String, Boolean> features = new HashMap<>();
features.put("http://apache.org/xml/features/disallow-doctype-decl", Boolean.TRUE);
features.put("http://apache.org/xml/features/validation/schema/normalized-value",
Boolean.FALSE);
features.put("http://javax.xml.XMLConstants/feature/secure-processing",
Boolean.TRUE);
features.put("http://xml.org/sax/features/external-general-entities",
Boolean.FALSE);
features.put("http://xml.org/sax/features/external-parameter-entities",
Boolean.FALSE);
pool.setBuilderFeatures(features);
return pool;
}
@Bean(name = "shibboleth.BuilderFactory")
@DependsOn("shibboleth.OpenSAMLConfig")
public XMLObjectBuilderFactory builderFactory() {
return XMLObjectProviderRegistrySupport.getBuilderFactory();
}
@Bean(name = "shibboleth.MarshallerFactory")
@DependsOn("shibboleth.OpenSAMLConfig")
public MarshallerFactory marshallerFactory() {
return XMLObjectProviderRegistrySupport.getMarshallerFactory();
}
@Bean(name = "shibboleth.UnmarshallerFactory")
@DependsOn("shibboleth.OpenSAMLConfig")
public UnmarshallerFactory unmarshallerFactory() {
return XMLObjectProviderRegistrySupport.getUnmarshallerFactory();
}
}