package org.apereo.cas.config;
import com.google.common.base.Throwables;
import org.apereo.cas.CipherExecutor;
import org.apereo.cas.authentication.DefaultMultifactorTriggerSelectionStrategy;
import org.apereo.cas.authentication.MultifactorTriggerSelectionStrategy;
import org.apereo.cas.authentication.ProtocolAttributeEncoder;
import org.apereo.cas.authentication.principal.DefaultWebApplicationResponseBuilderLocator;
import org.apereo.cas.authentication.principal.PersistentIdGenerator;
import org.apereo.cas.authentication.principal.ResponseBuilder;
import org.apereo.cas.authentication.principal.ResponseBuilderLocator;
import org.apereo.cas.authentication.principal.ShibbolethCompatiblePersistentIdGenerator;
import org.apereo.cas.authentication.principal.WebApplicationService;
import org.apereo.cas.authentication.principal.WebApplicationServiceResponseBuilder;
import org.apereo.cas.authentication.support.DefaultCasProtocolAttributeEncoder;
import org.apereo.cas.authentication.support.NoOpProtocolAttributeEncoder;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.services.AbstractResourceBasedServiceRegistryDao;
import org.apereo.cas.services.DefaultServicesManager;
import org.apereo.cas.services.InMemoryServiceRegistry;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.RegisteredServiceCipherExecutor;
import org.apereo.cas.services.RegisteredServicesEventListener;
import org.apereo.cas.services.ServiceRegistryDao;
import org.apereo.cas.services.ServiceRegistryInitializer;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.services.DefaultRegisteredServiceCipherExecutor;
import org.apereo.cas.util.services.RegisteredServiceJsonSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import java.util.ArrayList;
import java.util.List;
/**
* This is {@link CasCoreServicesConfiguration}.
*
* @author Misagh Moayyed
* @since 5.0.0
*/
@Configuration("casCoreServicesConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CasCoreServicesConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(CasCoreServicesConfiguration.class);
private static final String BEAN_NAME_SERVICE_REGISTRY_DAO = "serviceRegistryDao";
@Autowired
private CasConfigurationProperties casProperties;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ApplicationEventPublisher eventPublisher;
@RefreshScope
@Bean
public MultifactorTriggerSelectionStrategy defaultMultifactorTriggerSelectionStrategy() {
final String attributeNameTriggers = casProperties.getAuthn().getMfa().getGlobalPrincipalAttributeNameTriggers();
final String requestParameter = casProperties.getAuthn().getMfa().getRequestParameter();
return new DefaultMultifactorTriggerSelectionStrategy(attributeNameTriggers, requestParameter);
}
@RefreshScope
@Bean
public PersistentIdGenerator shibbolethCompatiblePersistentIdGenerator() {
return new ShibbolethCompatiblePersistentIdGenerator();
}
@ConditionalOnMissingBean(name = "webApplicationResponseBuilderLocator")
@Bean
public ResponseBuilderLocator webApplicationResponseBuilderLocator() {
return new DefaultWebApplicationResponseBuilderLocator();
}
@ConditionalOnMissingBean(name = "webApplicationServiceResponseBuilder")
@Bean
public ResponseBuilder<WebApplicationService> webApplicationServiceResponseBuilder() {
return new WebApplicationServiceResponseBuilder();
}
@ConditionalOnMissingBean(name = "casAttributeEncoder")
@RefreshScope
@Bean
public ProtocolAttributeEncoder casAttributeEncoder(@Qualifier("serviceRegistryDao") final ServiceRegistryDao serviceRegistryDao,
@Qualifier("cacheCredentialsCipherExecutor") final CipherExecutor cacheCredentialsCipherExecutor) {
return new DefaultCasProtocolAttributeEncoder(servicesManager(serviceRegistryDao),
registeredServiceCipherExecutor(), cacheCredentialsCipherExecutor);
}
@Bean
public ProtocolAttributeEncoder noOpCasAttributeEncoder() {
return new NoOpProtocolAttributeEncoder();
}
@ConditionalOnMissingBean(name = "registeredServiceCipherExecutor")
@Bean
@RefreshScope
public RegisteredServiceCipherExecutor registeredServiceCipherExecutor() {
return new DefaultRegisteredServiceCipherExecutor();
}
@ConditionalOnMissingBean(name = "servicesManager")
@Bean
@RefreshScope
public ServicesManager servicesManager(@Qualifier("serviceRegistryDao") final ServiceRegistryDao serviceRegistryDao) {
return new DefaultServicesManager(serviceRegistryDao);
}
@Bean
@RefreshScope
public RegisteredServicesEventListener registeredServicesEventListener(@Qualifier("servicesManager") final ServicesManager servicesManager) {
return new RegisteredServicesEventListener(servicesManager);
}
@ConditionalOnMissingBean(name = BEAN_NAME_SERVICE_REGISTRY_DAO)
@Bean
@RefreshScope
public ServiceRegistryDao serviceRegistryDao() {
LOGGER.warn("Runtime memory is used as the persistence storage for retrieving and persisting service definitions. "
+ "Changes that are made to service definitions during runtime WILL be LOST upon container restarts.");
final List<RegisteredService> services = new ArrayList<>();
if (applicationContext.containsBean("inMemoryRegisteredServices")) {
services.addAll(applicationContext.getBean("inMemoryRegisteredServices", List.class));
}
return new InMemoryServiceRegistry(services);
}
@Autowired
@ConditionalOnMissingBean(name = "jsonServiceRegistryDao")
@Bean
public ServiceRegistryInitializer serviceRegistryInitializer(@Qualifier(BEAN_NAME_SERVICE_REGISTRY_DAO) final ServiceRegistryDao serviceRegistryDao) {
return new ServiceRegistryInitializer(embeddedJsonServiceRegistry(eventPublisher), serviceRegistryDao, servicesManager(serviceRegistryDao),
casProperties.getServiceRegistry().isInitFromJson());
}
@Autowired
@ConditionalOnMissingBean(name = "jsonServiceRegistryDao")
@Bean
public ServiceRegistryDao embeddedJsonServiceRegistry(final ApplicationEventPublisher publisher) {
try {
return new EmbeddedServiceRegistryDao(publisher);
} catch (final Exception e) {
throw Throwables.propagate(e);
}
}
/**
* The embedded service registry that processes built-in JSON service files
* on the classpath.
*/
public static class EmbeddedServiceRegistryDao extends AbstractResourceBasedServiceRegistryDao {
EmbeddedServiceRegistryDao(final ApplicationEventPublisher publisher) throws Exception {
super(new ClassPathResource("services"), new RegisteredServiceJsonSerializer(), false, publisher);
}
@Override
protected String getExtension() {
return "json";
}
}
}