Apereo CAS Core Multitenancy library providing tenant management capabilities for Central Authentication Service
—
System for extracting tenant context from HTTP requests using configurable URL patterns and request processing. This enables automatic tenant identification based on request characteristics, particularly URL structure.
Core interface for extracting tenant information from various request contexts.
/**
* Interface for extracting tenant information from requests
*/
public interface TenantExtractor {
String BEAN_NAME = "tenantExtractor";
Pattern PATTERN_TENANTS = Pattern.compile("tenants/(.+)/(.+)", Pattern.CASE_INSENSITIVE);
/**
* Get the associated tenants manager
* @return TenantsManager instance used for tenant lookups
*/
TenantsManager getTenantsManager();
/**
* Extract tenant definition from HTTP servlet request
* Uses the request's flow ID to determine tenant context
* @param request HttpServletRequest to extract tenant from
* @return Optional containing tenant definition if found
*/
default Optional<TenantDefinition> extract(HttpServletRequest request);
/**
* Extract tenant definition from Spring WebFlow request context
* @param requestContext Spring WebFlow RequestContext
* @return Optional containing tenant definition if found
*/
default Optional<TenantDefinition> extract(RequestContext requestContext);
/**
* Extract tenant definition from request path string
* @param requestPath the request path to analyze
* @return Optional containing tenant definition if found
*/
Optional<TenantDefinition> extract(String requestPath);
/**
* Static utility method to extract tenant ID from path string
* Uses PATTERN_TENANTS regex to find tenant ID in URL structure
* @param requestPath the request path to analyze
* @return tenant ID string if found, null otherwise
*/
static String tenantIdFromPath(String requestPath);
}Default implementation of TenantExtractor that uses CAS configuration properties to control extraction behavior.
/**
* Default implementation of TenantExtractor
* Uses CAS configuration properties to determine extraction behavior
*/
public class DefaultTenantExtractor implements TenantExtractor {
/**
* Constructor requiring tenants manager and CAS configuration
* @param tenantsManager TenantsManager for tenant lookups
* @param casProperties CAS configuration properties controlling extraction behavior
*/
public DefaultTenantExtractor(TenantsManager tenantsManager, CasConfigurationProperties casProperties);
/**
* Get the tenants manager (inherited from TenantExtractor)
* @return TenantsManager instance
*/
@Override
public TenantsManager getTenantsManager();
/**
* Extract tenant from request path (inherited from TenantExtractor)
* Checks if multitenancy is enabled before attempting extraction
* @param requestPath the request path to analyze
* @return Optional containing tenant definition if found and enabled
*/
@Override
public Optional<TenantDefinition> extract(String requestPath);
}Usage Examples:
import org.apereo.cas.multitenancy.*;
import org.apereo.cas.configuration.CasConfigurationProperties;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.webflow.execution.RequestContext;
// Create tenant extractor
TenantsManager tenantsManager = new DefaultTenantsManager(resource);
CasConfigurationProperties casProperties = new CasConfigurationProperties();
TenantExtractor extractor = new DefaultTenantExtractor(tenantsManager, casProperties);
// Extract from request path
Optional<TenantDefinition> tenant1 = extractor.extract("/tenants/org1/login");
Optional<TenantDefinition> tenant2 = extractor.extract("/tenants/company2/validate");
if (tenant1.isPresent()) {
System.out.println("Found tenant: " + tenant1.get().getId());
}
// Extract from HTTP request
HttpServletRequest httpRequest = ...; // from servlet context
Optional<TenantDefinition> tenantFromHttp = extractor.extract(httpRequest);
// Extract from WebFlow context
RequestContext webflowContext = ...; // from Spring WebFlow
Optional<TenantDefinition> tenantFromFlow = extractor.extract(webflowContext);
// Use static utility method
String tenantId = TenantExtractor.tenantIdFromPath("/tenants/myorg/authenticate");
// Returns: "myorg"The tenant extraction system uses a predefined regex pattern to identify tenant information in URLs:
Pattern PATTERN_TENANTS = Pattern.compile("tenants/(.+)/(.+)", Pattern.CASE_INSENSITIVE);The pattern tenants/(.+)/(.+) matches URLs with the structure:
/tenants/{tenantId}/{operation}Example URL Matches:
// These URLs will match and extract tenant IDs:
"/tenants/organization1/login" // → "organization1"
"/tenants/company-a/validate" // → "company-a"
"/tenants/TENANT123/authenticate" // → "TENANT123"
"/app/tenants/myorg/logout" // → "myorg"
// These URLs will NOT match:
"/login" // No tenant structure
"/tenant/org1/login" // Missing 's' in 'tenants'
"/tenants/org1" // Missing operation part
"/tenants/" // Missing both parts/**
* Extract tenant ID from path using static method
*/
String tenantId = TenantExtractor.tenantIdFromPath("/tenants/acme-corp/validate");
// Returns: "acme-corp"
if (tenantId != null) {
// Use tenant ID for further processing
System.out.println("Extracted tenant: " + tenantId);
}The DefaultTenantExtractor respects CAS configuration properties to control extraction behavior:
// Extraction behavior is controlled by configuration property:
// cas.multitenancy.core.enabled = true/false
// When disabled, extract() always returns Optional.empty()
// When enabled, normal pattern matching is performed# CAS Configuration (application.yml)
cas:
multitenancy:
core:
enabled: true
json:
location: "classpath:tenants.json"The tenant extraction follows this processing flow:
Flow Diagram:
HTTP Request → Flow ID Extraction → Pattern Matching → Tenant ID → Manager Lookup → Tenant Definition// Extract from HttpServletRequest
public Optional<TenantDefinition> extractFromServlet(HttpServletRequest request) {
return extractor.extract(request);
}// Extract from Spring WebFlow RequestContext
public Optional<TenantDefinition> extractFromWebFlow(RequestContext context) {
return extractor.extract(context);
}// Direct path-based extraction for custom scenarios
public Optional<TenantDefinition> extractFromCustomPath(String customPath) {
return extractor.extract(customPath);
}Install with Tessl CLI
npx tessl i tessl/maven-org-apereo-cas--cas-server-core-multitenancy