0
# Tenant Extraction
1
2
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.
3
4
## Capabilities
5
6
### TenantExtractor Interface
7
8
Core interface for extracting tenant information from various request contexts.
9
10
```java { .api }
11
/**
12
* Interface for extracting tenant information from requests
13
*/
14
public interface TenantExtractor {
15
String BEAN_NAME = "tenantExtractor";
16
Pattern PATTERN_TENANTS = Pattern.compile("tenants/(.+)/(.+)", Pattern.CASE_INSENSITIVE);
17
18
/**
19
* Get the associated tenants manager
20
* @return TenantsManager instance used for tenant lookups
21
*/
22
TenantsManager getTenantsManager();
23
24
/**
25
* Extract tenant definition from HTTP servlet request
26
* Uses the request's flow ID to determine tenant context
27
* @param request HttpServletRequest to extract tenant from
28
* @return Optional containing tenant definition if found
29
*/
30
default Optional<TenantDefinition> extract(HttpServletRequest request);
31
32
/**
33
* Extract tenant definition from Spring WebFlow request context
34
* @param requestContext Spring WebFlow RequestContext
35
* @return Optional containing tenant definition if found
36
*/
37
default Optional<TenantDefinition> extract(RequestContext requestContext);
38
39
/**
40
* Extract tenant definition from request path string
41
* @param requestPath the request path to analyze
42
* @return Optional containing tenant definition if found
43
*/
44
Optional<TenantDefinition> extract(String requestPath);
45
46
/**
47
* Static utility method to extract tenant ID from path string
48
* Uses PATTERN_TENANTS regex to find tenant ID in URL structure
49
* @param requestPath the request path to analyze
50
* @return tenant ID string if found, null otherwise
51
*/
52
static String tenantIdFromPath(String requestPath);
53
}
54
```
55
56
### DefaultTenantExtractor Implementation
57
58
Default implementation of TenantExtractor that uses CAS configuration properties to control extraction behavior.
59
60
```java { .api }
61
/**
62
* Default implementation of TenantExtractor
63
* Uses CAS configuration properties to determine extraction behavior
64
*/
65
public class DefaultTenantExtractor implements TenantExtractor {
66
67
/**
68
* Constructor requiring tenants manager and CAS configuration
69
* @param tenantsManager TenantsManager for tenant lookups
70
* @param casProperties CAS configuration properties controlling extraction behavior
71
*/
72
public DefaultTenantExtractor(TenantsManager tenantsManager, CasConfigurationProperties casProperties);
73
74
/**
75
* Get the tenants manager (inherited from TenantExtractor)
76
* @return TenantsManager instance
77
*/
78
@Override
79
public TenantsManager getTenantsManager();
80
81
/**
82
* Extract tenant from request path (inherited from TenantExtractor)
83
* Checks if multitenancy is enabled before attempting extraction
84
* @param requestPath the request path to analyze
85
* @return Optional containing tenant definition if found and enabled
86
*/
87
@Override
88
public Optional<TenantDefinition> extract(String requestPath);
89
}
90
```
91
92
**Usage Examples:**
93
94
```java
95
import org.apereo.cas.multitenancy.*;
96
import org.apereo.cas.configuration.CasConfigurationProperties;
97
import jakarta.servlet.http.HttpServletRequest;
98
import org.springframework.webflow.execution.RequestContext;
99
100
// Create tenant extractor
101
TenantsManager tenantsManager = new DefaultTenantsManager(resource);
102
CasConfigurationProperties casProperties = new CasConfigurationProperties();
103
TenantExtractor extractor = new DefaultTenantExtractor(tenantsManager, casProperties);
104
105
// Extract from request path
106
Optional<TenantDefinition> tenant1 = extractor.extract("/tenants/org1/login");
107
Optional<TenantDefinition> tenant2 = extractor.extract("/tenants/company2/validate");
108
109
if (tenant1.isPresent()) {
110
System.out.println("Found tenant: " + tenant1.get().getId());
111
}
112
113
// Extract from HTTP request
114
HttpServletRequest httpRequest = ...; // from servlet context
115
Optional<TenantDefinition> tenantFromHttp = extractor.extract(httpRequest);
116
117
// Extract from WebFlow context
118
RequestContext webflowContext = ...; // from Spring WebFlow
119
Optional<TenantDefinition> tenantFromFlow = extractor.extract(webflowContext);
120
121
// Use static utility method
122
String tenantId = TenantExtractor.tenantIdFromPath("/tenants/myorg/authenticate");
123
// Returns: "myorg"
124
```
125
126
## URL Pattern Matching
127
128
The tenant extraction system uses a predefined regex pattern to identify tenant information in URLs:
129
130
### Pattern Definition
131
132
```java { .api }
133
Pattern PATTERN_TENANTS = Pattern.compile("tenants/(.+)/(.+)", Pattern.CASE_INSENSITIVE);
134
```
135
136
### Pattern Matching Behavior
137
138
The pattern `tenants/(.+)/(.+)` matches URLs with the structure:
139
- `/tenants/{tenantId}/{operation}`
140
- Case-insensitive matching
141
- First capture group contains the tenant ID
142
- Second capture group contains the operation/endpoint
143
144
**Example URL Matches:**
145
146
```java
147
// These URLs will match and extract tenant IDs:
148
"/tenants/organization1/login" // → "organization1"
149
"/tenants/company-a/validate" // → "company-a"
150
"/tenants/TENANT123/authenticate" // → "TENANT123"
151
"/app/tenants/myorg/logout" // → "myorg"
152
153
// These URLs will NOT match:
154
"/login" // No tenant structure
155
"/tenant/org1/login" // Missing 's' in 'tenants'
156
"/tenants/org1" // Missing operation part
157
"/tenants/" // Missing both parts
158
```
159
160
### Static Extraction Method
161
162
```java
163
/**
164
* Extract tenant ID from path using static method
165
*/
166
String tenantId = TenantExtractor.tenantIdFromPath("/tenants/acme-corp/validate");
167
// Returns: "acme-corp"
168
169
if (tenantId != null) {
170
// Use tenant ID for further processing
171
System.out.println("Extracted tenant: " + tenantId);
172
}
173
```
174
175
## Configuration Control
176
177
The DefaultTenantExtractor respects CAS configuration properties to control extraction behavior:
178
179
### Multitenancy Enable/Disable
180
181
```java
182
// Extraction behavior is controlled by configuration property:
183
// cas.multitenancy.core.enabled = true/false
184
185
// When disabled, extract() always returns Optional.empty()
186
// When enabled, normal pattern matching is performed
187
```
188
189
### Configuration Example
190
191
```yaml
192
# CAS Configuration (application.yml)
193
cas:
194
multitenancy:
195
core:
196
enabled: true
197
json:
198
location: "classpath:tenants.json"
199
```
200
201
## Request Processing Flow
202
203
The tenant extraction follows this processing flow:
204
205
1. **Configuration Check**: Verify if multitenancy is enabled
206
2. **Path Analysis**: Extract flow ID or use provided path string
207
3. **Pattern Matching**: Apply PATTERN_TENANTS regex to identify tenant ID
208
4. **Tenant Lookup**: Use TenantsManager to find tenant definition
209
5. **Result Return**: Return Optional with tenant or empty if not found
210
211
**Flow Diagram:**
212
213
```
214
HTTP Request → Flow ID Extraction → Pattern Matching → Tenant ID → Manager Lookup → Tenant Definition
215
```
216
217
## Integration Points
218
219
### Servlet Integration
220
221
```java
222
// Extract from HttpServletRequest
223
public Optional<TenantDefinition> extractFromServlet(HttpServletRequest request) {
224
return extractor.extract(request);
225
}
226
```
227
228
### Spring WebFlow Integration
229
230
```java
231
// Extract from Spring WebFlow RequestContext
232
public Optional<TenantDefinition> extractFromWebFlow(RequestContext context) {
233
return extractor.extract(context);
234
}
235
```
236
237
### Custom Path Processing
238
239
```java
240
// Direct path-based extraction for custom scenarios
241
public Optional<TenantDefinition> extractFromCustomPath(String customPath) {
242
return extractor.extract(customPath);
243
}