CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apereo-cas--cas-server-core-webflow-mfa-api

Core API for multifactor authentication webflow configuration in Apereo CAS providing interfaces and base classes for MFA provider integration

Pending
Overview
Eval results
Files

provider-selection.mddocs/

Provider Selection

Specialized components for handling composite MFA scenarios where multiple providers are available and selection logic is required. These components manage the process of presenting provider choices to users and handling their selections with persistence capabilities.

Capabilities

MultifactorProviderSelectionCriteria

Functional interface that defines strategy for determining when to proceed with MFA provider selection.

/**
 * Strategy interface for determining when to proceed with MFA provider selection
 */
@FunctionalInterface
public interface MultifactorProviderSelectionCriteria {
    
    /**
     * Determine if MFA provider selection should proceed
     * @param requestContext The webflow request context
     * @return true if provider selection should proceed
     */
    boolean shouldProceedWithMultifactorProviderSelection(RequestContext requestContext);
    
    /**
     * Static factory method for creating default criteria
     * @return Default criteria instance
     */
    static MultifactorProviderSelectionCriteria select() {
        return context -> true; // Default implementation always proceeds
    }
}

Usage Example:

// Custom selection criteria
MultifactorProviderSelectionCriteria customCriteria = requestContext -> {
    val authentication = WebUtils.getAuthentication(requestContext);
    val principal = authentication.getPrincipal();
    
    // Only proceed with selection if user has multiple registered devices
    val devices = getRegisteredDevicesForUser(principal);
    return devices.size() > 1;
};

// Use in action configuration
@Bean
public MultifactorProviderSelectionCriteria mfaSelectionCriteria() {
    return MultifactorProviderSelectionCriteria.select(); // or custom implementation
}

MultifactorProviderSelectionAction

Action that evaluates selection criteria to determine if provider selection should proceed.

/**
 * Action that evaluates selection criteria to determine if provider selection should proceed
 */
public class MultifactorProviderSelectionAction extends BaseCasWebflowAction {
    
    /**
     * Constructor
     * @param selectionCriteria Criteria for determining if selection should proceed
     */
    public MultifactorProviderSelectionAction(MultifactorProviderSelectionCriteria selectionCriteria);
    
    /**
     * Execute provider selection evaluation
     * @param requestContext The webflow request context
     * @return Event indicating whether to proceed with selection (yes/no)
     * @throws Exception If evaluation fails
     */
    @Override
    protected Event doExecuteInternal(RequestContext requestContext) throws Exception;
}

PrepareMultifactorProviderSelectionAction

Prepares available MFA providers for selection based on availability and bypass rules.

/**
 * Action that prepares available MFA providers for selection based on availability and bypass rules
 */
public class PrepareMultifactorProviderSelectionAction extends BaseCasWebflowAction {
    
    /**
     * Constructor
     * @param applicationContext Spring application context
     */
    public PrepareMultifactorProviderSelectionAction(ConfigurableApplicationContext applicationContext);
    
    /**
     * Execute provider preparation for selection
     * @param requestContext The webflow request context
     * @return Event indicating success or failure of preparation
     * @throws Exception If preparation fails
     */
    @Override
    protected Event doExecuteInternal(RequestContext requestContext) throws Exception;
}

MultifactorProviderSelectedAction

Handles the selection of a specific MFA provider and remembers the choice via cookies.

/**
 * Action that handles selection of a specific MFA provider and remembers the choice
 */
public class MultifactorProviderSelectedAction extends BaseCasWebflowAction {
    
    /**
     * Request parameter name for the selected MFA provider
     */
    static final String PARAMETER_SELECTED_MFA_PROVIDER = "mfaProvider";
    
    /**
     * Constructor
     * @param multifactorProviderCookieBuilder Cookie generator for remembering selection
     * @param casProperties CAS configuration properties
     */
    public MultifactorProviderSelectedAction(
        CasCookieBuilder multifactorProviderCookieBuilder,
        CasConfigurationProperties casProperties);
    
    /**
     * Pre-execution hook for provider selection
     * @param context The webflow request context
     * @return Event result of pre-execution
     * @throws Exception If pre-execution fails
     */
    @Override
    protected Event doPreExecute(RequestContext context) throws Exception;
    
    /**
     * Execute provider selection handling
     * @param requestContext The webflow request context
     * @return Event indicating success or failure of selection
     * @throws Exception If selection handling fails
     */
    @Override
    protected Event doExecuteInternal(RequestContext requestContext) throws Exception;
    
    /**
     * Remember the selected multifactor authentication provider via cookie
     * @param context The webflow request context
     * @param providerId The selected provider ID
     */
    protected void rememberSelectedMultifactorAuthenticationProvider(RequestContext context, String providerId);
}

