package org.apereo.cas.web.flow.authentication;
import org.apereo.cas.CentralAuthenticationService;
import org.apereo.cas.authentication.AuthenticationServiceSelectionPlan;
import org.apereo.cas.authentication.AuthenticationSystemSupport;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.services.MultifactorAuthenticationProvider;
import org.apereo.cas.services.MultifactorAuthenticationProviderResolver;
import org.apereo.cas.services.MultifactorAuthenticationProviderSelector;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.RegisteredServiceAccessStrategyUtils;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.services.VariegatedMultifactorAuthenticationProvider;
import org.apereo.cas.ticket.registry.TicketRegistrySupport;
import org.apereo.cas.web.flow.resolver.impl.AbstractCasWebflowEventResolver;
import org.springframework.web.util.CookieGenerator;
import org.springframework.webflow.execution.RequestContext;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
/**
* This is {@link BaseMultifactorAuthenticationProviderEventResolver}.
*
* @author Misagh Moayyed
* @since 5.1.0
*/
public abstract class BaseMultifactorAuthenticationProviderEventResolver extends AbstractCasWebflowEventResolver
implements MultifactorAuthenticationProviderResolver {
public BaseMultifactorAuthenticationProviderEventResolver(final AuthenticationSystemSupport authenticationSystemSupport,
final CentralAuthenticationService centralAuthenticationService,
final ServicesManager servicesManager,
final TicketRegistrySupport ticketRegistrySupport,
final CookieGenerator warnCookieGenerator,
final AuthenticationServiceSelectionPlan authenticationSelectionStrategies,
final MultifactorAuthenticationProviderSelector selector) {
super(authenticationSystemSupport, centralAuthenticationService, servicesManager,
ticketRegistrySupport, warnCookieGenerator,
authenticationSelectionStrategies, selector);
}
@Override
public Optional<MultifactorAuthenticationProvider> resolveProvider(final Map<String, MultifactorAuthenticationProvider> providers,
final Collection<String> requestMfaMethod) {
final Optional<MultifactorAuthenticationProvider> providerFound = providers.values()
.stream()
.filter(p -> requestMfaMethod.stream().anyMatch(p::matches))
.findFirst();
if (providerFound.isPresent()) {
final MultifactorAuthenticationProvider provider = providerFound.get();
if (provider instanceof VariegatedMultifactorAuthenticationProvider) {
final VariegatedMultifactorAuthenticationProvider multi = VariegatedMultifactorAuthenticationProvider.class.cast(provider);
return multi.getProviders()
.stream()
.filter(p -> requestMfaMethod.stream().anyMatch(p::matches))
.findFirst();
}
}
return providerFound;
}
/**
* Locate the provider in the collection, and have it match the requested mfa.
* If the provider is multi-instance, resolve based on inner-registered providers.
*
* @param providers the providers
* @param requestMfaMethod the request mfa method
* @return the optional
*/
public Optional<MultifactorAuthenticationProvider> resolveProvider(final Map<String, MultifactorAuthenticationProvider> providers,
final String requestMfaMethod) {
return resolveProvider(providers, Collections.singleton(requestMfaMethod));
}
@Override
public Collection<MultifactorAuthenticationProvider> flattenProviders(final Collection<? extends MultifactorAuthenticationProvider> providers) {
final Collection<MultifactorAuthenticationProvider> flattenedProviders = new HashSet<>();
providers.forEach(p -> {
if (p instanceof VariegatedMultifactorAuthenticationProvider) {
flattenedProviders.addAll(VariegatedMultifactorAuthenticationProvider.class.cast(p).getProviders());
} else {
flattenedProviders.add(p);
}
});
return flattenedProviders;
}
/**
* Resolve registered service in request context.
*
* @param requestContext the request context
* @return the registered service
*/
protected RegisteredService resolveRegisteredServiceInRequestContext(final RequestContext requestContext) {
final Service resolvedService = resolveServiceFromAuthenticationRequest(requestContext);
final RegisteredService service = this.servicesManager.findServiceBy(resolvedService);
RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(resolvedService, service);
return service;
}
}