CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apereo-cas--cas-server-core-multitenancy

Apereo CAS Core Multitenancy library providing tenant management capabilities for Central Authentication Service

Pending
Overview
Eval results
Files

tenant-extraction.mddocs/

Tenant Extraction

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.

Capabilities

TenantExtractor Interface

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

DefaultTenantExtractor Implementation

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"

URL Pattern Matching

The tenant extraction system uses a predefined regex pattern to identify tenant information in URLs:

Pattern Definition

Pattern PATTERN_TENANTS = Pattern.compile("tenants/(.+)/(.+)", Pattern.CASE_INSENSITIVE);

Pattern Matching Behavior

The pattern tenants/(.+)/(.+) matches URLs with the structure:

  • /tenants/{tenantId}/{operation}
  • Case-insensitive matching
  • First capture group contains the tenant ID
  • Second capture group contains the operation/endpoint

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

Static Extraction Method

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

Configuration Control

The DefaultTenantExtractor respects CAS configuration properties to control extraction behavior:

Multitenancy Enable/Disable

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

Configuration Example

# CAS Configuration (application.yml)
cas:
  multitenancy:
    core:
      enabled: true
    json:
      location: "classpath:tenants.json"

Request Processing Flow

The tenant extraction follows this processing flow:

  1. Configuration Check: Verify if multitenancy is enabled
  2. Path Analysis: Extract flow ID or use provided path string
  3. Pattern Matching: Apply PATTERN_TENANTS regex to identify tenant ID
  4. Tenant Lookup: Use TenantsManager to find tenant definition
  5. Result Return: Return Optional with tenant or empty if not found

Flow Diagram:

HTTP Request → Flow ID Extraction → Pattern Matching → Tenant ID → Manager Lookup → Tenant Definition

Integration Points

Servlet Integration

// Extract from HttpServletRequest
public Optional<TenantDefinition> extractFromServlet(HttpServletRequest request) {
    return extractor.extract(request);
}

Spring WebFlow Integration

// Extract from Spring WebFlow RequestContext
public Optional<TenantDefinition> extractFromWebFlow(RequestContext context) {
    return extractor.extract(context);
}

Custom Path Processing

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

docs

index.md

spring-integration.md

tenant-extraction.md

tenant-management.md

tenant-policies.md

tile.json