0
# Service-Based Theme Resolution
1
2
Advanced theme resolution based on registered service configurations, supporting Groovy scripts and HTTP URLs for dynamic theme selection.
3
4
## Capabilities
5
6
### RegisteredServiceThemeResolver
7
8
Theme resolver that determines theme based on registered service configuration with support for dynamic theme determination.
9
10
```java { .api }
11
/**
12
* Theme resolver that determines theme based on registered service configuration
13
* Supports static themes, Groovy scripts, and HTTP URLs for dynamic theme selection
14
*/
15
public class RegisteredServiceThemeResolver extends AbstractThemeResolver {
16
17
/**
18
* Constructor with required dependencies
19
* @param servicesManager CAS services manager for service lookup
20
* @param authenticationRequestServiceSelectionStrategies Service selection strategies
21
* @param casProperties CAS configuration properties
22
*/
23
public RegisteredServiceThemeResolver(
24
ObjectProvider<ServicesManager> servicesManager,
25
ObjectProvider<AuthenticationServiceSelectionPlan> authenticationRequestServiceSelectionStrategies,
26
ObjectProvider<CasConfigurationProperties> casProperties);
27
28
/**
29
* Resolves theme based on service configuration
30
* @param request HTTP request containing service parameter
31
* @return Theme name from service configuration, or default theme
32
*/
33
@Override
34
public String resolveThemeName(@Nonnull HttpServletRequest request);
35
36
/**
37
* No-op implementation for theme setting
38
* @param request HTTP request
39
* @param response HTTP response
40
* @param themeName Theme name
41
*/
42
@Override
43
public void setThemeName(@Nonnull HttpServletRequest request,
44
HttpServletResponse response, String themeName);
45
46
/**
47
* Determines theme name from service configuration
48
* @param request HTTP request
49
* @param service Resolved service
50
* @param registeredService Registered service configuration
51
* @return Theme name or default theme
52
*/
53
protected String determineThemeNameToChoose(HttpServletRequest request,
54
Service service,
55
WebBasedRegisteredService registeredService);
56
57
/**
58
* Executes Groovy script to determine theme name
59
* @param request HTTP request
60
* @param service Service requesting authentication
61
* @param registeredService Registered service configuration
62
* @param resource Groovy script resource
63
* @return Theme name from script execution
64
*/
65
protected String determineThemeFromGroovyResource(HttpServletRequest request,
66
Service service,
67
WebBasedRegisteredService registeredService,
68
AbstractResource resource);
69
70
/**
71
* Stores theme name as request attribute for later use
72
* @param request HTTP request
73
* @param themeName Theme name to remember
74
* @return The theme name that was stored
75
*/
76
protected String rememberThemeName(HttpServletRequest request, String themeName);
77
78
/**
79
* Stores default theme name as request attribute
80
* @param request HTTP request
81
* @return The default theme name that was stored
82
*/
83
protected String rememberThemeName(HttpServletRequest request);
84
85
/**
86
* Resolves theme for service using Spring expression evaluation
87
* @param registeredService Service configuration containing theme property
88
* @param request HTTP request for context
89
* @return Resolved theme name or null if not found
90
*/
91
protected String resolveThemeForService(WebBasedRegisteredService registeredService,
92
HttpServletRequest request);
93
}
94
```
95
96
**Usage Examples:**
97
98
```java
99
import org.apereo.cas.services.web.RegisteredServiceThemeResolver;
100
import org.apereo.cas.services.ServicesManager;
101
102
// Create service theme resolver
103
RegisteredServiceThemeResolver resolver = new RegisteredServiceThemeResolver(
104
servicesManagerProvider,
105
serviceSelectionPlanProvider,
106
casPropertiesProvider);
107
resolver.setDefaultThemeName("default");
108
109
// Service configuration determines theme
110
String theme = resolver.resolveThemeName(request);
111
```
112
113
## Theme Configuration Methods
114
115
### Static Theme Names
116
117
Simple static theme name in service configuration:
118
119
```json
120
{
121
"serviceId": "https://myapp.example.com/**",
122
"name": "My Application",
123
"theme": "corporate"
124
}
125
```
126
127
### Spring Expression Language
128
129
Dynamic theme using Spring EL expressions:
130
131
```json
132
{
133
"serviceId": "https://myapp.example.com/**",
134
"name": "My Application",
135
"theme": "#{request.getHeader('X-Client-Type') == 'mobile' ? 'mobile' : 'desktop'}"
136
}
137
```
138
139
### Groovy Scripts
140
141
Groovy script for complex theme logic:
142
143
```json
144
{
145
"serviceId": "https://myapp.example.com/**",
146
"name": "My Application",
147
"theme": "file:/etc/cas/themes/theme-selector.groovy"
148
}
149
```
150
151
**Example Groovy script:**
152
153
```groovy
154
// theme-selector.groovy
155
def userAgent = request.getHeader("User-Agent")
156
def clientId = request.getParameter("client_id")
157
158
if (userAgent?.contains("Mobile")) {
159
return "mobile"
160
} else if (clientId == "admin-portal") {
161
return "admin"
162
} else {
163
return "default"
164
}
165
```
166
167
### HTTP URL Endpoints
168
169
HTTP endpoint that returns theme name:
170
171
```json
172
{
173
"serviceId": "https://myapp.example.com/**",
174
"name": "My Application",
175
"theme": "https://config.example.com/theme?service=${service.id}"
176
}
177
```
178
179
**Example HTTP response:**
180
```
181
corporate-theme
182
```
183
184
## Resolution Process
185
186
1. **Service Extraction**: Extracts service from request context using WebUtils
187
2. **Service Resolution**: Uses AuthenticationServiceSelectionPlan to resolve service
188
3. **Service Lookup**: Finds registered service using ServicesManager
189
4. **Access Check**: Verifies service access is allowed
190
5. **Theme Determination**: Evaluates theme configuration based on type:
191
- **File Resource**: Executes as Groovy script
192
- **URL Resource**: Makes HTTP GET request
193
- **String Value**: Evaluates as Spring expression
194
6. **Theme Validation**: Validates theme exists in template prefixes or resource bundles
195
7. **Result Storage**: Stores resolved theme in request attributes
196
197
## Groovy Script Context
198
199
Groovy scripts receive the following variables:
200
201
```groovy { .api }
202
// Available variables in Groovy theme scripts
203
service // org.apereo.cas.authentication.principal.Service
204
registeredService // org.apereo.cas.services.WebBasedRegisteredService
205
queryString // String - HTTP query string
206
headers // Map<String, String> - HTTP headers
207
logger // org.slf4j.Logger - For logging
208
```
209
210
**Example advanced Groovy script:**
211
212
```groovy
213
import java.time.LocalTime
214
215
def now = LocalTime.now()
216
def userAgent = headers.get("User-Agent")
217
218
// Business hours theme (9 AM - 5 PM)
219
if (now.isAfter(LocalTime.of(9, 0)) && now.isBefore(LocalTime.of(17, 0))) {
220
logger.info("Using business hours theme for service: {}", service.id)
221
return "business"
222
}
223
224
// Mobile detection
225
if (userAgent?.toLowerCase()?.contains("mobile")) {
226
logger.info("Using mobile theme for service: {}", service.id)
227
return "mobile"
228
}
229
230
// Default theme
231
logger.info("Using default theme for service: {}", service.id)
232
return "default"
233
```
234
235
## HTTP URL Theme Resolution
236
237
For HTTP URL theme endpoints:
238
239
- **Method**: GET request
240
- **Parameters**: `service` parameter with service ID
241
- **Response**: Plain text theme name
242
- **Timeout**: Configurable HTTP timeout
243
- **Error Handling**: Falls back to default theme on HTTP errors
244
245
```java
246
// Example HTTP request made by resolver:
247
GET https://config.example.com/theme?service=https://myapp.example.com/login
248
Accept: text/plain
249
250
// Expected response:
251
corporate-dark
252
```
253
254
## Theme Validation
255
256
The resolver validates themes exist before returning them:
257
258
1. **Template Prefix Search**: Checks if `{theme}.properties` exists in template prefixes
259
2. **Resource Bundle Search**: Uses ResourceBundle.getBundle() to verify theme
260
3. **Fallback**: Returns default theme if validation fails
261
262
## Error Handling
263
264
Comprehensive error handling for all theme determination methods:
265
266
- **Service Not Found**: Returns default theme
267
- **Access Denied**: Returns default theme
268
- **Groovy Script Errors**: Logged, returns default theme
269
- **HTTP Errors**: Logged, returns default theme
270
- **Expression Errors**: Logged, returns default theme
271
- **Theme Validation Failures**: Logged, returns default theme
272
273
## Performance Considerations
274
275
- **Script Caching**: Groovy scripts are cached using CAS script resource cache
276
- **HTTP Caching**: No built-in HTTP response caching
277
- **Service Lookup**: Cached by ServicesManager implementation
278
- **Request Attributes**: Theme stored in request for reuse within request scope