Coverage Report - org.apache.shiro.web.servlet.IniShiroFilter
 
Classes in this File Line Coverage Branch Coverage Complexity
IniShiroFilter
96%
79/82
75%
30/40
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  
  * &lt;filter&gt;
 59  
  *     &lt;filter-name&gt;ShiroFilter&lt;/filter-name&gt;
 60  
  *     &lt;filter-class&gt;org.apache.shiro.web.servlet.IniShiroFilter&lt;/filter-class&gt;
 61  
  * &lt;/filter&gt;
 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  
  * &lt;filter&gt;
 68  
  *     &lt;filter-name&gt;ShiroFilter&lt;/filter-name&gt;
 69  
  *     &lt;filter-class&gt;org.apache.shiro.web.servlet.IniShiroFilter&lt;/filter-class&gt;
 70  
  *     &lt;init-param&gt;
 71  
  *         &lt;param-name&gt;configPath&lt;/param-name&gt;
 72  
  *         &lt;param-value&gt;/WEB-INF/someFile.ini&lt;/param-value&gt;
 73  
  *     &lt;/init-param&gt;
 74  
  * &lt;/filter&gt;
 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  
  * &lt;filter&gt;
 87  
  *     &lt;filter-name&gt;ShiroFilter&lt;/filter-name&gt;
 88  
  *     &lt;filter-class&gt;org.apache.shiro.web.servlet.IniShiroFilter&lt;/filter-class&gt;
 89  
  *     &lt;init-param&gt;
 90  
  *         &lt;param-name&gt;config&lt;/param-name&gt;
 91  
  *         &lt;param-value&gt;
 92  
  *             #INI config goes here...
 93  
  *      &lt;/param-value&gt;
 94  
  *     &lt;/init-param&gt;
 95  
  * &lt;/filter&gt;
 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  
 }