package org.apereo.cas.config;
import org.apache.commons.lang3.BooleanUtils;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.model.core.web.security.HttpWebRequestProperties;
import org.apereo.cas.security.RequestParameterPolicyEnforcementFilter;
import org.apereo.cas.security.ResponseHeadersEnforcementFilter;
import org.apereo.cas.web.support.AuthenticationCredentialsLocalBinderClearingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* This is {@link CasFiltersConfiguration} that attempts to create Spring-managed beans
* backed by external configuration.
*
* @author Misagh Moayyed
* @since 5.0.0
*/
@Configuration("casFiltersConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CasFiltersConfiguration {
@Autowired
private CasConfigurationProperties casProperties;
@RefreshScope
@Bean
public FilterRegistrationBean characterEncodingFilter() {
final FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new CharacterEncodingFilter(
casProperties.getHttpWebRequest().getWeb().getEncoding(),
casProperties.getHttpWebRequest().getWeb().isForceEncoding()));
bean.setUrlPatterns(Collections.singleton("/*"));
bean.setName("characterEncodingFilter");
bean.setAsyncSupported(true);
return bean;
}
@ConditionalOnProperty(prefix = "cas.httpWebRequest.cors", name = "enabled", havingValue = "true")
@Bean
@RefreshScope
public FilterRegistrationBean casCorsFilter() {
final HttpWebRequestProperties.Cors cors = casProperties.getHttpWebRequest().getCors();
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(cors.isEnabled());
config.setAllowedOrigins(cors.getAllowOrigins());
config.setAllowedMethods(cors.getAllowMethods());
config.setAllowedHeaders(cors.getAllowHeaders());
config.setMaxAge(cors.getMaxAge());
config.setExposedHeaders(cors.getExposedHeaders());
source.registerCorsConfiguration("/**", config);
final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setName("casCorsFilter");
bean.setAsyncSupported(true);
bean.setOrder(0);
return bean;
}
@RefreshScope
@Bean
public FilterRegistrationBean responseHeadersSecurityFilter() {
final HttpWebRequestProperties.Header header = casProperties.getHttpWebRequest().getHeader();
final Map<String, String> initParams = new HashMap<>();
initParams.put("enableCacheControl", BooleanUtils.toStringTrueFalse(header.isCache()));
initParams.put("enableXContentTypeOptions", BooleanUtils.toStringTrueFalse(header.isXcontent()));
initParams.put("enableStrictTransportSecurity", BooleanUtils.toStringTrueFalse(header.isHsts()));
initParams.put("enableXFrameOptions", BooleanUtils.toStringTrueFalse(header.isXframe()));
initParams.put("enableXSSProtection", BooleanUtils.toStringTrueFalse(header.isXss()));
final FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new ResponseHeadersEnforcementFilter());
bean.setUrlPatterns(Collections.singleton("/*"));
bean.setInitParameters(initParams);
bean.setName("responseHeadersSecurityFilter");
bean.setAsyncSupported(true);
return bean;
}
@RefreshScope
@Bean
public FilterRegistrationBean requestParameterSecurityFilter() {
final Map<String, String> initParams = new HashMap<>();
initParams.put(RequestParameterPolicyEnforcementFilter.PARAMETERS_TO_CHECK,
casProperties.getHttpWebRequest().getParamsToCheck());
initParams.put(RequestParameterPolicyEnforcementFilter.CHARACTERS_TO_FORBID, "none");
initParams.put(RequestParameterPolicyEnforcementFilter.ALLOW_MULTI_VALUED_PARAMETERS,
BooleanUtils.toStringTrueFalse(casProperties.getHttpWebRequest().isAllowMultiValueParameters()));
initParams.put(RequestParameterPolicyEnforcementFilter.ONLY_POST_PARAMETERS,
casProperties.getHttpWebRequest().getOnlyPostParams());
final FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new RequestParameterPolicyEnforcementFilter());
bean.setUrlPatterns(Collections.singleton("/*"));
bean.setName("requestParameterSecurityFilter");
bean.setInitParameters(initParams);
bean.setAsyncSupported(true);
return bean;
}
@Bean
public FilterRegistrationBean currentCredentialsAndAuthenticationClearingFilter() {
final FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new AuthenticationCredentialsLocalBinderClearingFilter());
bean.setUrlPatterns(Collections.singleton("/*"));
bean.setName("currentCredentialsAndAuthenticationClearingFilter");
bean.setAsyncSupported(true);
return bean;
}
}