1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.shiro.web.env;
20
21 import org.apache.shiro.config.ConfigurationException;
22 import org.apache.shiro.config.Ini;
23 import org.apache.shiro.config.IniFactorySupport;
24 import org.apache.shiro.io.ResourceUtils;
25 import org.apache.shiro.util.*;
26 import org.apache.shiro.web.config.IniFilterChainResolverFactory;
27 import org.apache.shiro.web.config.WebIniSecurityManagerFactory;
28 import org.apache.shiro.web.filter.mgt.FilterChainResolver;
29 import org.apache.shiro.web.mgt.WebSecurityManager;
30 import org.apache.shiro.web.util.WebUtils;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import javax.servlet.ServletContext;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.util.HashMap;
38 import java.util.Map;
39
40
41
42
43
44
45 public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
46
47 public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini";
48 public static final String FILTER_CHAIN_RESOLVER_NAME = "filterChainResolver";
49
50 private static final Logger log = LoggerFactory.getLogger(IniWebEnvironment.class);
51
52
53
54
55 private Ini ini;
56
57 private WebIniSecurityManagerFactory factory;
58
59 public IniWebEnvironment() {
60 factory = new WebIniSecurityManagerFactory();
61 }
62
63
64
65
66
67 public void init() {
68
69 setIni(parseConfig());
70
71 configure();
72 }
73
74
75
76
77
78
79
80
81 protected Ini parseConfig() {
82 Ini ini = getIni();
83
84 String[] configLocations = getConfigLocations();
85
86 if (log.isWarnEnabled() && !CollectionUtils.isEmpty(ini) &&
87 configLocations != null && configLocations.length > 0) {
88 log.warn("Explicit INI instance has been provided, but configuration locations have also been " +
89 "specified. The {} implementation does not currently support multiple Ini config, but this may " +
90 "be supported in the future. Only the INI instance will be used for configuration.",
91 IniWebEnvironment.class.getName());
92 }
93
94 if (CollectionUtils.isEmpty(ini)) {
95 log.debug("Checking any specified config locations.");
96 ini = getSpecifiedIni(configLocations);
97 }
98
99 if (CollectionUtils.isEmpty(ini)) {
100 log.debug("No INI instance or config locations specified. Trying default config locations.");
101 ini = getDefaultIni();
102 }
103
104
105
106 ini = mergeIni(getFrameworkIni(), ini);
107
108 if (CollectionUtils.isEmpty(ini)) {
109 String msg = "Shiro INI configuration was either not found or discovered to be empty/unconfigured.";
110 throw new ConfigurationException(msg);
111 }
112 return ini;
113 }
114
115 protected void configure() {
116
117 this.objects.clear();
118
119 WebSecurityManager securityManager = createWebSecurityManager();
120 setWebSecurityManager(securityManager);
121
122 FilterChainResolver resolver = createFilterChainResolver();
123 if (resolver != null) {
124 setFilterChainResolver(resolver);
125 }
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 protected Ini getFrameworkIni() {
169 return null;
170 }
171
172 protected Ini getSpecifiedIni(String[] configLocations) throws ConfigurationException {
173
174 Ini ini = null;
175
176 if (configLocations != null && configLocations.length > 0) {
177
178 if (configLocations.length > 1) {
179 log.warn("More than one Shiro .ini config location has been specified. Only the first will be " +
180 "used for configuration as the {} implementation does not currently support multiple " +
181 "files. This may be supported in the future however.", IniWebEnvironment.class.getName());
182 }
183
184
185 ini = createIni(configLocations[0], true);
186 }
187
188 return ini;
189 }
190
191 protected Ini mergeIni(Ini ini1, Ini ini2) {
192
193 if (ini1 == null) {
194 return ini2;
195 }
196
197 if (ini2 == null) {
198 return ini1;
199 }
200
201
202 Ini iniResult = new Ini(ini1);
203 iniResult.merge(ini2);
204
205 return iniResult;
206 }
207
208 protected Ini getDefaultIni() {
209
210 Ini ini = null;
211
212 String[] configLocations = getDefaultConfigLocations();
213 if (configLocations != null) {
214 for (String location : configLocations) {
215 ini = createIni(location, false);
216 if (!CollectionUtils.isEmpty(ini)) {
217 log.debug("Discovered non-empty INI configuration at location '{}'. Using for configuration.",
218 location);
219 break;
220 }
221 }
222 }
223
224 return ini;
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239 protected Ini createIni(String configLocation, boolean required) throws ConfigurationException {
240
241 Ini ini = null;
242
243 if (configLocation != null) {
244 ini = convertPathToIni(configLocation, required);
245 }
246 if (required && CollectionUtils.isEmpty(ini)) {
247 String msg = "Required configuration location '" + configLocation + "' does not exist or did not " +
248 "contain any INI configuration.";
249 throw new ConfigurationException(msg);
250 }
251
252 return ini;
253 }
254
255 protected FilterChainResolver createFilterChainResolver() {
256
257 FilterChainResolver resolver = null;
258
259 Ini ini = getIni();
260
261 if (!CollectionUtils.isEmpty(ini)) {
262
263 Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS);
264 Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS);
265 if (!CollectionUtils.isEmpty(urls) || !CollectionUtils.isEmpty(filters)) {
266
267
268 Factory<FilterChainResolver> factory = (Factory<FilterChainResolver>) this.objects.get(FILTER_CHAIN_RESOLVER_NAME);
269 if (factory instanceof IniFactorySupport) {
270 IniFactorySupport iniFactory = (IniFactorySupport) factory;
271 iniFactory.setIni(ini);
272 iniFactory.setDefaults(this.objects);
273 }
274 resolver = factory.getInstance();
275 }
276 }
277
278 return resolver;
279 }
280
281 protected WebSecurityManager createWebSecurityManager() {
282
283 Ini ini = getIni();
284 if (!CollectionUtils.isEmpty(ini)) {
285 factory.setIni(ini);
286 }
287
288 Map<String, Object> defaults = getDefaults();
289 if (!CollectionUtils.isEmpty(defaults)) {
290 factory.setDefaults(defaults);
291 }
292
293 WebSecurityManager../../org/apache/shiro/web/mgt/WebSecurityManager.html#WebSecurityManager">WebSecurityManager wsm = (WebSecurityManager)factory.getInstance();
294
295
296
297 Map<String, ?> beans = factory.getBeans();
298 if (!CollectionUtils.isEmpty(beans)) {
299 this.objects.putAll(beans);
300 }
301
302 return wsm;
303 }
304
305
306
307
308
309
310 protected String[] getDefaultConfigLocations() {
311 return new String[]{
312 DEFAULT_WEB_INI_RESOURCE_PATH,
313 IniFactorySupport.DEFAULT_INI_RESOURCE_PATH
314 };
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328 private Ini convertPathToIni(String path, boolean required) {
329
330
331
332 Ini ini = null;
333
334 if (StringUtils.hasText(path)) {
335 InputStream is = null;
336
337
338 if (!ResourceUtils.hasResourcePrefix(path)) {
339 is = getServletContextResourceStream(path);
340 } else {
341 try {
342 is = ResourceUtils.getInputStreamForPath(path);
343 } catch (IOException e) {
344 if (required) {
345 throw new ConfigurationException(e);
346 } else {
347 if (log.isDebugEnabled()) {
348 log.debug("Unable to load optional path '" + path + "'.", e);
349 }
350 }
351 }
352 }
353 if (is != null) {
354 ini = new Ini();
355 ini.load(is);
356 } else {
357 if (required) {
358 throw new ConfigurationException("Unable to load resource path '" + path + "'");
359 }
360 }
361 }
362
363 return ini;
364 }
365
366
367 private InputStream getServletContextResourceStream(String path) {
368 InputStream is = null;
369
370 path = WebUtils.normalize(path);
371 ServletContext sc = getServletContext();
372 if (sc != null) {
373 is = sc.getResourceAsStream(path);
374 }
375
376 return is;
377 }
378
379
380
381
382
383
384 public Ini getIni() {
385 return this.ini;
386 }
387
388
389
390
391
392
393
394
395
396 public void setIni(Ini ini) {
397 this.ini = ini;
398 }
399
400 protected Map<String, Object> getDefaults() {
401 Map<String, Object> defaults = new HashMap<String, Object>();
402 defaults.put(FILTER_CHAIN_RESOLVER_NAME, new IniFilterChainResolverFactory());
403 return defaults;
404 }
405
406
407
408
409
410
411
412 @SuppressWarnings("unused")
413 protected WebIniSecurityManagerFactory getSecurityManagerFactory() {
414 return factory;
415 }
416
417
418
419
420
421
422
423 protected void setSecurityManagerFactory(WebIniSecurityManagerFactory factory) {
424 this.factory = factory;
425 }
426 }