package org.apereo.cas.authentication;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.services.UnauthorizedSsoServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* This is {@link RegisteredServiceAuthenticationHandlerResolver}
* that acts on the criteria presented by a registered service to
* detect which handler(s) should be resolved for authentication.
*
* @author Misagh Moayyed
* @since 5.0.0
*/
public class RegisteredServiceAuthenticationHandlerResolver implements AuthenticationHandlerResolver {
private static final Logger LOGGER = LoggerFactory.getLogger(RegisteredServiceAuthenticationHandlerResolver.class);
/**
* The Services manager.
*/
protected final ServicesManager servicesManager;
/**
* Instantiates a new Registered service authentication handler resolver.
*
* @param servicesManager the services manager
*/
public RegisteredServiceAuthenticationHandlerResolver(final ServicesManager servicesManager) {
this.servicesManager = servicesManager;
}
@Override
public Set<AuthenticationHandler> resolve(final Set<AuthenticationHandler> candidateHandlers,
final AuthenticationTransaction transaction) {
final Service service = transaction.getService();
if (service != null && this.servicesManager != null) {
final RegisteredService registeredService = this.servicesManager.findServiceBy(service);
if (registeredService == null || !registeredService.getAccessStrategy().isServiceAccessAllowed()) {
LOGGER.warn("Service [{}] is not allowed to use SSO.", registeredService);
throw new UnauthorizedSsoServiceException();
}
if (!registeredService.getRequiredHandlers().isEmpty()) {
LOGGER.debug("Authentication transaction requires [{}] for service [{}]", registeredService.getRequiredHandlers(), service);
final Set<AuthenticationHandler> handlerSet = new LinkedHashSet<>(candidateHandlers);
LOGGER.info("Candidate authentication handlers examined this transaction are [{}]", handlerSet);
final Iterator<AuthenticationHandler> it = handlerSet.iterator();
while (it.hasNext()) {
final AuthenticationHandler handler = it.next();
if (!(handler instanceof HttpBasedServiceCredentialsAuthenticationHandler)
&& !registeredService.getRequiredHandlers().contains(handler.getName())) {
LOGGER.debug("Authentication handler [{}] is not required for this transaction and is removed", handler.getName());
it.remove();
}
}
LOGGER.debug("Authentication handlers for this transaction are [{}]", handlerSet);
return handlerSet;
}
LOGGER.debug("No specific authentication handlers are required for this transaction");
}
final String handlers = candidateHandlers.stream().map(AuthenticationHandler::getName).collect(Collectors.joining());
LOGGER.debug("Authentication handlers used for this transaction are [{}]", handlers);
return candidateHandlers;
}
}