package org.apereo.cas.mgmt.config; import com.google.common.base.Throwables; import org.apereo.cas.authentication.AuthenticationMetaDataPopulator; import org.apereo.cas.authentication.principal.ServiceFactory; import org.apereo.cas.authentication.principal.WebApplicationService; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.configuration.support.Beans; import org.apereo.cas.mgmt.services.web.ManageRegisteredServicesMultiActionController; import org.apereo.cas.mgmt.services.web.RegisteredServiceSimpleFormController; import org.apereo.cas.mgmt.services.web.factory.AccessStrategyMapper; import org.apereo.cas.mgmt.services.web.factory.AttributeFilterMapper; import org.apereo.cas.mgmt.services.web.factory.AttributeFormDataPopulator; import org.apereo.cas.mgmt.services.web.factory.AttributeReleasePolicyMapper; import org.apereo.cas.mgmt.services.web.factory.DefaultAccessStrategyMapper; import org.apereo.cas.mgmt.services.web.factory.DefaultAttributeFilterMapper; import org.apereo.cas.mgmt.services.web.factory.DefaultAttributeReleasePolicyMapper; import org.apereo.cas.mgmt.services.web.factory.DefaultPrincipalAttributesRepositoryMapper; import org.apereo.cas.mgmt.services.web.factory.DefaultProxyPolicyMapper; import org.apereo.cas.mgmt.services.web.factory.DefaultRegisteredServiceFactory; import org.apereo.cas.mgmt.services.web.factory.DefaultRegisteredServiceMapper; import org.apereo.cas.mgmt.services.web.factory.DefaultUsernameAttributeProviderMapper; import org.apereo.cas.mgmt.services.web.factory.FormDataPopulator; import org.apereo.cas.mgmt.services.web.factory.PrincipalAttributesRepositoryMapper; import org.apereo.cas.mgmt.services.web.factory.ProxyPolicyMapper; import org.apereo.cas.mgmt.services.web.factory.RegisteredServiceFactory; import org.apereo.cas.mgmt.services.web.factory.RegisteredServiceMapper; import org.apereo.cas.mgmt.web.CasManagementRootController; import org.apereo.cas.mgmt.web.CasManagementSecurityInterceptor; import org.apereo.cas.services.ServicesManager; import org.apereo.cas.ticket.UniqueTicketIdGenerator; import org.apereo.services.persondir.IPersonAttributeDao; import org.pac4j.cas.client.direct.DirectCasClient; import org.pac4j.cas.config.CasConfiguration; import org.pac4j.core.authorization.authorizer.Authorizer; import org.pac4j.core.authorization.authorizer.RequireAnyRoleAuthorizer; import org.pac4j.core.authorization.generator.AuthorizationGenerator; import org.pac4j.core.authorization.generator.FromAttributesAuthorizationGenerator; import org.pac4j.core.authorization.generator.SpringSecurityPropertiesAuthorizationGenerator; import org.pac4j.core.client.Client; import org.pac4j.core.config.Config; import org.pac4j.core.context.WebContext; import org.pac4j.core.profile.CommonProfile; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.i18n.CookieLocaleResolver; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; import org.springframework.web.servlet.mvc.UrlFilenameViewController; import javax.servlet.Filter; import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; /** * This is {@link CasManagementWebAppConfiguration}. * * @author Misagh Moayyed * @since 5.0.0 */ @Configuration("casManagementWebAppConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) public class CasManagementWebAppConfiguration extends WebMvcConfigurerAdapter { @Autowired(required = false) @Qualifier("formDataPopulators") private List formDataPopulators = new ArrayList<>(); @Autowired private ServerProperties serverProperties; @Autowired private CasConfigurationProperties casProperties; @Autowired @Qualifier("webApplicationServiceFactory") private ServiceFactory<WebApplicationService> webApplicationServiceFactory; @Bean public Filter characterEncodingFilter() { return new CharacterEncodingFilter(StandardCharsets.UTF_8.name(), true); } @Bean public Authorizer requireAnyRoleAuthorizer() { return new RequireAnyRoleAuthorizer(casProperties.getMgmt().getAdminRoles()); } @RefreshScope @ConditionalOnMissingBean(name = "attributeRepository") @Bean public IPersonAttributeDao attributeRepository() { return Beans.newStubAttributeRepository(casProperties.getAuthn().getAttributeRepository()); } @Bean public Client casClient() { final CasConfiguration cfg = new CasConfiguration(casProperties.getServer().getLoginUrl()); final DirectCasClient client = new DirectCasClient(cfg); client.setAuthorizationGenerator(authorizationGenerator()); client.setName("CasClient"); return client; } @Bean public Config config() { final Config cfg = new Config(getDefaultServiceUrl(), casClient()); cfg.setAuthorizer(requireAnyRoleAuthorizer()); return cfg; } @Bean public Controller rootController() { return new CasManagementRootController(); } @Bean public SimpleUrlHandlerMapping handlerMappingC() { final SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setOrder(1); mapping.setAlwaysUseFullPath(true); mapping.setRootHandler(rootController()); final Properties properties = new Properties(); properties.put("/*.html", new UrlFilenameViewController()); mapping.setMappings(properties); return mapping; } @Bean public HandlerInterceptorAdapter casManagementSecurityInterceptor() { return new CasManagementSecurityInterceptor(config()); } @RefreshScope @Bean public Properties userProperties() { try { final Properties p = new Properties(); p.load(casProperties.getMgmt().getUserPropertiesFile().getInputStream()); return p; } catch (final Exception e) { throw Throwables.propagate(e); } } @ConditionalOnMissingBean(name = "authorizationGenerator") @Bean @RefreshScope public AuthorizationGenerator authorizationGenerator() { final List<String> authzAttributes = casProperties.getMgmt().getAuthzAttributes(); if (!authzAttributes.isEmpty()) { if ("*".equals(authzAttributes)) { return new PermitAllAuthorizationGenerator(); } return new FromAttributesAuthorizationGenerator(authzAttributes.toArray(new String[]{}), new String[]{}); } return new SpringSecurityPropertiesAuthorizationGenerator(userProperties()); } @Bean public CookieLocaleResolver localeResolver() { return new CookieLocaleResolver() { @Override protected Locale determineDefaultLocale(final HttpServletRequest request) { final Locale locale = request.getLocale(); if (StringUtils.isEmpty(casProperties.getMgmt().getDefaultLocale()) || !locale.getLanguage().equals(casProperties.getMgmt().getDefaultLocale())) { return locale; } return new Locale(casProperties.getMgmt().getDefaultLocale()); } }; } @RefreshScope @Bean public LocaleChangeInterceptor localeChangeInterceptor() { final LocaleChangeInterceptor bean = new LocaleChangeInterceptor(); bean.setParamName(this.casProperties.getLocale().getParamName()); return bean; } @Override public void addInterceptors(final InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); registry.addInterceptor(casManagementSecurityInterceptor()) .addPathPatterns("/**").excludePathPatterns("/callback*", "/logout*", "/authorizationFailure"); } @Bean public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() { return new SimpleControllerHandlerAdapter(); } @Bean public AccessStrategyMapper defaultAccessStrategyMapper() { return new DefaultAccessStrategyMapper(); } @Bean public RegisteredServiceFactory registeredServiceFactory() { this.formDataPopulators.add(attributeFormDataPopulator()); return new DefaultRegisteredServiceFactory(defaultAccessStrategyMapper(), defaultAttributeReleasePolicyMapper(), defaultProxyPolicyMapper(), defaultRegisteredServiceMapper(), usernameAttributeProviderMapper(), formDataPopulators); } @Bean public AttributeReleasePolicyMapper defaultAttributeReleasePolicyMapper() { return new DefaultAttributeReleasePolicyMapper(defaultAttributeFilterMapper(), defaultPrincipalAttributesRepositoryMapper()); } @Bean public FormDataPopulator attributeFormDataPopulator() { return new AttributeFormDataPopulator(attributeRepository()); } @Bean public DefaultUsernameAttributeProviderMapper usernameAttributeProviderMapper() { return new DefaultUsernameAttributeProviderMapper(); } @Bean public RegisteredServiceMapper defaultRegisteredServiceMapper() { return new DefaultRegisteredServiceMapper(); } @Bean public ProxyPolicyMapper defaultProxyPolicyMapper() { return new DefaultProxyPolicyMapper(); } @Bean public AttributeFilterMapper defaultAttributeFilterMapper() { return new DefaultAttributeFilterMapper(); } @Bean public PrincipalAttributesRepositoryMapper defaultPrincipalAttributesRepositoryMapper() { return new DefaultPrincipalAttributesRepositoryMapper(); } @Bean public ManageRegisteredServicesMultiActionController manageRegisteredServicesMultiActionController( @Qualifier("servicesManager") final ServicesManager servicesManager) { return new ManageRegisteredServicesMultiActionController(servicesManager, registeredServiceFactory(), webApplicationServiceFactory, getDefaultServiceUrl()); } @Bean public RegisteredServiceSimpleFormController registeredServiceSimpleFormController(@Qualifier("servicesManager") final ServicesManager servicesManager) { return new RegisteredServiceSimpleFormController(servicesManager, registeredServiceFactory()); } private String getDefaultServiceUrl() { return casProperties.getMgmt().getServerName().concat(serverProperties.getContextPath()).concat("/manage.html"); } @Bean public List serviceFactoryList() { return new ArrayList(); } @Bean public Map<String, UniqueTicketIdGenerator> uniqueIdGeneratorsMap() { return new HashMap<>(); } @Bean public List<AuthenticationMetaDataPopulator> authenticationMetadataPopulators() { return new ArrayList<>(); } /** * The Permit all authorization generator. */ public class PermitAllAuthorizationGenerator implements AuthorizationGenerator<CommonProfile> { @Override public CommonProfile generate(final WebContext webContext, final CommonProfile commonProfile) { commonProfile.addRoles(casProperties.getMgmt().getAdminRoles()); return commonProfile; } } }