1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.shiro.web.filter.mgt;
20
21 import org.apache.shiro.config.ConfigurationException;
22 import org.apache.shiro.util.CollectionUtils;
23 import org.apache.shiro.util.Nameable;
24 import org.apache.shiro.util.StringUtils;
25 import org.apache.shiro.web.filter.PathConfigProcessor;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import javax.servlet.Filter;
30 import javax.servlet.FilterChain;
31 import javax.servlet.FilterConfig;
32 import javax.servlet.ServletException;
33 import java.util.Collections;
34 import java.util.LinkedHashMap;
35 import java.util.Map;
36 import java.util.Set;
37
38
39
40
41
42
43
44
45
46
47 public class DefaultFilterChainManager implements FilterChainManager {
48
49 private static transient final Logger log = LoggerFactory.getLogger(DefaultFilterChainManager.class);
50
51 private FilterConfig filterConfig;
52
53 private Map<String, Filter> filters;
54
55 private Map<String, NamedFilterList> filterChains;
56
57 public DefaultFilterChainManager() {
58 this.filters = new LinkedHashMap<String, Filter>();
59 this.filterChains = new LinkedHashMap<String, NamedFilterList>();
60 addDefaultFilters(false);
61 }
62
63 public DefaultFilterChainManager(FilterConfig filterConfig) {
64 this.filters = new LinkedHashMap<String, Filter>();
65 this.filterChains = new LinkedHashMap<String, NamedFilterList>();
66 setFilterConfig(filterConfig);
67 addDefaultFilters(true);
68 }
69
70
71
72
73
74
75 public FilterConfig getFilterConfig() {
76 return filterConfig;
77 }
78
79
80
81
82
83
84 public void setFilterConfig(FilterConfig filterConfig) {
85 this.filterConfig = filterConfig;
86 }
87
88 public Map<String, Filter> getFilters() {
89 return filters;
90 }
91
92 @SuppressWarnings({"UnusedDeclaration"})
93 public void setFilters(Map<String, Filter> filters) {
94 this.filters = filters;
95 }
96
97 public Map<String, NamedFilterList> getFilterChains() {
98 return filterChains;
99 }
100
101 @SuppressWarnings({"UnusedDeclaration"})
102 public void setFilterChains(Map<String, NamedFilterList> filterChains) {
103 this.filterChains = filterChains;
104 }
105
106 public Filter getFilter(String name) {
107 return this.filters.get(name);
108 }
109
110 public void addFilter(String name, Filter filter) {
111 addFilter(name, filter, false);
112 }
113
114 public void addFilter(String name, Filter filter, boolean init) {
115 addFilter(name, filter, init, true);
116 }
117
118 public void createChain(String chainName, String chainDefinition) {
119 if (!StringUtils.hasText(chainName)) {
120 throw new NullPointerException("chainName cannot be null or empty.");
121 }
122 if (!StringUtils.hasText(chainDefinition)) {
123 throw new NullPointerException("chainDefinition cannot be null or empty.");
124 }
125
126 if (log.isDebugEnabled()) {
127 log.debug("Creating chain [" + chainName + "] from String definition [" + chainDefinition + "]");
128 }
129
130
131
132
133
134
135
136
137
138
139
140 String[] filterTokens = splitChainDefinition(chainDefinition);
141
142
143
144 for (String token : filterTokens) {
145 String[] nameConfigPair = toNameConfigPair(token);
146
147
148 addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);
149 }
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 protected String[] splitChainDefinition(String chainDefinition) {
171 return StringUtils.split(chainDefinition, StringUtils.DEFAULT_DELIMITER_CHAR, '[', ']', true, true);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 protected String[] toNameConfigPair(String token) throws ConfigurationException {
198
199 try {
200 String[] pair = token.split("\\[", 2);
201 String name = StringUtils.clean(pair[0]);
202
203 if (name == null) {
204 throw new IllegalArgumentException("Filter name not found for filter chain definition token: " + token);
205 }
206 String config = null;
207
208 if (pair.length == 2) {
209 config = StringUtils.clean(pair[1]);
210
211 config = config.substring(0, config.length() - 1);
212 config = StringUtils.clean(config);
213
214
215
216
217
218 if (config != null && config.startsWith("\"") && config.endsWith("\"")) {
219 String stripped = config.substring(1, config.length() - 1);
220 stripped = StringUtils.clean(stripped);
221
222
223
224 if (stripped != null && stripped.indexOf('"') == -1) {
225 config = stripped;
226 }
227
228
229
230
231 }
232 }
233
234 return new String[]{name, config};
235
236 } catch (Exception e) {
237 String msg = "Unable to parse filter chain definition token: " + token;
238 throw new ConfigurationException(msg, e);
239 }
240 }
241
242 protected void addFilter(String name, Filter filter, boolean init, boolean overwrite) {
243 Filter existing = getFilter(name);
244 if (existing == null || overwrite) {
245 if (filter instanceof Nameable) {
246 ((Nameable) filter).setName(name);
247 }
248 if (init) {
249 initFilter(filter);
250 }
251 this.filters.put(name, filter);
252 }
253 }
254
255 public void addToChain(String chainName, String filterName) {
256 addToChain(chainName, filterName, null);
257 }
258
259 public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) {
260 if (!StringUtils.hasText(chainName)) {
261 throw new IllegalArgumentException("chainName cannot be null or empty.");
262 }
263 Filter filter = getFilter(filterName);
264 if (filter == null) {
265 throw new IllegalArgumentException("There is no filter with name '" + filterName +
266 "' to apply to chain [" + chainName + "] in the pool of available Filters. Ensure a " +
267 "filter with that name/path has first been registered with the addFilter method(s).");
268 }
269
270 applyChainConfig(chainName, filter, chainSpecificFilterConfig);
271
272 NamedFilterList chain = ensureChain(chainName);
273 chain.add(filter);
274 }
275
276 protected void applyChainConfig(String chainName, Filter filter, String chainSpecificFilterConfig) {
277 if (log.isDebugEnabled()) {
278 log.debug("Attempting to apply path [" + chainName + "] to filter [" + filter + "] " +
279 "with config [" + chainSpecificFilterConfig + "]");
280 }
281 if (filter instanceof PathConfigProcessor) {
282 ((PathConfigProcessor) filter).processPathConfig(chainName, chainSpecificFilterConfig);
283 } else {
284 if (StringUtils.hasText(chainSpecificFilterConfig)) {
285
286
287 String msg = "chainSpecificFilterConfig was specified, but the underlying " +
288 "Filter instance is not an 'instanceof' " +
289 PathConfigProcessor.class.getName() + ". This is required if the filter is to accept " +
290 "chain-specific configuration.";
291 throw new ConfigurationException(msg);
292 }
293 }
294 }
295
296 protected NamedFilterList ensureChain(String chainName) {
297 NamedFilterList chain = getChain(chainName);
298 if (chain == null) {
299 chain = new SimpleNamedFilterList(chainName);
300 this.filterChains.put(chainName, chain);
301 }
302 return chain;
303 }
304
305 public NamedFilterList getChain(String chainName) {
306 return this.filterChains.get(chainName);
307 }
308
309 public boolean hasChains() {
310 return !CollectionUtils.isEmpty(this.filterChains);
311 }
312
313 public Set<String> getChainNames() {
314
315 return this.filterChains != null ? this.filterChains.keySet() : Collections.EMPTY_SET;
316 }
317
318 public FilterChain proxy(FilterChain original, String chainName) {
319 NamedFilterList configured = getChain(chainName);
320 if (configured == null) {
321 String msg = "There is no configured chain under the name/key [" + chainName + "].";
322 throw new IllegalArgumentException(msg);
323 }
324 return configured.proxy(original);
325 }
326
327
328
329
330
331
332 protected void initFilter(Filter filter) {
333 FilterConfig filterConfig = getFilterConfig();
334 if (filterConfig == null) {
335 throw new IllegalStateException("FilterConfig attribute has not been set. This must occur before filter " +
336 "initialization can occur.");
337 }
338 try {
339 filter.init(filterConfig);
340 } catch (ServletException e) {
341 throw new ConfigurationException(e);
342 }
343 }
344
345 protected void addDefaultFilters(boolean init) {
346 for (DefaultFilter defaultFilter : DefaultFilter.values()) {
347 addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
348 }
349 }
350 }