0
# Header-Based Theme Resolution
1
2
Simple theme resolution that extracts theme names from HTTP request headers.
3
4
## Capabilities
5
6
### RequestHeaderThemeResolver
7
8
Theme resolver that extracts theme from HTTP request headers using a configured header name.
9
10
```java { .api }
11
/**
12
* Theme resolver that extracts theme from HTTP request headers
13
*/
14
public class RequestHeaderThemeResolver extends AbstractThemeResolver {
15
16
/**
17
* Constructor with header name configuration
18
* @param themeHeaderName Name of HTTP header to check for theme value
19
*/
20
public RequestHeaderThemeResolver(String themeHeaderName);
21
22
/**
23
* Resolves theme from request header
24
* @param request HTTP request containing theme header
25
* @return Theme name from header, or default theme if header missing/empty
26
*/
27
@Nonnull
28
@Override
29
public String resolveThemeName(HttpServletRequest request);
30
31
/**
32
* No-op implementation for theme setting
33
* @param httpServletRequest HTTP request
34
* @param httpServletResponse HTTP response
35
* @param theme Theme name
36
*/
37
@Override
38
public void setThemeName(@Nonnull HttpServletRequest httpServletRequest,
39
HttpServletResponse httpServletResponse, String theme);
40
}
41
```
42
43
**Usage Examples:**
44
45
```java
46
import org.apereo.cas.services.web.RequestHeaderThemeResolver;
47
48
// Create header-based theme resolver
49
RequestHeaderThemeResolver headerResolver = new RequestHeaderThemeResolver("X-CAS-Theme");
50
headerResolver.setDefaultThemeName("default");
51
52
// Resolve theme from request
53
String themeName = headerResolver.resolveThemeName(request);
54
55
// Example HTTP request with theme header:
56
// GET /cas/login HTTP/1.1
57
// Host: cas.example.com
58
// X-CAS-Theme: dark
59
//
60
// Result: themeName = "dark"
61
```
62
63
## Header Configuration
64
65
### Standard Header Names
66
67
Common header names used for theme selection:
68
69
```java
70
// Common theme header patterns
71
new RequestHeaderThemeResolver("X-Theme"); // Generic
72
new RequestHeaderThemeResolver("X-CAS-Theme"); // CAS-specific
73
new RequestHeaderThemeResolver("X-UI-Theme"); // UI-specific
74
new RequestHeaderThemeResolver("Theme"); // Simple
75
new RequestHeaderThemeResolver("X-Client-Theme"); // Client-specific
76
```
77
78
### Custom Header Names
79
80
Any valid HTTP header name can be used:
81
82
```java
83
// Examples of custom header configurations
84
new RequestHeaderThemeResolver("X-Brand-Theme");
85
new RequestHeaderThemeResolver("X-Tenant-Theme");
86
new RequestHeaderThemeResolver("X-Mobile-Theme");
87
new RequestHeaderThemeResolver("Preferred-Theme");
88
```
89
90
## Integration Patterns
91
92
### API-Driven Theme Selection
93
94
Ideal for API clients that need to specify themes programmatically:
95
96
```http
97
POST /cas/v1/tickets HTTP/1.1
98
Host: cas.example.com
99
Content-Type: application/json
100
X-CAS-Theme: api-minimal
101
102
{
103
"username": "user@example.com",
104
"password": "secret"
105
}
106
```
107
108
### Mobile App Integration
109
110
Mobile applications can specify appropriate themes:
111
112
```http
113
GET /cas/login?service=https://mobile.example.com HTTP/1.1
114
Host: cas.example.com
115
User-Agent: MyMobileApp/1.0
116
X-CAS-Theme: mobile-dark
117
```
118
119
### Multi-Tenant Applications
120
121
Different tenants can specify their themes:
122
123
```http
124
GET /cas/login?service=https://tenant1.example.com HTTP/1.1
125
Host: cas.example.com
126
X-Tenant-Theme: tenant1-corporate
127
```
128
129
### Load Balancer Integration
130
131
Load balancers can add theme headers based on routing rules:
132
133
```nginx
134
# Nginx configuration example
135
location /cas/login {
136
proxy_pass http://cas-backend;
137
138
# Add theme header based on host
139
if ($host = "admin.example.com") {
140
proxy_set_header X-CAS-Theme "admin";
141
}
142
if ($host = "mobile.example.com") {
143
proxy_set_header X-CAS-Theme "mobile";
144
}
145
}
146
```
147
148
## Theme Resolution Behavior
149
150
### Header Processing
151
152
- **Case Sensitive**: Header names are case-sensitive
153
- **First Value**: Uses first header value if multiple headers present
154
- **Trim Whitespace**: Theme values are trimmed of leading/trailing whitespace
155
- **Empty Headers**: Empty or whitespace-only headers treated as missing
156
157
### Default Theme Fallback
158
159
Returns default theme when:
160
- Header is not present in request
161
- Header value is empty or whitespace-only
162
- Header value is null
163
164
```java
165
// Example resolution logic
166
String headerValue = request.getHeader(themeHeaderName);
167
if (StringUtils.isBlank(headerValue)) {
168
return getDefaultThemeName(); // "default"
169
}
170
return headerValue.trim();
171
```
172
173
## Security Considerations
174
175
### Header Validation
176
177
The resolver performs minimal validation:
178
- No theme name validation against available themes
179
- No sanitization of header values
180
- No protection against header injection
181
182
### Recommended Practices
183
184
1. **Theme Validation**: Validate themes exist at theme source level
185
2. **Input Sanitization**: Sanitize theme names before use
186
3. **Allowlist Themes**: Maintain allowlist of valid theme names
187
4. **Header Security**: Use secure header naming conventions
188
189
```java
190
// Example theme validation wrapper
191
public class ValidatingHeaderThemeResolver extends RequestHeaderThemeResolver {
192
private final Set<String> validThemes;
193
194
@Override
195
public String resolveThemeName(HttpServletRequest request) {
196
String theme = super.resolveThemeName(request);
197
if (validThemes.contains(theme)) {
198
return theme;
199
}
200
return getDefaultThemeName();
201
}
202
}
203
```
204
205
## Request Context Integration
206
207
### Request Attribute Storage
208
209
When used in ChainingThemeResolver, resolved themes are stored as request attributes:
210
211
```java
212
// Theme stored as request attribute for later use
213
String attributeName = casProperties.getTheme().getParamName(); // Default: "theme"
214
request.setAttribute(attributeName, resolvedTheme);
215
```
216
217
### Spring Web MVC Integration
218
219
Works seamlessly with Spring Web MVC theme resolution:
220
221
```java
222
// Spring controller can access resolved theme
223
@Controller
224
public class LoginController {
225
226
@RequestMapping("/login")
227
public String login(HttpServletRequest request, Model model) {
228
String theme = (String) request.getAttribute("theme");
229
model.addAttribute("currentTheme", theme);
230
return "login";
231
}
232
}
233
```
234
235
## Performance Characteristics
236
237
- **Very Fast**: Simple header lookup with minimal processing
238
- **No I/O**: No file system or network access required
239
- **Stateless**: No session or persistence overhead
240
- **Cache Friendly**: Results can be cached per request if needed
241
242
## Common Use Cases
243
244
1. **API Authentication**: REST clients specifying themes
245
2. **Mobile Applications**: Native apps requesting mobile-optimized themes
246
3. **Multi-Brand Platforms**: Different brands specifying their themes
247
4. **A/B Testing**: Experimental themes via header injection
248
5. **Load Balancer Routing**: Infrastructure-level theme assignment
249
6. **Development/Testing**: Easy theme switching during development