CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apereo-cas--cas-server-core-authentication-api

Core authentication API module for Apereo CAS providing fundamental authentication interfaces, implementations, and components for the CAS server infrastructure

Pending
Overview
Eval results
Files

authentication-handlers.mddocs/

Authentication Handlers

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.

Core Handler Interface

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();
}

Base Handler Implementation

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; }
}

Username/Password Authentication

Abstract Username/Password Handler

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;
}

Accept Users Handler

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;
    }
}

Pre/Post Processing Handler

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;
}

Proxy Authentication Handler

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

Handler resolvers determine which authentication handlers should be used for specific authentication requests.

Default Handler Resolver

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;
    }
}

Credential Type Resolver

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);
    }
}

Credential Source Resolver

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);
    }
}

Registered Service Resolver

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;
    }
}

Groovy Handler Resolver

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;
    }
}

JAAS Authentication Support

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()));
    }
}

Handler Configuration Examples

Spring Configuration

@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);
    }
}

Programmatic Configuration

// 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

docs

adaptive-authentication.md

authentication-handlers.md

authentication-policies.md

credential-handling.md

index.md

password-policies.md

principal-resolution.md

tile.json