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

spring-integration.mddocs/

Spring Integration

Auto-configuration classes and beans for seamless Spring Boot integration with proper conditional configuration. The multitenancy module provides complete Spring Boot auto-configuration support with feature toggles and security endpoint configuration.

Capabilities

CasCoreMultitenancyAutoConfiguration Class

Main auto-configuration class that sets up all multitenancy beans with proper Spring Boot integration patterns.

/**
 * Spring Boot auto-configuration for CAS multitenancy functionality
 * Conditionally enabled based on feature configuration
 */
@EnableConfigurationProperties(CasConfigurationProperties.class)
@ConditionalOnFeatureEnabled(feature = CasFeatureModule.FeatureCatalog.Multitenancy)
@AutoConfiguration
public class CasCoreMultitenancyAutoConfiguration {
    
    /**
     * Create TenantsManager bean with JSON-based configuration
     * Conditionally created only if no existing bean with the same name exists
     * @param casProperties CAS configuration properties containing multitenancy settings
     * @return DefaultTenantsManager instance configured with JSON location
     * @throws Exception if resource location cannot be resolved
     */
    @Bean
    @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
    @ConditionalOnMissingBean(name = TenantsManager.BEAN_NAME)
    public TenantsManager tenantsManager(CasConfigurationProperties casProperties) throws Exception;
    
    /**
     * Create TenantExtractor bean for request-based tenant extraction
     * Conditionally created only if no existing bean with the same name exists
     * @param casProperties CAS configuration properties
     * @param tenantsManager TenantsManager bean for tenant lookups
     * @return DefaultTenantExtractor instance
     */
    @Bean
    @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
    @ConditionalOnMissingBean(name = TenantExtractor.BEAN_NAME)
    public TenantExtractor tenantExtractor(
        CasConfigurationProperties casProperties,
        @Qualifier(TenantsManager.BEAN_NAME) TenantsManager tenantsManager);
    
    /**
     * Create web security configurer for multitenancy endpoints
     * Configures security rules for tenant-related HTTP endpoints
     * @return CasWebSecurityConfigurer for HTTP security configuration
     */
    @Bean
    @ConditionalOnMissingBean(name = "casMultitenancyEndpointConfigurer")
    @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
    public CasWebSecurityConfigurer<HttpSecurity> casMultitenancyEndpointConfigurer();
}

Usage in Spring Boot Application:

// Auto-configuration is automatically applied when module is on classpath
// No manual configuration needed - beans are created automatically

@SpringBootApplication
public class CasApplication {
    public static void main(String[] args) {
        SpringApplication.run(CasApplication.class, args);
        // TenantsManager and TenantExtractor beans are automatically available
    }
}

// Inject beans in your components
@Component
public class MultitenancyService {
    
    @Autowired
    private TenantsManager tenantsManager;
    
    @Autowired
    private TenantExtractor tenantExtractor;
    
    public void processTenantRequest(HttpServletRequest request) {
        Optional<TenantDefinition> tenant = tenantExtractor.extract(request);
        if (tenant.isPresent()) {
            // Process with tenant context
            System.out.println("Processing for tenant: " + tenant.get().getId());
        }
    }
}

Configuration Properties

Multitenancy Configuration Structure

The auto-configuration uses CAS configuration properties to control multitenancy behavior:

# application.yml configuration example
cas:
  multitenancy:
    core:
      enabled: true                           # Enable/disable multitenancy
    json:
      location: "classpath:tenants.json"      # Location of tenant definitions file

Property Access Pattern

// Configuration properties are accessed within auto-configuration
CasConfigurationProperties casProperties = ...;

// Get JSON location for tenant definitions
Resource location = casProperties.getMultitenancy().getJson().getLocation();

// Check if multitenancy core is enabled
boolean enabled = casProperties.getMultitenancy().getCore().isEnabled();

Bean Lifecycle Management

Refresh Scope

All multitenancy beans are configured with @RefreshScope to support dynamic configuration updates:

@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public TenantsManager tenantsManager(CasConfigurationProperties casProperties) {
    // Bean will be recreated when configuration changes
    Resource location = casProperties.getMultitenancy().getJson().getLocation();
    return new DefaultTenantsManager(location);
}

