0
# Filter Chain Management
1
2
Components for managing and resolving filter chains in Apache Shiro web applications. These classes handle the registration, configuration, and resolution of servlet filter chains based on URL patterns, enabling flexible and powerful security policy configuration.
3
4
## Capabilities
5
6
### Filter Chain Resolution
7
8
Core interfaces and implementations for resolving filter chains based on incoming requests and URL patterns.
9
10
```java { .api }
11
interface FilterChainResolver {
12
/**
13
* Resolves and returns the filter chain for the given request.
14
*
15
* @param request the incoming servlet request
16
* @param response the servlet response
17
* @param originalChain the original filter chain from the servlet container
18
* @return the resolved filter chain or originalChain if no specific chain found
19
*/
20
FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);
21
}
22
```
23
24
```java { .api }
25
class PathMatchingFilterChainResolver implements FilterChainResolver {
26
/**
27
* Creates a new PathMatchingFilterChainResolver.
28
*/
29
public PathMatchingFilterChainResolver();
30
31
/**
32
* Returns the FilterChainManager used to manage filter chains.
33
*
34
* @return the FilterChainManager instance
35
*/
36
public FilterChainManager getFilterChainManager();
37
38
/**
39
* Sets the FilterChainManager to use for managing filter chains.
40
*
41
* @param filterChainManager the FilterChainManager to set
42
*/
43
public void setFilterChainManager(FilterChainManager filterChainManager);
44
45
/**
46
* Resolves the filter chain by matching the request path against configured patterns.
47
*
48
* @param request the servlet request
49
* @param response the servlet response
50
* @param originalChain the original filter chain
51
* @return the matching filter chain or originalChain if no match
52
*/
53
public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);
54
55
/**
56
* Returns the request path used for pattern matching.
57
*
58
* @param request the servlet request
59
* @return the request path within the application
60
*/
61
protected String getPathWithinApplication(ServletRequest request);
62
}
63
```
64
65
### Filter Chain Management
66
67
Interfaces and implementations for managing named filter chains and their configurations.
68
69
```java { .api }
70
interface FilterChainManager extends FilterManager {
71
/**
72
* Returns all configured filter chains.
73
*
74
* @return Map of chain names to NamedFilterList instances
75
*/
76
Map<String, NamedFilterList> getFilterChains();
77
78
/**
79
* Returns whether any filter chains have been configured.
80
*
81
* @return true if chains exist
82
*/
83
boolean hasChains();
84
85
/**
86
* Returns the filter chain with the specified name.
87
*
88
* @param chainName the name of the chain to retrieve
89
* @return the NamedFilterList for the specified chain name
90
*/
91
NamedFilterList getChain(String chainName);
92
93
/**
94
* Creates a new filter chain with the specified name and configuration.
95
*
96
* @param chainName the name of the chain to create
97
* @param chainDefinition the chain configuration string
98
* @return the created NamedFilterList
99
*/
100
NamedFilterList createChain(String chainName, String chainDefinition);
101
102
/**
103
* Adds a filter to the specified chain.
104
*
105
* @param chainName the name of the chain
106
* @param filterName the name of the filter to add
107
*/
108
void addToChain(String chainName, String filterName);
109
110
/**
111
* Adds a filter to the specified chain with configuration.
112
*
113
* @param chainName the name of the chain
114
* @param filterName the name of the filter to add
115
* @param chainSpecificFilterConfig filter-specific configuration
116
*/
117
void addToChain(String chainName, String filterName, String chainSpecificFilterConfig);
118
119
/**
120
* Creates a filter chain from the given definition string.
121
*
122
* @param chainName the name of the chain
123
* @param chainDefinition comma-delimited filter names with optional configs
124
* @return the created NamedFilterList
125
*/
126
NamedFilterList createChain(String chainName, String chainDefinition);
127
}
128
```
129
130
```java { .api }
131
class DefaultFilterChainManager extends AbstractFilterChainManager {
132
/**
133
* Creates a new DefaultFilterChainManager with default filters.
134
*/
135
public DefaultFilterChainManager();
136
137
/**
138
* Creates a new DefaultFilterChainManager with the specified FilterConfig.
139
*
140
* @param filterConfig the FilterConfig for initializing filters
141
*/
142
public DefaultFilterChainManager(FilterConfig filterConfig);
143
144
/**
145
* Returns all configured filter chains.
146
*
147
* @return Map of chain names to filter chains
148
*/
149
public Map<String, NamedFilterList> getFilterChains();
150
151
/**
152
* Returns whether any filter chains exist.
153
*
154
* @return true if chains are configured
155
*/
156
public boolean hasChains();
157
158
/**
159
* Returns the filter chain with the specified name.
160
*
161
* @param chainName the chain name
162
* @return the NamedFilterList or null if not found
163
*/
164
public NamedFilterList getChain(String chainName);
165
166
/**
167
* Creates a filter chain from the definition string.
168
*
169
* @param chainName the name for the chain
170
* @param chainDefinition comma-delimited filter configuration
171
* @return the created NamedFilterList
172
*/
173
public NamedFilterList createChain(String chainName, String chainDefinition);
174
175
/**
176
* Adds a filter to the specified chain.
177
*
178
* @param chainName the chain name
179
* @param filterName the filter name to add
180
*/
181
public void addToChain(String chainName, String filterName);
182
183
/**
184
* Adds a filter to the specified chain with configuration.
185
*
186
* @param chainName the chain name
187
* @param filterName the filter name to add
188
* @param chainSpecificFilterConfig the filter configuration
189
*/
190
public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig);
191
192
/**
193
* Creates default filter instances for common Shiro filters.
194
*
195
* @return Map of filter names to Filter instances
196
*/
197
protected Map<String, Filter> createDefaultFilters();
198
199
/**
200
* Adds default filters to this manager.
201
*/
202
protected void addDefaultFilters(boolean init);
203
}
204
```
205
206
### Named Filter Lists
207
208
Classes representing named collections of filters that form filter chains.
209
210
```java { .api }
211
interface NamedFilterList extends List<Filter> {
212
/**
213
* Returns the name of this filter list.
214
*
215
* @return the filter list name
216
*/
217
String getName();
218
219
/**
220
* Creates a FilterChain that executes the filters in this list.
221
*
222
* @param originalChain the original filter chain to delegate to after processing
223
* @return a FilterChain that executes this list's filters
224
*/
225
FilterChain proxy(FilterChain originalChain);
226
}
227
```
228
229
```java { .api }
230
class SimpleNamedFilterList extends ArrayList<Filter> implements NamedFilterList {
231
/**
232
* Creates a new SimpleNamedFilterList with the specified name.
233
*
234
* @param name the name for this filter list
235
*/
236
public SimpleNamedFilterList(String name);
237
238
/**
239
* Creates a new SimpleNamedFilterList with the specified name and filters.
240
*
241
* @param name the name for this filter list
242
* @param filters the initial filters for this list
243
*/
244
public SimpleNamedFilterList(String name, List<Filter> filters);
245
246
/**
247
* Returns the name of this filter list.
248
*
249
* @return the filter list name
250
*/
251
public String getName();
252
253
/**
254
* Creates a proxied FilterChain that executes this list's filters.
255
*
256
* @param originalChain the original chain to execute after this list's filters
257
* @return a FilterChain proxy for this filter list
258
*/
259
public FilterChain proxy(FilterChain originalChain);
260
}
261
```
262
263
### Default Filters Enumeration
264
265
Enumeration defining all built-in Shiro filters available for use in filter chains.
266
267
```java { .api }
268
enum DefaultFilter {
269
anon(AnonymousFilter.class),
270
authc(FormAuthenticationFilter.class),
271
authcBasic(BasicHttpAuthenticationFilter.class),
272
authcBearer(BearerHttpAuthenticationFilter.class),
273
logout(LogoutFilter.class),
274
noSessionCreation(NoSessionCreationFilter.class),
275
perms(PermissionsAuthorizationFilter.class),
276
port(PortFilter.class),
277
rest(HttpMethodPermissionFilter.class),
278
roles(RolesAuthorizationFilter.class),
279
ssl(SslFilter.class),
280
user(UserFilter.class),
281
invalidRequest(InvalidRequestFilter.class);
282
283
/**
284
* Creates a new instance of this filter.
285
*
286
* @return a new Filter instance
287
*/
288
public Filter newInstance();
289
290
/**
291
* Returns the Filter class for this default filter.
292
*
293
* @return the Filter class
294
*/
295
public Class<? extends Filter> getFilterClass();
296
297
/**
298
* Creates a map of all default filters with their names as keys.
299
*
300
* @param filterConfig the FilterConfig for filter initialization
301
* @return Map of filter names to Filter instances
302
*/
303
public static Map<String, Filter> createInstanceMap(FilterConfig filterConfig);
304
}
305
```
306
307
### Filter Management Base Classes
308
309
Abstract base classes providing common filter management functionality.
310
311
```java { .api }
312
abstract class AbstractFilterChainManager implements FilterChainManager {
313
/**
314
* Returns all registered filters.
315
*
316
* @return Map of filter names to Filter instances
317
*/
318
public Map<String, Filter> getFilters();
319
320
/**
321
* Returns the filter with the specified name.
322
*
323
* @param name the filter name
324
* @return the Filter instance or null if not found
325
*/
326
public Filter getFilter(String name);
327
328
/**
329
* Adds a filter with the specified name.
330
*
331
* @param name the filter name
332
* @param filter the Filter instance
333
*/
334
public void addFilter(String name, Filter filter);
335
336
/**
337
* Adds a filter with the specified name and initializes it.
338
*
339
* @param name the filter name
340
* @param filter the Filter instance
341
* @param init whether to initialize the filter
342
*/
343
public void addFilter(String name, Filter filter, boolean init);
344
345
/**
346
* Creates a filter instance from the class name.
347
*
348
* @param className the fully qualified filter class name
349
* @param args constructor arguments
350
* @return the created Filter instance
351
*/
352
public Filter createFilter(String className, Object... args);
353
354
/**
355
* Initializes the specified filter.
356
*
357
* @param filter the filter to initialize
358
*/
359
protected void initFilter(Filter filter);
360
}
361
```
362
363
## Usage Examples
364
365
### Basic Filter Chain Configuration
366
367
```java
368
public void setupBasicFilterChains() {
369
// Create filter chain manager
370
DefaultFilterChainManager manager = new DefaultFilterChainManager();
371
372
// Basic authentication and authorization chains
373
manager.createChain("/login", "authc");
374
manager.createChain("/logout", "logout");
375
manager.createChain("/admin/**", "authc, roles[admin]");
376
manager.createChain("/user/**", "authc");
377
manager.createChain("/api/**", "authcBasic");
378
manager.createChain("/**", "anon");
379
380
// Create resolver and set in filter
381
PathMatchingFilterChainResolver resolver = new PathMatchingFilterChainResolver();
382
resolver.setFilterChainManager(manager);
383
384
// Use with AbstractShiroFilter
385
AbstractShiroFilter shiroFilter = new ShiroFilter();
386
shiroFilter.setFilterChainResolver(resolver);
387
}
388
```
389
390
### Advanced Filter Chain Configuration
391
392
```java
393
public void setupAdvancedFilterChains() {
394
DefaultFilterChainManager manager = new DefaultFilterChainManager();
395
396
// Add custom filters
397
manager.addFilter("jwt", new JwtAuthenticationFilter());
398
manager.addFilter("cors", new CorsFilter());
399
manager.addFilter("rate", new RateLimitFilter());
400
401
// Complex filter chains with multiple filters and configurations
402
manager.createChain("/api/public/**", "cors, anon");
403
manager.createChain("/api/auth/**", "cors, authc");
404
manager.createChain("/api/admin/**", "cors, jwt, roles[admin], rate");
405
manager.createChain("/api/users/**", "cors, jwt, perms[user:read], rate");
406
407
// SSL requirements for sensitive areas
408
manager.createChain("/secure/**", "ssl, authc, roles[user]");
409
manager.createChain("/admin/**", "ssl, authc, roles[admin]");
410
411
// Different authentication methods for different areas
412
manager.createChain("/web/login", "authc"); // Form auth for web
413
manager.createChain("/web/**", "authc, user"); // Web interface
414
manager.createChain("/api/v1/**", "authcBasic"); // Basic auth for API v1
415
manager.createChain("/api/v2/**", "jwt"); // JWT for API v2
416
417
// Create resolver
418
PathMatchingFilterChainResolver resolver = new PathMatchingFilterChainResolver();
419
resolver.setFilterChainManager(manager);
420
}
421
```
422
423
### Programmatic Chain Building
424
425
```java
426
public class FilterChainBuilder {
427
private DefaultFilterChainManager manager;
428
429
public FilterChainBuilder() {
430
this.manager = new DefaultFilterChainManager();
431
}
432
433
public FilterChainBuilder addCustomFilter(String name, Filter filter) {
434
manager.addFilter(name, filter);
435
return this;
436
}
437
438
public FilterChainBuilder publicAccess(String pattern) {
439
manager.createChain(pattern, "anon");
440
return this;
441
}
442
443
public FilterChainBuilder requireAuthentication(String pattern) {
444
manager.createChain(pattern, "authc");
445
return this;
446
}
447
448
public FilterChainBuilder requireRole(String pattern, String role) {
449
manager.createChain(pattern, "authc, roles[" + role + "]");
450
return this;
451
}
452
453
public FilterChainBuilder requirePermission(String pattern, String permission) {
454
manager.createChain(pattern, "authc, perms[" + permission + "]");
455
return this;
456
}
457
458
public FilterChainBuilder requireSsl(String pattern) {
459
manager.createChain(pattern, "ssl, authc");
460
return this;
461
}
462
463
public FilterChainBuilder apiAccess(String pattern, String authType) {
464
String chain = "cors";
465
if ("basic".equals(authType)) {
466
chain += ", authcBasic";
467
} else if ("bearer".equals(authType)) {
468
chain += ", authcBearer";
469
}
470
manager.createChain(pattern, chain);
471
return this;
472
}
473
474
public FilterChainManager build() {
475
return manager;
476
}
477
}
478
479
// Usage
480
public void buildFilterChains() {
481
FilterChainBuilder builder = new FilterChainBuilder()
482
.addCustomFilter("audit", new AuditFilter())
483
.publicAccess("/css/**")
484
.publicAccess("/js/**")
485
.publicAccess("/images/**")
486
.requireAuthentication("/login")
487
.requireSsl("/admin/**")
488
.requireRole("/admin/**", "admin")
489
.requirePermission("/reports/**", "report:read")
490
.apiAccess("/api/v1/**", "basic")
491
.apiAccess("/api/v2/**", "bearer")
492
.publicAccess("/**");
493
494
FilterChainManager manager = builder.build();
495
}
496
```
497
498
### Dynamic Filter Chain Modification
499
500
```java
501
public class DynamicFilterChainManager {
502
private DefaultFilterChainManager manager;
503
504
public DynamicFilterChainManager() {
505
this.manager = new DefaultFilterChainManager();
506
}
507
508
public void addSecurityRule(String pattern, String[] roles, String[] permissions) {
509
StringBuilder chainDef = new StringBuilder("authc");
510
511
if (roles != null && roles.length > 0) {
512
chainDef.append(", roles[").append(String.join(",", roles)).append("]");
513
}
514
515
if (permissions != null && permissions.length > 0) {
516
chainDef.append(", perms[").append(String.join(",", permissions)).append("]");
517
}
518
519
manager.createChain(pattern, chainDef.toString());
520
}
521
522
public void removeSecurityRule(String pattern) {
523
Map<String, NamedFilterList> chains = manager.getFilterChains();
524
chains.remove(pattern);
525
}
526
527
public void updateSecurityRule(String pattern, String newChainDefinition) {
528
removeSecurityRule(pattern);
529
manager.createChain(pattern, newChainDefinition);
530
}
531
532
public void addMaintenanceMode() {
533
// Add maintenance filter to all paths except admin
534
manager.addFilter("maintenance", new MaintenanceFilter());
535
manager.createChain("/**", "maintenance, anon");
536
manager.createChain("/admin/**", "ssl, authc, roles[admin]");
537
}
538
539
public void removeMaintenance() {
540
// Remove maintenance mode and restore normal chains
541
Map<String, NamedFilterList> chains = manager.getFilterChains();
542
chains.clear();
543
setupNormalChains();
544
}
545
546
private void setupNormalChains() {
547
manager.createChain("/admin/**", "ssl, authc, roles[admin]");
548
manager.createChain("/user/**", "authc");
549
manager.createChain("/**", "anon");
550
}
551
}
552
```
553
554
### Filter Chain Testing and Debugging
555
556
```java
557
public class FilterChainDebugger {
558
559
public void debugFilterChains(FilterChainManager manager) {
560
Map<String, NamedFilterList> chains = manager.getFilterChains();
561
562
System.out.println("=== Filter Chain Configuration ===");
563
for (Map.Entry<String, NamedFilterList> entry : chains.entrySet()) {
564
String pattern = entry.getKey();
565
NamedFilterList filterList = entry.getValue();
566
567
System.out.printf("Pattern: %s%n", pattern);
568
System.out.printf(" Chain: %s%n", filterList.getName());
569
System.out.printf(" Filters: ");
570
571
for (Filter filter : filterList) {
572
System.out.printf("%s ", filter.getClass().getSimpleName());
573
}
574
System.out.println();
575
}
576
}
577
578
public boolean testPathMatching(String testPath, FilterChainManager manager) {
579
PathMatchingFilterChainResolver resolver = new PathMatchingFilterChainResolver();
580
resolver.setFilterChainManager(manager);
581
582
MockHttpServletRequest request = new MockHttpServletRequest();
583
request.setRequestURI(testPath);
584
MockHttpServletResponse response = new MockHttpServletResponse();
585
586
FilterChain chain = resolver.getChain(request, response, null);
587
588
boolean hasCustomChain = !(chain instanceof javax.servlet.FilterChain);
589
System.out.printf("Path '%s' -> %s%n", testPath,
590
hasCustomChain ? "Custom Chain" : "Default Chain");
591
592
return hasCustomChain;
593
}
594
}
595
```