package org.apereo.cas.otp.config; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import org.apereo.cas.CentralAuthenticationService; import org.apereo.cas.authentication.AuthenticationServiceSelectionPlan; import org.apereo.cas.authentication.AuthenticationSystemSupport; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.otp.repository.token.CachingOneTimeTokenRepository; import org.apereo.cas.otp.repository.token.OneTimeToken; import org.apereo.cas.otp.repository.token.OneTimeTokenRepository; import org.apereo.cas.otp.web.flow.OneTimeTokenAuthenticationWebflowAction; import org.apereo.cas.otp.web.flow.OneTimeTokenAuthenticationWebflowEventResolver; import org.apereo.cas.otp.web.flow.rest.OneTimeTokenQRGeneratorController; import org.apereo.cas.services.MultifactorAuthenticationProviderSelector; import org.apereo.cas.services.ServicesManager; import org.apereo.cas.ticket.registry.TicketRegistrySupport; import org.apereo.cas.web.flow.authentication.RankedMultifactorAuthenticationProviderSelector; import org.apereo.cas.web.flow.resolver.CasWebflowEventResolver; 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.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.util.CookieGenerator; import org.springframework.webflow.execution.Action; import java.util.Collection; import java.util.concurrent.TimeUnit; /** * This is {@link OneTimeTokenAuthenticationConfiguration}. * * @author Misagh Moayyed * @since 5.1.0 */ @Configuration("oneTimeTokenAuthenticationConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) @EnableScheduling public class OneTimeTokenAuthenticationConfiguration { private static final int EXPIRE_TOKENS_IN_SECONDS = 30; private static final int INITIAL_CACHE_SIZE = 50; private static final long MAX_CACHE_SIZE = 1_000; private static final Logger LOGGER = LoggerFactory.getLogger(OneTimeTokenAuthenticationConfiguration.class); @Autowired @Qualifier("centralAuthenticationService") private CentralAuthenticationService centralAuthenticationService; @Autowired @Qualifier("defaultAuthenticationSystemSupport") private AuthenticationSystemSupport authenticationSystemSupport; @Autowired @Qualifier("defaultTicketRegistrySupport") private TicketRegistrySupport ticketRegistrySupport; @Autowired @Qualifier("servicesManager") private ServicesManager servicesManager; @Autowired(required = false) @Qualifier("multifactorAuthenticationProviderSelector") private MultifactorAuthenticationProviderSelector multifactorAuthenticationProviderSelector = new RankedMultifactorAuthenticationProviderSelector(); @Autowired @Qualifier("warnCookieGenerator") private CookieGenerator warnCookieGenerator; @Autowired @Qualifier("authenticationServiceSelectionPlan") private AuthenticationServiceSelectionPlan authenticationRequestServiceSelectionStrategies; @Bean @RefreshScope public CasWebflowEventResolver oneTimeTokenAuthenticationWebflowEventResolver() { return new OneTimeTokenAuthenticationWebflowEventResolver(authenticationSystemSupport, centralAuthenticationService, servicesManager, ticketRegistrySupport, warnCookieGenerator, authenticationRequestServiceSelectionStrategies, multifactorAuthenticationProviderSelector); } @Bean @RefreshScope public Action oneTimeTokenAuthenticationWebflowAction() { return new OneTimeTokenAuthenticationWebflowAction(oneTimeTokenAuthenticationWebflowEventResolver()); } @Bean public OneTimeTokenQRGeneratorController oneTimeTokenQRGeneratorController() { return new OneTimeTokenQRGeneratorController(); } @ConditionalOnMissingBean(name = "oneTimeTokenAuthenticatorTokenRepository") @Bean public OneTimeTokenRepository oneTimeTokenAuthenticatorTokenRepository() { final LoadingCache<String, Collection<OneTimeToken>> storage = CacheBuilder.newBuilder() .initialCapacity(INITIAL_CACHE_SIZE) .maximumSize(MAX_CACHE_SIZE) .recordStats() .expireAfterWrite(EXPIRE_TOKENS_IN_SECONDS, TimeUnit.SECONDS) .build(new CacheLoader<String, Collection<OneTimeToken>>() { @Override public Collection<OneTimeToken> load(final String s) throws Exception { LOGGER.error("Load operation of the cache is not supported."); return null; } }); return new CachingOneTimeTokenRepository(storage); } }