Complete Provider Selection Flow Example:

@Configuration
public class CompositeProviderSelectionConfiguration {
    
    @Bean
    public MultifactorProviderSelectionCriteria compositeProviderSelectionCriteria() {
        return requestContext -> {
            // Get available providers from flow scope
            val availableProviders = MultifactorAuthenticationWebflowUtils
                .getSelectableMultifactorAuthenticationProviders(requestContext);
            
            // Only proceed with selection if multiple providers are available
            return availableProviders != null && availableProviders.size() > 1;
        };
    }
    
    @Bean
    public Action multifactorProviderSelectionAction(
        MultifactorProviderSelectionCriteria selectionCriteria) {
        return new MultifactorProviderSelectionAction(selectionCriteria);
    }
    
    @Bean
    public Action prepareMultifactorProviderSelectionAction(
        ConfigurableApplicationContext applicationContext) {
        return new PrepareMultifactorProviderSelectionAction(applicationContext);
    }
    
    @Bean
    public Action multifactorProviderSelectedAction(
        @Qualifier("compositeProviderSelectionCookieGenerator") 
        CasCookieBuilder cookieGenerator,
        CasConfigurationProperties casProperties) {
        return new MultifactorProviderSelectedAction(cookieGenerator, casProperties);
    }
    
    @Bean
    public CasCookieBuilder compositeProviderSelectionCookieGenerator(
        CasConfigurationProperties casProperties) {
        return new DefaultCasCookieBuilder(
            "COMPOSITE_MFA_PROVIDER_SELECTION",
            casProperties.getSessionReplication().getCookie());
    }
}

Webflow Integration Example:

The provider selection actions are typically used in a webflow sequence like this:

<!-- Check if provider selection should proceed -->
<action-state id="checkCompositeProviderSelection">
    <evaluate expression="multifactorProviderSelectionAction"/>
    <transition on="yes" to="prepareProviderSelection"/>
    <transition on="no" to="mfaCheckAvailable"/>
</action-state>

<!-- Prepare available providers for selection -->
<action-state id="prepareProviderSelection">
    <evaluate expression="prepareMultifactorProviderSelectionAction"/>
    <transition on="success" to="viewProviderSelection"/>
    <transition on="error" to="mfaUnavailable"/>
</action-state>

<!-- Display provider selection view -->
<view-state id="viewProviderSelection" view="mfa/casCompositeProviderSelectionView">
    <transition on="submit" to="providerSelected"/>
</view-state>

<!-- Handle provider selection -->
<action-state id="providerSelected">
    <evaluate expression="multifactorProviderSelectedAction"/>
    <transition on="success" to="mfaCheckAvailable"/>
    <transition on="error" to="viewProviderSelection"/>
</action-state>

JSP/Thymeleaf View Example:

<!-- Provider selection form -->
<form method="post">
    <div class="mfa-provider-selection">
        <h3>Select Authentication Method</h3>
        
        <c:forEach var="provider" items="${mfaSelectableProviders}">
            <div class="provider-option">
                <input type="radio" 
                       name="mfaProvider" 
                       value="${provider}"
                       id="provider_${provider}"/>
                <label for="provider_${provider}">
                    ${provider} <!-- Or lookup friendly name -->
                </label>
            </div>
        </c:forEach>
        
        <button type="submit" name="_eventId" value="submit">Continue</button>
    </div>
</form>

Cookie-based Provider Memory

The MultifactorProviderSelectedAction automatically remembers user selections via cookies:

// Cookie configuration example
@Bean
public CasCookieBuilder compositeProviderSelectionCookieGenerator(
    CasConfigurationProperties casProperties) {
    
    val cookieProps = casProperties.getSessionReplication().getCookie();
    return CasCookieBuilder.builder()
        .name("COMPOSITE_MFA_PROVIDER_SELECTION")
        .domain(cookieProps.getDomain())
        .path(cookieProps.getPath())
        .maxAge(Duration.ofDays(30)) // Remember for 30 days
        .secure(cookieProps.isSecure())
        .httpOnly(cookieProps.isHttpOnly())
        .sameSitePolicy(cookieProps.getSameSitePolicy())
        .build();
}

This enables the system to automatically select the user's previously chosen provider in future authentication attempts, reducing friction while still allowing users to change their selection when needed.

Install with Tessl CLI

npx tessl i tessl/maven-org-apereo-cas--cas-server-core-webflow-mfa-api

docs

authentication-components.md

event-resolution.md

index.md

provider-selection.md

webflow-actions.md

webflow-configuration.md

webflow-utilities.md

tile.json