package org.apereo.cas.integration.pac4j.authentication.handler.support;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.HandlerResult;
import org.apereo.cas.authentication.PreventedException;
import org.apereo.cas.authentication.handler.support.AbstractPac4jAuthenticationHandler;
import org.apereo.cas.authentication.principal.ClientCredential;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.web.support.WebUtils;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.Credentials;
import org.pac4j.core.credentials.authenticator.Authenticator;
import org.pac4j.core.profile.UserProfile;
import org.pac4j.core.profile.creator.AuthenticatorProfileCreator;
import org.pac4j.core.profile.creator.ProfileCreator;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.core.util.InitializableObject;
import org.pac4j.core.util.InitializableWebObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.login.FailedLoginException;
import java.security.GeneralSecurityException;
/**
* Abstract pac4j authentication handler which uses a pac4j authenticator and profile creator.
*
* @author Jerome Leleu
* @param <I> the type parameter
* @param <C> the type parameter
* @since 4.2.0
*/
public abstract class AbstractWrapperAuthenticationHandler<I extends Credential, C extends Credentials>
extends AbstractPac4jAuthenticationHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractWrapperAuthenticationHandler.class);
/**
* The pac4j profile creator used for authentication.
*/
protected ProfileCreator profileCreator = AuthenticatorProfileCreator.INSTANCE;
public AbstractWrapperAuthenticationHandler(final String name, final ServicesManager servicesManager, final PrincipalFactory principalFactory,
final Integer order) {
super(name, servicesManager, principalFactory, order);
}
@Override
public boolean supports(final Credential credential) {
return credential != null && getCasCredentialsType().isAssignableFrom(credential.getClass());
}
@Override
protected HandlerResult doAuthentication(final Credential credential) throws GeneralSecurityException, PreventedException {
CommonHelper.assertNotNull("profileCreator", this.profileCreator);
final C credentials = convertToPac4jCredentials((I) credential);
LOGGER.debug("credentials: [{}]", credentials);
try {
final Authenticator authenticator = getAuthenticator(credential);
if (authenticator instanceof InitializableObject) {
((InitializableObject) authenticator).init();
}
if (authenticator instanceof InitializableWebObject) {
((InitializableWebObject) authenticator).init(getWebContext());
}
CommonHelper.assertNotNull("authenticator", authenticator);
authenticator.validate(credentials, getWebContext());
final UserProfile profile = this.profileCreator.create(credentials, getWebContext());
LOGGER.debug("profile: [{}]", profile);
return createResult(new ClientCredential(credentials), profile);
} catch (final Exception e) {
LOGGER.error("Failed to validate credentials", e);
throw new FailedLoginException("Failed to validate credentials: " + e.getMessage());
}
}
/**
* Gets the web context from the current thread-bound object.
*
* @return the web context
*/
protected static WebContext getWebContext() {
return WebUtils.getPac4jJ2EContext(
WebUtils.getHttpServletRequestFromRequestAttributes(),
WebUtils.getHttpServletResponseFromRequestAttributes());
}
/**
* Convert a CAS credential into a pac4j credentials to play the authentication.
*
* @param casCredential the CAS credential
* @return the pac4j credentials
* @throws GeneralSecurityException On authentication failure.
* @throws PreventedException On the indeterminate case when authentication is prevented.
*/
protected abstract C convertToPac4jCredentials(I casCredential) throws GeneralSecurityException,
PreventedException;
/**
* Return the CAS credential supported by this handler (to be converted in a pac4j credentials
* by {@link #convertToPac4jCredentials(Credential)}).
*
* @return the CAS credential class
*/
protected abstract Class<I> getCasCredentialsType();
/**
* Gets authenticator.
*
* @param credential the credential
* @return the authenticator
*/
protected abstract Authenticator getAuthenticator(Credential credential);
public ProfileCreator getProfileCreator() {
return this.profileCreator;
}
public void setProfileCreator(final ProfileCreator profileCreator) {
this.profileCreator = profileCreator;
}
}