Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
IniShiroFilter |
|
| 2.6;2.6 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | package org.apache.shiro.web.servlet; | |
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.mgt.SecurityManager; | |
26 | import org.apache.shiro.util.CollectionUtils; | |
27 | import org.apache.shiro.util.StringUtils; | |
28 | import org.apache.shiro.web.config.IniFilterChainResolverFactory; | |
29 | import org.apache.shiro.web.config.WebIniSecurityManagerFactory; | |
30 | import org.apache.shiro.web.filter.mgt.FilterChainResolver; | |
31 | import org.apache.shiro.web.mgt.WebSecurityManager; | |
32 | import org.apache.shiro.web.util.WebUtils; | |
33 | import org.slf4j.Logger; | |
34 | import org.slf4j.LoggerFactory; | |
35 | ||
36 | import java.io.InputStream; | |
37 | import java.util.Map; | |
38 | ||
39 | /** | |
40 | * <h1>Deprecated</h1> | |
41 | * This filter has been deprecated as of Shiro 1.2 in favor of using the {@link ShiroFilter} in {@code web.xml} instead. | |
42 | * See the {@link ShiroFilter} JavaDoc for usage. | |
43 | * <p/> | |
44 | * ====================== | |
45 | * <p/> | |
46 | * Servlet Filter that configures and enables all Shiro functions within a web application by using the | |
47 | * <a href="http://en.wikipedia.org/wiki/INI_file">INI</a> configuration format. | |
48 | * <p/> | |
49 | * The actual INI configuration contents are not covered here, but instead in Shiro's | |
50 | * <a href="http://shiro.apache.org/configuration.html">Configuration Documentation</a> and additional web-specific | |
51 | * <a href="http://shiro.apache.org/web.html">Web Documentation</a>. | |
52 | * <h2>Usage</h2> | |
53 | * <h3>Default</h3> | |
54 | * By default, the simplest filter declaration expects a {@code shiro.ini} resource to be located at | |
55 | * {@code /WEB-INF/shiro.ini}, or, if not there, falls back to checking the root of the classpath | |
56 | * (i.e. {@code classpath:shiro.ini}): | |
57 | * <pre> | |
58 | * <filter> | |
59 | * <filter-name>ShiroFilter</filter-name> | |
60 | * <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> | |
61 | * </filter> | |
62 | * </pre> | |
63 | * <h3>Custom Path</h3> | |
64 | * If you want the INI configuration to be somewhere other than {@code /WEB-INF/shiro.ini} or | |
65 | * {@code classpath:shiro.ini}, you may specify an alternate location via the {@code configPath init-param}: | |
66 | * <pre> | |
67 | * <filter> | |
68 | * <filter-name>ShiroFilter</filter-name> | |
69 | * <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> | |
70 | * <init-param> | |
71 | * <param-name>configPath</param-name> | |
72 | * <param-value>/WEB-INF/someFile.ini</param-value> | |
73 | * </init-param> | |
74 | * </filter> | |
75 | * </pre> | |
76 | * Unqualified (schemeless or 'non-prefixed') paths are assumed to be {@code ServletContext} resource paths, resolvable | |
77 | * via {@link javax.servlet.ServletContext#getResourceAsStream(String) ServletContext#getResourceAsStream}. | |
78 | * <p/> | |
79 | * Non-ServletContext resources may be loaded from qualified locations by specifying prefixes indicating the source, | |
80 | * e.g. {@code file:}, {@code url:}, and {@code classpath:}. See the | |
81 | * {@link ResourceUtils#getInputStreamForPath(String)} JavaDoc for more. | |
82 | * <h3>Inline</h3> | |
83 | * For relatively simple environments, you can embed the INI config directly inside the filter declaration with | |
84 | * the {@code config init-param}: | |
85 | * <pre> | |
86 | * <filter> | |
87 | * <filter-name>ShiroFilter</filter-name> | |
88 | * <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> | |
89 | * <init-param> | |
90 | * <param-name>config</param-name> | |
91 | * <param-value> | |
92 | * #INI config goes here... | |
93 | * </param-value> | |
94 | * </init-param> | |
95 | * </filter> | |
96 | * </pre> | |
97 | * Although this is typically not recommended because any Shiro configuration changes would contribute to version control | |
98 | * 'noise' in the web.xml file. | |
99 | * <p/> | |
100 | * When creating the shiro.ini configuration itself, please see Shiro's | |
101 | * <a href="http://shiro.apache.org/configuration.html">Configuration Documentation</a> and | |
102 | * <a href="http://shiro.apache.org/web.html">Web Documentation</a>. | |
103 | * | |
104 | * @see <a href="http://shiro.apache.org/configuration.html">Apache Shiro INI Configuration</a> | |
105 | * @see <a href="http://shiro.apache.org/web.html">Apache Shiro Web Documentation</a> | |
106 | * @since 1.0 | |
107 | * @deprecated in 1.2 in favor of using the {@link ShiroFilter} | |
108 | */ | |
109 | @Deprecated | |
110 | public class IniShiroFilter extends AbstractShiroFilter { | |
111 | ||
112 | public static final String CONFIG_INIT_PARAM_NAME = "config"; | |
113 | public static final String CONFIG_PATH_INIT_PARAM_NAME = "configPath"; | |
114 | ||
115 | public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini"; | |
116 | ||
117 | 2 | private static final Logger log = LoggerFactory.getLogger(IniShiroFilter.class); |
118 | ||
119 | private String config; | |
120 | private String configPath; | |
121 | ||
122 | 10 | public IniShiroFilter() { |
123 | 10 | } |
124 | ||
125 | /** | |
126 | * Returns the actual INI configuration text to use to build the {@link SecurityManager} and | |
127 | * {@link FilterChainResolver} used by the web application or {@code null} if the | |
128 | * {@link #getConfigPath() configPath} should be used to load a fallback INI source. | |
129 | * <p/> | |
130 | * This value is {@code null} by default, but it will be automatically set to the value of the | |
131 | * '{@code config}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet | |
132 | * container at startup. | |
133 | * | |
134 | * @return the actual INI configuration text to use to build the {@link SecurityManager} and | |
135 | * {@link FilterChainResolver} used by the web application or {@code null} if the | |
136 | * {@link #getConfigPath() configPath} should be used to load a fallback INI source. | |
137 | */ | |
138 | public String getConfig() { | |
139 | 10 | return this.config; |
140 | } | |
141 | ||
142 | /** | |
143 | * Sets the actual INI configuration text to use to build the {@link SecurityManager} and | |
144 | * {@link FilterChainResolver} used by the web application. If this value is {@code null}, the | |
145 | * {@link #getConfigPath() configPath} will be checked to see if a .ini file should be loaded instead. | |
146 | * <p/> | |
147 | * This value is {@code null} by default, but it will be automatically set to the value of the | |
148 | * '{@code config}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet | |
149 | * container at startup. | |
150 | * | |
151 | * @param config the actual INI configuration text to use to build the {@link SecurityManager} and | |
152 | * {@link FilterChainResolver} used by the web application. | |
153 | */ | |
154 | public void setConfig(String config) { | |
155 | 2 | this.config = config; |
156 | 2 | } |
157 | ||
158 | /** | |
159 | * Returns the config path to be used to load a .ini file for configuration if a configuration is | |
160 | * not specified via the {@link #getConfig() config} attribute. | |
161 | * <p/> | |
162 | * This value is {@code null} by default, but it will be automatically set to the value of the | |
163 | * '{@code configPath}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet | |
164 | * container at startup. | |
165 | * | |
166 | * @return the config path to be used to load a .ini file for configuration if a configuration is | |
167 | * not specified via the {@link #getConfig() config} attribute. | |
168 | */ | |
169 | public String getConfigPath() { | |
170 | 8 | return configPath; |
171 | } | |
172 | ||
173 | /** | |
174 | * Sets the config path to be used to load a .ini file for configuration if a configuration is | |
175 | * not specified via the {@link #getConfig() config} attribute. | |
176 | * <p/> | |
177 | * This value is {@code null} by default, but it will be automatically set to the value of the | |
178 | * '{@code configPath}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet | |
179 | * container at startup. | |
180 | * | |
181 | * @param configPath the config path to be used to load a .ini file for configuration if a configuration is | |
182 | * not specified via the {@link #getConfig() config} attribute. | |
183 | */ | |
184 | public void setConfigPath(String configPath) { | |
185 | 4 | this.configPath = StringUtils.clean(configPath); |
186 | 4 | } |
187 | ||
188 | public void init() throws Exception { | |
189 | 10 | applyInitParams(); |
190 | 10 | configure(); |
191 | 8 | } |
192 | ||
193 | protected void applyInitParams() throws Exception { | |
194 | 10 | String config = getInitParam(CONFIG_INIT_PARAM_NAME); |
195 | 10 | if (config != null) { |
196 | 2 | setConfig(config); |
197 | } | |
198 | 10 | String configPath = getInitParam(CONFIG_PATH_INIT_PARAM_NAME); |
199 | 10 | if (configPath != null) { |
200 | 4 | setConfigPath(configPath); |
201 | } | |
202 | 10 | } |
203 | ||
204 | protected void configure() throws Exception { | |
205 | 10 | Ini ini = loadIniFromConfig(); |
206 | ||
207 | 10 | if (CollectionUtils.isEmpty(ini)) { |
208 | 8 | log.info("Null or empty configuration specified via 'config' init-param. " + |
209 | "Checking path-based configuration."); | |
210 | 8 | ini = loadIniFromPath(); |
211 | } | |
212 | //added for SHIRO-178: | |
213 | 8 | if (CollectionUtils.isEmpty(ini)) { |
214 | 4 | log.info("Null or empty configuration specified via '" + CONFIG_INIT_PARAM_NAME + "' or '" + |
215 | CONFIG_PATH_INIT_PARAM_NAME + "' filter parameters. Trying the default " + | |
216 | DEFAULT_WEB_INI_RESOURCE_PATH + " file."); | |
217 | 4 | ini = getServletContextIniResource(DEFAULT_WEB_INI_RESOURCE_PATH); |
218 | } | |
219 | //although the preferred default is /WEB-INF/shiro.ini per SHIRO-178, keep this | |
220 | //for backwards compatibility: | |
221 | 8 | if (CollectionUtils.isEmpty(ini)) { |
222 | 2 | log.info("Null or empty configuration specified via '" + CONFIG_INIT_PARAM_NAME + "' or '" + |
223 | CONFIG_PATH_INIT_PARAM_NAME + "' filter parameters. Trying the default " + | |
224 | IniFactorySupport.DEFAULT_INI_RESOURCE_PATH + " file."); | |
225 | 2 | ini = IniFactorySupport.loadDefaultClassPathIni(); |
226 | } | |
227 | ||
228 | 8 | Map<String, ?> objects = applySecurityManager(ini); |
229 | 8 | applyFilterChainResolver(ini, objects); |
230 | 8 | } |
231 | ||
232 | protected Ini loadIniFromConfig() { | |
233 | 10 | Ini ini = null; |
234 | 10 | String config = getConfig(); |
235 | 10 | if (config != null) { |
236 | 2 | ini = convertConfigToIni(config); |
237 | } | |
238 | 10 | return ini; |
239 | } | |
240 | ||
241 | protected Ini loadIniFromPath() { | |
242 | 8 | Ini ini = null; |
243 | 8 | String path = getConfigPath(); |
244 | 8 | if (path != null) { |
245 | 4 | ini = convertPathToIni(path); |
246 | } | |
247 | 6 | return ini; |
248 | } | |
249 | ||
250 | protected Map<String, ?> applySecurityManager(Ini ini) { | |
251 | WebIniSecurityManagerFactory factory; | |
252 | 8 | if (CollectionUtils.isEmpty(ini)) { |
253 | 2 | factory = new WebIniSecurityManagerFactory(); |
254 | } else { | |
255 | 6 | factory = new WebIniSecurityManagerFactory(ini); |
256 | } | |
257 | ||
258 | // Create the security manager and check that it implements WebSecurityManager. | |
259 | // Otherwise, it can't be used with the filter. | |
260 | 8 | SecurityManager securityManager = factory.getInstance(); |
261 | 8 | if (!(securityManager instanceof WebSecurityManager)) { |
262 | 0 | String msg = "The configured security manager is not an instance of WebSecurityManager, so " + |
263 | "it can not be used with the Shiro servlet filter."; | |
264 | 0 | throw new ConfigurationException(msg); |
265 | } | |
266 | ||
267 | 8 | setSecurityManager((WebSecurityManager) securityManager); |
268 | ||
269 | 8 | return factory.getBeans(); |
270 | } | |
271 | ||
272 | protected void applyFilterChainResolver(Ini ini, Map<String, ?> defaults) { | |
273 | 8 | if (ini == null || ini.isEmpty()) { |
274 | //nothing to use to create the resolver, just return | |
275 | //(the AbstractShiroFilter allows a null resolver, in which case the original FilterChain is | |
276 | // always used). | |
277 | 2 | return; |
278 | } | |
279 | ||
280 | //only create a resolver if the 'filters' or 'urls' sections are defined: | |
281 | 6 | Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS); |
282 | 6 | Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS); |
283 | 6 | if ((urls != null && !urls.isEmpty()) || (filters != null && !filters.isEmpty())) { |
284 | //either the urls section or the filters section was defined. Go ahead and create the resolver | |
285 | //and set it: | |
286 | 6 | IniFilterChainResolverFactory filterChainResolverFactory = new IniFilterChainResolverFactory(ini, defaults); |
287 | 6 | filterChainResolverFactory.setFilterConfig(getFilterConfig()); |
288 | 6 | FilterChainResolver resolver = filterChainResolverFactory.getInstance(); |
289 | 6 | setFilterChainResolver(resolver); |
290 | } | |
291 | 6 | } |
292 | ||
293 | protected Ini convertConfigToIni(String config) { | |
294 | 2 | Ini ini = new Ini(); |
295 | 2 | ini.load(config); |
296 | 2 | return ini; |
297 | } | |
298 | ||
299 | /** | |
300 | * Returns the INI instance reflecting the specified servlet context resource path or {@code null} if no | |
301 | * resource was found. | |
302 | * | |
303 | * @param servletContextPath the servlet context resource path of the INI file to load | |
304 | * @return the INI instance reflecting the specified servlet context resource path or {@code null} if no | |
305 | * resource was found. | |
306 | * @since 1.2 | |
307 | */ | |
308 | protected Ini getServletContextIniResource(String servletContextPath) { | |
309 | 6 | String path = WebUtils.normalize(servletContextPath); |
310 | 6 | if (getServletContext() != null) { |
311 | 6 | InputStream is = getServletContext().getResourceAsStream(path); |
312 | 6 | if (is != null) { |
313 | 2 | Ini ini = new Ini(); |
314 | 2 | ini.load(is); |
315 | 2 | if (CollectionUtils.isEmpty(ini)) { |
316 | 0 | log.warn("ServletContext INI resource '" + servletContextPath + "' exists, but it did not contain " + |
317 | "any data."); | |
318 | } | |
319 | 2 | return ini; |
320 | } | |
321 | } | |
322 | 4 | return null; |
323 | } | |
324 | ||
325 | /** | |
326 | * Converts the specified file path to an {@link Ini} instance. | |
327 | * <p/> | |
328 | * If the path does not have a resource prefix as defined by {@link ResourceUtils#hasResourcePrefix(String)}, the | |
329 | * path is expected to be resolvable by the {@code ServletContext} via | |
330 | * {@link javax.servlet.ServletContext#getResourceAsStream(String)}. | |
331 | * | |
332 | * @param path the path of the INI resource to load into an INI instance. | |
333 | * @return an INI instance populated based on the given INI resource path. | |
334 | */ | |
335 | protected Ini convertPathToIni(String path) { | |
336 | ||
337 | 4 | Ini ini = new Ini(); |
338 | ||
339 | //SHIRO-178: Check for servlet context resource and not | |
340 | //only resource paths: | |
341 | 4 | if (!ResourceUtils.hasResourcePrefix(path)) { |
342 | 2 | ini = getServletContextIniResource(path); |
343 | 2 | if (ini == null) { |
344 | 2 | String msg = "There is no servlet context resource corresponding to configPath '" + path + "' If " + |
345 | "the resource is located elsewhere (not immediately resolveable in the servlet context), " + | |
346 | "specify an appropriate classpath:, url:, or file: resource prefix accordingly."; | |
347 | 2 | throw new ConfigurationException(msg); |
348 | } | |
349 | } else { | |
350 | //normal resource path - load as usual: | |
351 | 2 | ini.loadFromPath(path); |
352 | } | |
353 | ||
354 | 2 | return ini; |
355 | } | |
356 | } |