CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apereo-cas--cas-server-support-surrogate-api

Apereo CAS Surrogate Authentication API providing core interfaces and classes for surrogate authentication functionality

Pending
Overview
Eval results
Files

service-access-control.mddocs/

Service Access Control

Service-level access control strategies for surrogate authentication enable fine-grained authorization at the individual CAS service level. These strategies determine whether surrogate authentication is permitted for specific services and provide different authorization mechanisms including attribute-based and script-based control.

Capabilities

Base Access Strategy

Abstract base class providing common functionality for surrogate-aware service access strategies.

public abstract class BaseSurrogateRegisteredServiceAccessStrategy extends BaseRegisteredServiceAccessStrategy {
    
    /**
     * Check if the current request is from a surrogate authentication session.
     *
     * @param request the service access strategy request
     * @return true if this is a surrogate authentication session
     */
    protected boolean isSurrogateAuthenticationSession(RegisteredServiceAccessStrategyRequest request) {
        return request.getAttributes().containsKey(SurrogateAuthenticationService.AUTHENTICATION_ATTR_SURROGATE_ENABLED);
    }
}

Attribute-Based Access Strategy

Service access strategy that uses principal attributes to determine surrogate authentication authorization.

@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class SurrogateRegisteredServiceAccessStrategy extends BaseSurrogateRegisteredServiceAccessStrategy {
    
    /**
     * Defines the attribute aggregation behavior when checking for required attributes.
     * Default requires that all attributes be present and match the principal's.
     */
    protected boolean requireAllAttributes = true;

    /**
     * Indicates whether matching on required attribute values
     * should be done in a case-insensitive manner.
     */
    protected boolean caseInsensitive;
    
    /**
     * Required attributes for surrogate access authorization.
     * Map of attribute names to sets of required values.
     */
    private Map<String, Set<String>> surrogateRequiredAttributes = new HashMap<>(0);

    /**
     * Main authorization method for service access requests.
     *
     * @param request the service access request
     * @return true if access is authorized
     */
    @Override
    public boolean authorizeRequest(RegisteredServiceAccessStrategyRequest request) {
        return !isSurrogateAuthenticationSession(request) || doPrincipalAttributesAllowSurrogateServiceAccess(request);
    }

    /**
     * Evaluate principal attributes against required surrogate attributes.
     *
     * @param request the service access request
     * @return true if attributes meet requirements
     */
    protected boolean doPrincipalAttributesAllowSurrogateServiceAccess(RegisteredServiceAccessStrategyRequest request) {
        return RegisteredServiceAccessStrategyEvaluator.builder()
            .caseInsensitive(this.caseInsensitive)
            .requireAllAttributes(this.requireAllAttributes)
            .requiredAttributes(this.surrogateRequiredAttributes)
            .rejectedAttributes(new LinkedHashMap<>(0))
            .build()
            .apply(request);
    }
}

Groovy Script-Based Access Strategy

Service access strategy that uses Groovy scripts for flexible, programmatic authorization logic.

@Slf4j
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class GroovySurrogateRegisteredServiceAccessStrategy extends BaseSurrogateRegisteredServiceAccessStrategy {
    
    /**
     * Path to Groovy script for authorization logic.
     * Supports Spring Expression Language for dynamic script resolution.
     */
    @ExpressionLanguageCapable
    private String groovyScript;

    /**
     * Execute Groovy script to determine authorization.
     *
     * @param request the service access request
     * @return true if access is authorized
     * @throws Throwable if script execution fails
     */
    @Override
    public boolean authorizeRequest(RegisteredServiceAccessStrategyRequest request) throws Throwable {
        if (isSurrogateAuthenticationSession(request)) {
            try {
                Object[] args = new Object[]{request.getPrincipalId(), request.getAttributes(), LOGGER};
                Resource resource = ResourceUtils.getResourceFrom(SpringExpressionLanguageValueResolver.getInstance().resolve(this.groovyScript));
                ExecutableCompiledScriptFactory scriptFactory = ExecutableCompiledScriptFactory.getExecutableCompiledScriptFactory();
                return scriptFactory.fromResource(resource).execute(args, Boolean.class);
            } catch (Exception e) {
                LoggingUtils.error(LOGGER, e);
            }
            return false;
        }
        return super.authorizeRequest(request);
    }
}

Usage Examples

Configuring Attribute-Based Access Control

import org.apereo.cas.services.SurrogateRegisteredServiceAccessStrategy;

import java.util.*;

// Create attribute-based access strategy
SurrogateRegisteredServiceAccessStrategy strategy = new SurrogateRegisteredServiceAccessStrategy();

// Configure to require all attributes and use case-insensitive matching
strategy.setRequireAllAttributes(true);
strategy.setCaseInsensitive(true);

