or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auto-configuration.mdheader-theme-resolution.mdindex.mdservice-theme-resolution.mdtheme-resolution.mdtheme-sources.md

service-theme-resolution.mddocs/

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