package org.apereo.cas.config; import org.apereo.cas.audit.spi.PrincipalIdProvider; import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer; import org.apereo.cas.authentication.SurrogateAuthenticationAspect; import org.apereo.cas.authentication.SurrogatePrincipalResolver; import org.apereo.cas.authentication.adaptive.AdaptiveAuthenticationPolicy; import org.apereo.cas.authentication.audit.SurrogatePrincipalIdProvider; import org.apereo.cas.authentication.principal.DefaultPrincipalFactory; import org.apereo.cas.authentication.principal.PrincipalFactory; import org.apereo.cas.authentication.principal.PrincipalResolver; import org.apereo.cas.authentication.surrogate.JsonResourceSurrogateAuthenticationService; import org.apereo.cas.authentication.surrogate.LdapSurrogateUsernamePasswordService; import org.apereo.cas.authentication.surrogate.SimpleSurrogateAuthenticationService; import org.apereo.cas.authentication.surrogate.SurrogateAuthenticationService; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.configuration.model.support.surrogate.SurrogateAuthenticationProperties; import org.apereo.cas.configuration.support.Beans; import org.apereo.cas.web.flow.CasWebflowConfigurer; import org.apereo.cas.web.flow.SurrogateInitialAuthenticationAction; import org.apereo.cas.web.flow.SurrogateSelectionAction; import org.apereo.cas.web.flow.SurrogateWebflowConfigurer; import org.apereo.cas.web.flow.resolver.CasDelegatingWebflowEventResolver; import org.apereo.cas.web.flow.resolver.CasWebflowEventResolver; import org.apereo.services.persondir.IPersonAttributeDao; import org.ldaptive.ConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.BeanCreationException; 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.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.util.StringUtils; import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; import org.springframework.webflow.execution.Action; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; /** * This is {@link SurrogateAuthenticationConfiguration}. * * @author Misagh Moayyed * @author John Gasper * @since 5.1.0 */ @Configuration("surrogateAuthenticationConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) @EnableAspectJAutoProxy public class SurrogateAuthenticationConfiguration implements AuthenticationEventExecutionPlanConfigurer { private static final Logger LOGGER = LoggerFactory.getLogger(SurrogateAuthenticationConfiguration.class); @Autowired private CasConfigurationProperties casProperties; @Autowired @Qualifier("adaptiveAuthenticationPolicy") private AdaptiveAuthenticationPolicy adaptiveAuthenticationPolicy; @Autowired @Qualifier("serviceTicketRequestWebflowEventResolver") private CasWebflowEventResolver serviceTicketRequestWebflowEventResolver; @Autowired @Qualifier("initialAuthenticationAttemptWebflowEventResolver") private CasDelegatingWebflowEventResolver initialAuthenticationAttemptWebflowEventResolver; @Autowired @Qualifier("loginFlowRegistry") private FlowDefinitionRegistry loginFlowDefinitionRegistry; @Autowired private FlowBuilderServices flowBuilderServices; @ConditionalOnMissingBean(name = "surrogateWebflowConfigurer") @Bean public CasWebflowConfigurer surrogateWebflowConfigurer() { return new SurrogateWebflowConfigurer(flowBuilderServices, loginFlowDefinitionRegistry, selectSurrogateAction()); } @ConditionalOnMissingBean(name = "selectSurrogateAction") @Bean public Action selectSurrogateAction() { return new SurrogateSelectionAction(casProperties.getAuthn().getSurrogate().getSeparator()); } @Bean public Action authenticationViaFormAction() { return new SurrogateInitialAuthenticationAction(initialAuthenticationAttemptWebflowEventResolver, serviceTicketRequestWebflowEventResolver, adaptiveAuthenticationPolicy, casProperties.getAuthn().getSurrogate().getSeparator(), surrogateAuthenticationService()); } @RefreshScope @ConditionalOnMissingBean(name = "surrogateAuthenticationService") @Bean public SurrogateAuthenticationService surrogateAuthenticationService() { try { final SurrogateAuthenticationProperties su = casProperties.getAuthn().getSurrogate(); if (su.getJson().getConfig().getLocation() != null) { LOGGER.debug("Using JSON resource [{}] to locate surrogate accounts", su.getJson().getConfig().getLocation()); return new JsonResourceSurrogateAuthenticationService(su.getJson().getConfig().getLocation()); } if (StringUtils.hasText(su.getLdap().getLdapUrl()) && StringUtils.hasText(su.getLdap().getSearchFilter()) && StringUtils.hasText(su.getLdap().getBaseDn()) && StringUtils.hasText(su.getLdap().getMemberAttributeName())) { LOGGER.debug("Using LDAP [{}] with baseDn [{}] to locate surrogate accounts", su.getLdap().getLdapUrl(), su.getLdap().getBaseDn()); final ConnectionFactory factory = Beans.newLdaptivePooledConnectionFactory(su.getLdap()); return new LdapSurrogateUsernamePasswordService(factory, su.getLdap()); } final Map<String, Set> accounts = new LinkedHashMap<>(); su.getSimple().getSurrogates().forEach((k, v) -> accounts.put(k, StringUtils.commaDelimitedListToSet(v))); LOGGER.debug("Using accounts [{}] for surrogate authentication", accounts); return new SimpleSurrogateAuthenticationService(accounts); } catch (final Exception e) { throw new BeanCreationException(e.getMessage(), e); } } @Bean public SurrogateAuthenticationAspect surrogateAuthenticationAspect() { return new SurrogateAuthenticationAspect(new DefaultPrincipalFactory(), surrogateAuthenticationService()); } @Autowired @RefreshScope @Bean public PrincipalResolver personDirectoryPrincipalResolver(@Qualifier("attributeRepository") final IPersonAttributeDao attributeRepository, @Qualifier("principalFactory") final PrincipalFactory principalFactory) { final SurrogatePrincipalResolver bean = new SurrogatePrincipalResolver(); bean.setAttributeRepository(attributeRepository); bean.setPrincipalAttributeName(casProperties.getPersonDirectory().getPrincipalAttribute()); bean.setReturnNullIfNoAttributes(casProperties.getPersonDirectory().isReturnNull()); bean.setPrincipalFactory(principalFactory); return bean; } @Bean public PrincipalIdProvider principalIdProvider() { return new SurrogatePrincipalIdProvider(); } }