Core authentication API module for Apereo CAS providing fundamental authentication interfaces, implementations, and components for the CAS server infrastructure
—
Authentication handlers are core components responsible for validating credentials against various authentication sources such as LDAP directories, databases, web services, and local user stores. The CAS authentication API provides a comprehensive framework for implementing and configuring authentication handlers.
package org.apereo.cas.authentication;
import java.security.GeneralSecurityException;
public interface AuthenticationHandler {
String getName();
boolean supports(Credential credential);
AuthenticationHandlerExecutionResult authenticate(Credential credential)
throws GeneralSecurityException, PreventedException;
Integer getOrder();
AuthenticationHandlerStates getState();
void setState(AuthenticationHandlerStates state);
Predicate<Credential> getCredentialSelectionPredicate();
}package org.apereo.cas.authentication;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
public abstract class AbstractAuthenticationHandler implements AuthenticationHandler {
protected final PrincipalFactory principalFactory;
private final ServicesManager servicesManager;
private final String name;
private final Integer order;
private AuthenticationHandlerStates state;
protected AbstractAuthenticationHandler(String name,
ServicesManager servicesManager,
PrincipalFactory principalFactory,
Integer order) {
this.name = name;
this.servicesManager = servicesManager;
this.principalFactory = principalFactory;
this.order = order;
this.state = AuthenticationHandlerStates.ACTIVE;
}
public String getName() { return name; }
public Integer getOrder() { return order; }
public AuthenticationHandlerStates getState() { return state; }
public void setState(AuthenticationHandlerStates state) { this.state = state; }
protected ServicesManager getServicesManager() { return servicesManager; }
protected PrincipalFactory getPrincipalFactory() { return principalFactory; }
}package org.apereo.cas.authentication.handler.support;
import org.apereo.cas.authentication.AbstractAuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.credential.UsernamePasswordCredential;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
public abstract class AbstractUsernamePasswordAuthenticationHandler
extends AbstractAuthenticationHandler {
protected AbstractUsernamePasswordAuthenticationHandler(String name,
ServicesManager servicesManager,
PrincipalFactory principalFactory,
Integer order) {
super(name, servicesManager, principalFactory, order);
}
public boolean supports(Credential credential) {
return credential instanceof UsernamePasswordCredential;
}
public final AuthenticationHandlerExecutionResult authenticate(Credential credential)
throws GeneralSecurityException, PreventedException {
UsernamePasswordCredential usernamePasswordCredential = (UsernamePasswordCredential) credential;
String originalPassword = usernamePasswordCredential.toPassword();
AuthenticationHandlerExecutionResult result =
authenticateUsernamePasswordInternal(usernamePasswordCredential, originalPassword);
return result;
}
protected abstract AuthenticationHandlerExecutionResult
authenticateUsernamePasswordInternal(UsernamePasswordCredential credential,
String originalPassword)
throws GeneralSecurityException, PreventedException;
}Simple handler that authenticates against a predefined map of users and passwords:
package org.apereo.cas.authentication;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import java.util.Map;
public class AcceptUsersAuthenticationHandler
extends AbstractUsernamePasswordAuthenticationHandler {
private Map<String, String> users;
public AcceptUsersAuthenticationHandler(Map<String, String> users) {
this(AcceptUsersAuthenticationHandler.class.getSimpleName(),
null, new DefaultPrincipalFactory(), null, users);
}
public AcceptUsersAuthenticationHandler(String name,
ServicesManager servicesManager,
PrincipalFactory principalFactory,
Integer order,
Map<String, String> users) {
super(name, servicesManager, principalFactory, order);
this.users = users;
}
protected AuthenticationHandlerExecutionResult
authenticateUsernamePasswordInternal(UsernamePasswordCredential credential,
String originalPassword)
throws GeneralSecurityException {
String username = credential.getUsername();
String password = credential.toPassword();
String expectedPassword = users.get(username);
if (expectedPassword != null && expectedPassword.equals(password)) {
Principal principal = principalFactory.createPrincipal(username);
return createHandlerResult(credential, principal, null);
}
throw new FailedLoginException();
}
public void setUsers(Map<String, String> users) {
this.users = users;
}
}package org.apereo.cas.authentication.handler.support;
import org.apereo.cas.authentication.AbstractAuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.PreventedException;
import java.security.GeneralSecurityException;
public abstract class AbstractPreAndPostProcessingAuthenticationHandler
extends AbstractAuthenticationHandler {
protected AbstractPreAndPostProcessingAuthenticationHandler(String name,
ServicesManager servicesManager,
PrincipalFactory principalFactory,
Integer order) {
super(name, servicesManager, principalFactory, order);
}
public final AuthenticationHandlerExecutionResult authenticate(Credential credential)
throws GeneralSecurityException, PreventedException {
if (!preProcess(credential)) {
throw new PreventedException("Pre-processing failed");
}
try {
AuthenticationHandlerExecutionResult result = doAuthentication(credential);
if (!postProcess(credential, result)) {
throw new PreventedException("Post-processing failed");
}
return result;
} catch (Exception e) {
handleAuthenticationException(credential, e);
throw e;
}
}
protected boolean preProcess(Credential credential) { return true; }
protected boolean postProcess(Credential credential,
AuthenticationHandlerExecutionResult result) { return true; }
protected void handleAuthenticationException(Credential credential, Exception e) { }
protected abstract AuthenticationHandlerExecutionResult doAuthentication(Credential credential)
throws GeneralSecurityException, PreventedException;
}package org.apereo.cas.authentication.handler.support;
import org.apereo.cas.authentication.AbstractAuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.authentication.credential.HttpBasedServiceCredential;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
public class ProxyAuthenticationHandler extends AbstractAuthenticationHandler {
public ProxyAuthenticationHandler(String name,
ServicesManager servicesManager,
PrincipalFactory principalFactory,
Integer order) {
super(name, servicesManager, principalFactory, order);
}
public boolean supports(Credential credential) {
return credential instanceof HttpBasedServiceCredential;
}
public AuthenticationHandlerExecutionResult authenticate(Credential credential)
throws GeneralSecurityException, PreventedException {
HttpBasedServiceCredential httpCredential = (HttpBasedServiceCredential) credential;
if (httpCredential.getService() != null && httpCredential.getCallbackUrl() != null) {
Principal principal = principalFactory.createPrincipal(httpCredential.getId());
return createHandlerResult(credential, principal, null);
}
throw new FailedLoginException("Invalid HTTP-based service credential");
}
}Handler resolvers determine which authentication handlers should be used for specific authentication requests.
package org.apereo.cas.authentication.handler;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationTransaction;
import java.util.Set;
public interface AuthenticationHandlerResolver {
Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
AuthenticationTransaction transaction);
boolean supports(Set<AuthenticationHandler> handlers,
AuthenticationTransaction transaction);
}
public class DefaultAuthenticationHandlerResolver implements AuthenticationHandlerResolver {
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
AuthenticationTransaction transaction) {
return candidateHandlers.stream()
.filter(handler -> handler.getState() == AuthenticationHandlerStates.ACTIVE)
.filter(handler -> transaction.getCredentials().stream()
.anyMatch(handler::supports))
.collect(Collectors.toSet());
}
public boolean supports(Set<AuthenticationHandler> handlers,
AuthenticationTransaction transaction) {
return true;
}
}package org.apereo.cas.authentication.handler;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationTransaction;
import org.apereo.cas.authentication.Credential;
public class ByCredentialTypeAuthenticationHandlerResolver
implements AuthenticationHandlerResolver {
private Class<? extends Credential> credentialType;
public ByCredentialTypeAuthenticationHandlerResolver(Class<? extends Credential> credentialType) {
this.credentialType = credentialType;
}
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
AuthenticationTransaction transaction) {
return candidateHandlers.stream()
.filter(handler -> transaction.getCredentials().stream()
.anyMatch(credential -> credentialType.isInstance(credential) && handler.supports(credential)))
.collect(Collectors.toSet());
}
public boolean supports(Set<AuthenticationHandler> handlers,
AuthenticationTransaction transaction) {
return transaction.getCredentials().stream()
.anyMatch(credentialType::isInstance);
}
}package org.apereo.cas.authentication.handler;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationTransaction;
import org.apereo.cas.authentication.credential.UsernamePasswordCredential;
public class ByCredentialSourceAuthenticationHandlerResolver
implements AuthenticationHandlerResolver {
private String source;
public ByCredentialSourceAuthenticationHandlerResolver(String source) {
this.source = source;
}
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
AuthenticationTransaction transaction) {
return candidateHandlers.stream()
.filter(handler -> transaction.getCredentials().stream()
.anyMatch(credential -> matchesSource(credential) && handler.supports(credential)))
.collect(Collectors.toSet());
}
private boolean matchesSource(Credential credential) {
if (credential instanceof UsernamePasswordCredential) {
UsernamePasswordCredential upc = (UsernamePasswordCredential) credential;
return source.equals(upc.getSource());
}
return false;
}
public boolean supports(Set<AuthenticationHandler> handlers,
AuthenticationTransaction transaction) {
return transaction.getCredentials().stream()
.anyMatch(this::matchesSource);
}
}package org.apereo.cas.authentication.handler;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationTransaction;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.ServicesManager;
public class RegisteredServiceAuthenticationHandlerResolver
implements AuthenticationHandlerResolver {
private ServicesManager servicesManager;
public RegisteredServiceAuthenticationHandlerResolver(ServicesManager servicesManager) {
this.servicesManager = servicesManager;
}
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
AuthenticationTransaction transaction) {
Service service = transaction.getService();
if (service == null) {
return candidateHandlers;
}
RegisteredService registeredService = servicesManager.findServiceBy(service);
if (registeredService == null || registeredService.getAuthenticationPolicy() == null) {
return candidateHandlers;
}
Set<String> requiredHandlers = registeredService.getAuthenticationPolicy()
.getRequiredAuthenticationHandlers();
if (requiredHandlers.isEmpty()) {
return candidateHandlers;
}
return candidateHandlers.stream()
.filter(handler -> requiredHandlers.contains(handler.getName()))
.collect(Collectors.toSet());
}
public boolean supports(Set<AuthenticationHandler> handlers,
AuthenticationTransaction transaction) {
return transaction.getService() != null;
}
}package org.apereo.cas.authentication.handler;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationTransaction;
import org.apereo.cas.util.scripting.ExecutableCompiledGroovyScript;
public class GroovyAuthenticationHandlerResolver implements AuthenticationHandlerResolver {
private ExecutableCompiledGroovyScript watchableScript;
public GroovyAuthenticationHandlerResolver(ExecutableCompiledGroovyScript watchableScript) {
this.watchableScript = watchableScript;
}
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
AuthenticationTransaction transaction) {
Object result = watchableScript.execute(candidateHandlers, transaction,
AuthenticationHandler.class);
if (result instanceof Set) {
return (Set<AuthenticationHandler>) result;
} else if (result instanceof Collection) {
return new LinkedHashSet<>((Collection<AuthenticationHandler>) result);
}
return candidateHandlers;
}
public boolean supports(Set<AuthenticationHandler> handlers,
AuthenticationTransaction transaction) {
return watchableScript != null;
}
}The authentication API provides JAAS (Java Authentication and Authorization Service) integration:
package org.apereo.cas.authentication.handler.support.jaas;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
public class JaasAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
private String realm;
private String kerberosKdcSystemProperty;
private String kerberosRealmSystemProperty;
public JaasAuthenticationHandler(String name,
ServicesManager servicesManager,
PrincipalFactory principalFactory,
Integer order,
String realm) {
super(name, servicesManager, principalFactory, order);
this.realm = realm;
}
protected AuthenticationHandlerExecutionResult
authenticateUsernamePasswordInternal(UsernamePasswordCredential credential,
String originalPassword)
throws GeneralSecurityException {
try {
String username = credential.getUsername();
LoginContext loginContext = createLoginContext(credential);
loginContext.login();
Principal principal = principalFactory.createPrincipal(username);
return createHandlerResult(credential, principal, null);
} catch (LoginException e) {
throw new FailedLoginException("JAAS authentication failed: " + e.getMessage());
}
}
private LoginContext createLoginContext(UsernamePasswordCredential credential)
throws LoginException {
return new LoginContext(realm, new JaasUsernamePasswordCallbackHandler(
credential.getUsername(), credential.getPassword()));
}
}@Configuration
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class AuthenticationHandlerConfiguration {
@Bean
public AuthenticationHandler acceptUsersAuthenticationHandler() {
Map<String, String> users = Map.of(
"admin", "password",
"user", "secret"
);
return new AcceptUsersAuthenticationHandler(users);
}
@Bean
public AuthenticationHandlerResolver defaultAuthenticationHandlerResolver() {
return new DefaultAuthenticationHandlerResolver();
}
@Bean
public AuthenticationHandlerResolver credentialTypeResolver() {
return new ByCredentialTypeAuthenticationHandlerResolver(
UsernamePasswordCredential.class);
}
}// Create authentication handler
AcceptUsersAuthenticationHandler handler = new AcceptUsersAuthenticationHandler(
"TestHandler",
servicesManager,
new DefaultPrincipalFactory(),
100,
Map.of("testuser", "testpass")
);
// Configure handler state
handler.setState(AuthenticationHandlerStates.ACTIVE);
// Create resolver for specific credential types
AuthenticationHandlerResolver resolver =
new ByCredentialTypeAuthenticationHandlerResolver(UsernamePasswordCredential.class);
// Register in execution plan
authenticationEventExecutionPlan.registerAuthenticationHandler(handler);
authenticationEventExecutionPlan.registerAuthenticationHandlerResolver(resolver);Authentication handlers provide the core credential validation logic in CAS authentication workflows. They can be customized and extended to integrate with virtually any authentication source or protocol, making them a flexible foundation for enterprise authentication requirements.
Install with Tessl CLI
npx tessl i tessl/maven-org-apereo-cas--cas-server-core-authentication-api