// Set required attributes for surrogate access
Map<String, Set<String>> requiredAttributes = new HashMap<>();
requiredAttributes.put("role", Set.of("admin", "support"));
requiredAttributes.put("department", Set.of("IT", "Security"));
strategy.setSurrogateRequiredAttributes(requiredAttributes);

// Use in service registry
RegisteredService service = // ... create service
service.setAccessStrategy(strategy);

Groovy Script Authorization

import org.apereo.cas.services.GroovySurrogateRegisteredServiceAccessStrategy;

// Create script-based access strategy
GroovySurrogateRegisteredServiceAccessStrategy strategy = new GroovySurrogateRegisteredServiceAccessStrategy();

// Set Groovy script path (supports classpath:, file:, http: URLs)
strategy.setGroovyScript("classpath:surrogate-authorization.groovy");

// Use in service registry
RegisteredService service = // ... create service  
service.setAccessStrategy(strategy);

Example Groovy script (surrogate-authorization.groovy):

// Script receives: principalId, attributes, logger
def principalId = args[0]
def attributes = args[1] 
def logger = args[2]

logger.debug("Evaluating surrogate access for principal: {}", principalId)

// Check if user has admin role
def roles = attributes.get("roles")
if (roles != null && roles.contains("admin")) {
    logger.info("Granting surrogate access to admin user: {}", principalId)
    return true
}

// Check business hours for support staff
def supportRoles = attributes.get("roles")
if (supportRoles != null && supportRoles.contains("support")) {
    def hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
    def isBusinessHours = hour >= 9 && hour <= 17
    
    if (isBusinessHours) {
        logger.info("Granting surrogate access to support user during business hours: {}", principalId)
        return true
    }
}

logger.warn("Denying surrogate access for principal: {}", principalId)
return false

Custom Access Strategy Implementation

import org.apereo.cas.services.BaseSurrogateRegisteredServiceAccessStrategy;
import org.apereo.cas.services.RegisteredServiceAccessStrategyRequest;

public class TimeBoundSurrogateAccessStrategy extends BaseSurrogateRegisteredServiceAccessStrategy {
    
    private int startHour = 9;
    private int endHour = 17;
    
    @Override
    public boolean authorizeRequest(RegisteredServiceAccessStrategyRequest request) {
        if (!isSurrogateAuthenticationSession(request)) {
            return true; // Non-surrogate sessions are always allowed
        }
        
        // Check time bounds for surrogate sessions
        Calendar now = Calendar.getInstance();
        int currentHour = now.get(Calendar.HOUR_OF_DAY);
        
        boolean withinBusinessHours = currentHour >= startHour && currentHour <= endHour;
        
        if (!withinBusinessHours) {
            LOGGER.warn("Surrogate authentication denied outside business hours for principal: {}", 
                request.getPrincipalId());
        }
        
        return withinBusinessHours;
    }
    
    // Getters and setters
    public int getStartHour() { return startHour; }
    public void setStartHour(int startHour) { this.startHour = startHour; }
    public int getEndHour() { return endHour; }
    public void setEndHour(int endHour) { this.endHour = endHour; }
}

JSON Configuration

Service access strategies can be configured via JSON in the CAS service registry:

{
  "@class": "org.apereo.cas.services.CasRegisteredService",
  "serviceId": "^https://example\\.com/.*",
  "name": "Example Service",
  "id": 1,
  "accessStrategy": {
    "@class": "org.apereo.cas.services.SurrogateRegisteredServiceAccessStrategy",
    "requireAllAttributes": true,
    "caseInsensitive": false,
    "surrogateRequiredAttributes": {
      "@class": "java.util.HashMap",
      "role": ["admin", "support"],
      "department": ["IT"]
    }
  }
}

Required Dependencies

These classes depend on types from:

import org.apereo.cas.services.BaseRegisteredServiceAccessStrategy;
import org.apereo.cas.services.RegisteredServiceAccessStrategyRequest;
import org.apereo.cas.services.util.RegisteredServiceAccessStrategyEvaluator;
import org.apereo.cas.authentication.surrogate.SurrogateAuthenticationService;
import org.apereo.cas.configuration.support.ExpressionLanguageCapable;
import org.apereo.cas.util.LoggingUtils;
import org.apereo.cas.util.ResourceUtils;
import org.apereo.cas.util.scripting.ExecutableCompiledScriptFactory;
import org.apereo.cas.util.spring.SpringExpressionLanguageValueResolver;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import org.springframework.core.io.Resource;

import java.io.Serial;
import java.util.*;

Install with Tessl CLI

npx tessl i tessl/maven-org-apereo-cas--cas-server-support-surrogate-api

docs

authentication-service.md

index.md

request-credential-handling.md

service-access-control.md

tile.json