Refresh Scope Benefits:

  • Dynamic Updates: Beans are recreated when configuration properties change
  • Zero Downtime: Configuration updates don't require application restart
  • Proxy Mode: Default proxy mode ensures proper bean lifecycle management

Conditional Bean Creation

Beans are created conditionally to allow for custom implementations:

@ConditionalOnMissingBean(name = TenantsManager.BEAN_NAME)
public TenantsManager tenantsManager(CasConfigurationProperties casProperties) {
    // Only created if no existing bean with name "tenantsManager"
}

Custom Bean Override Example:

@Configuration
public class CustomMultitenancyConfiguration {
    
    // Override default TenantsManager with custom implementation
    @Bean(name = TenantsManager.BEAN_NAME)
    @Primary
    public TenantsManager customTenantsManager() {
        return new CustomTenantsManager();
    }
}

Security Configuration

Web Security Configurer

The auto-configuration includes a security configurer for multitenancy endpoints:

/**
 * Web security configurer for multitenancy endpoints
 * Configures access rules for tenant-related HTTP endpoints
 */
@Bean
@ConditionalOnMissingBean(name = "casMultitenancyEndpointConfigurer")
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public CasWebSecurityConfigurer<HttpSecurity> casMultitenancyEndpointConfigurer() {
    return new CasWebSecurityConfigurer<>() {
        @Override
        @CanIgnoreReturnValue
        public CasWebSecurityConfigurer<HttpSecurity> configure(HttpSecurity http) throws Exception {
            http.authorizeHttpRequests(customizer -> {
                AntPathRequestMatcher authEndpoints = new AntPathRequestMatcher("/tenants/**");
                customizer.requestMatchers(authEndpoints).permitAll();
            });
            return this;
        }
    };
}

Security Configuration Effects:

  • Endpoint Access: /tenants/** endpoints are configured to permit all access
  • Path Matching: Uses Ant-style path matching for flexible endpoint patterns
  • Integration: Seamlessly integrates with existing CAS security configuration

Feature Toggle Integration

Conditional Activation

The entire auto-configuration is conditionally enabled based on CAS feature configuration:

@ConditionalOnFeatureEnabled(feature = CasFeatureModule.FeatureCatalog.Multitenancy)

Feature Control:

# Enable multitenancy feature
cas:
  features:
    multitenancy:
      enabled: true

Feature Module Catalog

The multitenancy feature is part of the CAS feature catalog system:

// Feature reference
CasFeatureModule.FeatureCatalog.Multitenancy

Dependency Injection Patterns

Bean Qualification

Beans use proper qualification to avoid naming conflicts:

@Qualifier(TenantsManager.BEAN_NAME)
TenantsManager tenantsManager

Constructor Injection Example

@Component
public class TenantAwareService {
    
    private final TenantsManager tenantsManager;
    private final TenantExtractor tenantExtractor;
    
    // Constructor injection - recommended approach
    public TenantAwareService(TenantsManager tenantsManager, TenantExtractor tenantExtractor) {
        this.tenantsManager = tenantsManager;  
        this.tenantExtractor = tenantExtractor;
    }
    
    public void handleTenantOperation(String tenantId) {
        Optional<TenantDefinition> tenant = tenantsManager.findTenant(tenantId);
        // Process tenant operation
    }
}

Field Injection Example

@Service
public class MultitenancyController {
    
    @Autowired
    @Qualifier(TenantsManager.BEAN_NAME)
    private TenantsManager tenantsManager;
    
    @Autowired
    @Qualifier(TenantExtractor.BEAN_NAME)  
    private TenantExtractor tenantExtractor;
    
    @GetMapping("/admin/tenants")
    public List<TenantDefinition> getAllTenants() {
        return tenantsManager.findTenants();
    }
}

Configuration Profiles

Environment-Specific Configuration

# Development profile
---
spring:
  config:
    activate:
      on-profile: development
cas:
  multitenancy:
    json:
      location: "file:/dev/cas/tenants-dev.json"

# Production profile  
---
spring:
  config:
    activate:
      on-profile: production
cas:
  multitenancy:
    json:
      location: "file:/etc/cas/tenants-prod.json"

Testing Configuration

@TestConfiguration
public class MultitenancyTestConfiguration {
    
    @Bean
    @Primary
    public TenantsManager testTenantsManager() {
        // Test-specific implementation
        return new TestTenantsManager();
    }
}

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