0
# Ticket Caching
1
2
Stateless ticket caching implementations for performance optimization in clustered and stateless authentication scenarios. These components provide caching strategies to avoid repeated CAS server validation calls for the same service tickets.
3
4
## Capabilities
5
6
### Stateless Ticket Cache Interface
7
8
Core interface defining ticket caching operations for stateless CAS authentication scenarios.
9
10
```java { .api }
11
/**
12
* Interface for caching CAS authentication tokens to avoid repeated server validation.
13
* Used in stateless authentication scenarios where tickets need to be validated multiple times.
14
*/
15
public interface StatelessTicketCache {
16
17
/**
18
* Gets a cached authentication token by service ticket ID.
19
* @param serviceTicket the CAS service ticket to look up
20
* @return cached CasAuthenticationToken or null if not found or expired
21
*/
22
CasAuthenticationToken getByTicketId(String serviceTicket);
23
24
/**
25
* Stores an authentication token in the cache.
26
* @param token the CasAuthenticationToken to cache
27
* @throws IllegalArgumentException if token is null or invalid
28
*/
29
void putTicketInCache(CasAuthenticationToken token);
30
31
/**
32
* Removes an authentication token from the cache.
33
* @param token the CasAuthenticationToken to remove
34
*/
35
void removeTicketFromCache(CasAuthenticationToken token);
36
37
/**
38
* Removes an authentication token from the cache by service ticket ID.
39
* @param serviceTicket the service ticket ID to remove
40
*/
41
void removeTicketFromCache(String serviceTicket);
42
}
43
```
44
45
### Null Stateless Ticket Cache
46
47
No-operation implementation that disables ticket caching entirely.
48
49
```java { .api }
50
/**
51
* No-operation implementation of StatelessTicketCache that performs no caching.
52
* All operations are no-ops, effectively disabling ticket caching.
53
* Used when caching is not desired or in development environments.
54
*/
55
public final class NullStatelessTicketCache implements StatelessTicketCache {
56
57
/**
58
* Always returns null, indicating no cached ticket found.
59
* @param serviceTicket the service ticket (ignored)
60
* @return null always
61
*/
62
public CasAuthenticationToken getByTicketId(String serviceTicket);
63
64
/**
65
* No-operation method that does not store the token.
66
* @param token the token to cache (ignored)
67
*/
68
public void putTicketInCache(CasAuthenticationToken token);
69
70
/**
71
* No-operation method that does not remove anything.
72
* @param token the token to remove (ignored)
73
*/
74
public void removeTicketFromCache(CasAuthenticationToken token);
75
76
/**
77
* No-operation method that does not remove anything.
78
* @param serviceTicket the service ticket to remove (ignored)
79
*/
80
public void removeTicketFromCache(String serviceTicket);
81
}
82
```
83
84
**Usage Example:**
85
86
```java
87
@Bean
88
public StatelessTicketCache nullTicketCache() {
89
return new NullStatelessTicketCache();
90
}
91
```
92
93
### Spring Cache-Based Ticket Cache
94
95
Production-ready implementation using Spring's cache abstraction for distributed caching support.
96
97
```java { .api }
98
/**
99
* StatelessTicketCache implementation backed by Spring's Cache abstraction.
100
* Supports various cache providers (Redis, Hazelcast, Ehcache, etc.) through Spring Cache.
101
*/
102
public class SpringCacheBasedTicketCache implements StatelessTicketCache {
103
104
/**
105
* Creates cache implementation with specified Spring Cache instance.
106
* @param cache Spring Cache instance to use for storage
107
* @throws IllegalArgumentException if cache is null
108
*/
109
public SpringCacheBasedTicketCache(Cache cache);
110
111
/**
112
* Retrieves cached authentication token by service ticket ID.
113
* @param serviceTicket the service ticket to look up
114
* @return cached CasAuthenticationToken or null if not found
115
*/
116
public CasAuthenticationToken getByTicketId(String serviceTicket);
117
118
/**
119
* Stores authentication token in the cache using the service ticket as key.
120
* @param token the CasAuthenticationToken to cache (must not be null)
121
* @throws IllegalArgumentException if token or its credentials are null
122
*/
123
public void putTicketInCache(CasAuthenticationToken token);
124
125
/**
126
* Removes authentication token from cache.
127
* @param token the token to remove (uses token's credentials as key)
128
*/
129
public void removeTicketFromCache(CasAuthenticationToken token);
130
131
/**
132
* Removes authentication token from cache by service ticket ID.
133
* @param serviceTicket the service ticket ID to remove from cache
134
*/
135
public void removeTicketFromCache(String serviceTicket);
136
}
137
```
138
139
**Usage Example:**
140
141
```java
142
@Configuration
143
@EnableCaching
144
public class TicketCacheConfig {
145
146
@Bean
147
public CacheManager cacheManager() {
148
RedisCacheManager.Builder builder = RedisCacheManager
149
.RedisCacheManagerBuilder
150
.fromConnectionFactory(redisConnectionFactory())
151
.cacheDefaults(cacheConfiguration());
152
return builder.build();
153
}
154
155
@Bean
156
public StatelessTicketCache springCacheBasedTicketCache() {
157
Cache cache = cacheManager().getCache("casTickets");
158
return new SpringCacheBasedTicketCache(cache);
159
}
160
161
private RedisCacheConfiguration cacheConfiguration() {
162
return RedisCacheConfiguration.defaultCacheConfig()
163
.entryTtl(Duration.ofMinutes(5)) // Cache tickets for 5 minutes
164
.serializeKeysWith(RedisSerializationContext.SerializationPair
165
.fromSerializer(new StringRedisSerializer()))
166
.serializeValuesWith(RedisSerializationContext.SerializationPair
167
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
168
}
169
}
170
```
171
172
## Cache Configuration Examples
173
174
### Redis-Based Caching
175
176
```java
177
@Configuration
178
@EnableCaching
179
public class RedisCacheConfig {
180
181
@Bean
182
public LettuceConnectionFactory redisConnectionFactory() {
183
return new LettuceConnectionFactory(
184
new RedisStandaloneConfiguration("localhost", 6379));
185
}
186
187
@Bean
188
public RedisCacheManager cacheManager() {
189
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
190
.entryTtl(Duration.ofMinutes(10)) // 10-minute TTL
191
.disableCachingNullValues()
192
.serializeKeysWith(RedisSerializationContext.SerializationPair
193
.fromSerializer(new StringRedisSerializer()))
194
.serializeValuesWith(RedisSerializationContext.SerializationPair
195
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
196
197
return RedisCacheManager.builder(redisConnectionFactory())
198
.cacheDefaults(config)
199
.build();
200
}
201
202
@Bean
203
public StatelessTicketCache redisTicketCache() {
204
Cache cache = cacheManager().getCache("cas-tickets");
205
return new SpringCacheBasedTicketCache(cache);
206
}
207
}
208
```
209
210
### Hazelcast-Based Caching
211
212
```java
213
@Configuration
214
@EnableCaching
215
public class HazelcastCacheConfig {
216
217
@Bean
218
public HazelcastInstance hazelcastInstance() {
219
Config config = new Config();
220
config.getMapConfig("cas-tickets")
221
.setTimeToLiveSeconds(300) // 5-minute TTL
222
.setMaxIdleSeconds(300);
223
return Hazelcast.newHazelcastInstance(config);
224
}
225
226
@Bean
227
public CacheManager hazelcastCacheManager() {
228
return new HazelcastCacheManager(hazelcastInstance());
229
}
230
231
@Bean
232
public StatelessTicketCache hazelcastTicketCache() {
233
Cache cache = hazelcastCacheManager().getCache("cas-tickets");
234
return new SpringCacheBasedTicketCache(cache);
235
}
236
}
237
```
238
239
### Ehcache-Based Caching
240
241
```java
242
@Configuration
243
@EnableCaching
244
public class EhcacheConfig {
245
246
@Bean
247
public CacheManager ehCacheManager() {
248
CachingProvider provider = Caching.getCachingProvider();
249
javax.cache.CacheManager cacheManager = provider.getCacheManager();
250
251
javax.cache.configuration.Configuration<String, CasAuthenticationToken> configuration =
252
Eh107Configuration.fromEhcacheCacheConfiguration(
253
CacheConfigurationBuilder
254
.newCacheConfigurationBuilder(String.class, CasAuthenticationToken.class,
255
ResourcePoolsBuilder.heap(1000))
256
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(5)))
257
.build());
258
259
cacheManager.createCache("cas-tickets", configuration);
260
return new JCacheCacheManager(cacheManager);
261
}
262
263
@Bean
264
public StatelessTicketCache ehcacheTicketCache() {
265
Cache cache = ehCacheManager().getCache("cas-tickets");
266
return new SpringCacheBasedTicketCache(cache);
267
}
268
}
269
```
270
271
## Cache Integration with Authentication Provider
272
273
```java
274
@Bean
275
public CasAuthenticationProvider casAuthenticationProvider() {
276
CasAuthenticationProvider provider = new CasAuthenticationProvider();
277
provider.setServiceProperties(serviceProperties());
278
provider.setTicketValidator(ticketValidator());
279
provider.setUserDetailsService(userDetailsService());
280
provider.setKey("cas-authentication-provider");
281
282
// Set ticket cache for performance optimization
283
provider.setStatelessTicketCache(springCacheBasedTicketCache());
284
285
return provider;
286
}
287
```
288
289
## Cache Considerations
290
291
### Cache Key Strategy
292
293
The cache uses the CAS service ticket as the key:
294
295
```java
296
// Cache key format
297
String cacheKey = casAuthenticationToken.getCredentials().toString();
298
299
// Example cache key
300
"ST-123456-abcdefghijklmnop-cas-server.example.com"
301
```
302
303
### Cache Expiration
304
305
- **Short TTL**: Tickets should expire quickly to maintain security
306
- **Ticket Lifetime**: Should not exceed CAS server ticket expiration
307
- **Recommended**: 5-10 minutes maximum
308
- **Security**: Shorter expiration reduces risk of ticket replay
309
310
### Serialization Requirements
311
312
Cached objects must be serializable:
313
314
```java
315
// CasAuthenticationToken implements Serializable
316
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
317
private static final long serialVersionUID = 1L;
318
// ...
319
}
320
```
321
322
### Performance Benefits
323
324
- **Reduced Network Calls**: Avoids repeated CAS server validation
325
- **Improved Response Time**: Local cache access vs. network round-trip
326
- **Server Load Reduction**: Decreases load on CAS server
327
- **Scalability**: Better performance in high-traffic scenarios
328
329
### Cache Monitoring
330
331
```java
332
@Component
333
public class CacheMetrics {
334
335
@Autowired
336
private CacheManager cacheManager;
337
338
@EventListener
339
public void handleCacheHit(CacheHitEvent event) {
340
// Log or meter cache hits
341
log.debug("Cache hit for ticket: {}", event.getKey());
342
}
343
344
@EventListener
345
public void handleCacheMiss(CacheMissEvent event) {
346
// Log or meter cache misses
347
log.debug("Cache miss for ticket: {}", event.getKey());
348
}
349
}
350
```
351
352
## Security Considerations
353
354
- **Cache Isolation**: Separate cache namespace for CAS tickets
355
- **Access Control**: Restrict cache access to authentication components
356
- **Encryption**: Consider encrypting cached authentication tokens
357
- **Audit Trail**: Log cache operations for security monitoring
358
- **Cleanup**: Ensure proper cache cleanup on logout or session invalidation
359
360
## Best Practices
361
362
1. **Use Distributed Cache**: For clustered applications
363
2. **Short Expiration**: Keep TTL under 10 minutes
364
3. **Monitor Performance**: Track cache hit/miss ratios
365
4. **Secure Configuration**: Encrypt sensitive cache data
366
5. **Proper Sizing**: Configure appropriate cache size limits
367
6. **Exception Handling**: Handle cache failures gracefully