| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.shiro.web.servlet; |
| |
| import org.apache.shiro.config.ConfigurationException; |
| import org.apache.shiro.config.Ini; |
| import org.apache.shiro.ini.IniFactorySupport; |
| import org.apache.shiro.lang.io.ResourceUtils; |
| import org.apache.shiro.mgt.SecurityManager; |
| import org.apache.shiro.util.CollectionUtils; |
| import org.apache.shiro.lang.util.StringUtils; |
| import org.apache.shiro.web.config.IniFilterChainResolverFactory; |
| import org.apache.shiro.web.config.WebIniSecurityManagerFactory; |
| import org.apache.shiro.web.filter.mgt.FilterChainResolver; |
| import org.apache.shiro.web.mgt.WebSecurityManager; |
| import org.apache.shiro.web.util.WebUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.InputStream; |
| import java.util.Map; |
| |
| /** |
| * <h1>Deprecated</h1> |
| * This filter has been deprecated as of Shiro 1.2 in favor of using the {@link ShiroFilter} in {@code web.xml} instead. |
| * See the {@link ShiroFilter} JavaDoc for usage. |
| * <p/> |
| * ====================== |
| * <p/> |
| * Servlet Filter that configures and enables all Shiro functions within a web application by using the |
| * <a href="http://en.wikipedia.org/wiki/INI_file">INI</a> configuration format. |
| * <p/> |
| * The actual INI configuration contents are not covered here, but instead in Shiro's |
| * <a href="http://shiro.apache.org/configuration.html">Configuration Documentation</a> and additional web-specific |
| * <a href="http://shiro.apache.org/web.html">Web Documentation</a>. |
| * <h2>Usage</h2> |
| * <h3>Default</h3> |
| * By default, the simplest filter declaration expects a {@code shiro.ini} resource to be located at |
| * {@code /WEB-INF/shiro.ini}, or, if not there, falls back to checking the root of the classpath |
| * (i.e. {@code classpath:shiro.ini}): |
| * <pre> |
| * <filter> |
| * <filter-name>ShiroFilter</filter-name> |
| * <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> |
| * </filter> |
| * </pre> |
| * <h3>Custom Path</h3> |
| * If you want the INI configuration to be somewhere other than {@code /WEB-INF/shiro.ini} or |
| * {@code classpath:shiro.ini}, you may specify an alternate location via the {@code configPath init-param}: |
| * <pre> |
| * <filter> |
| * <filter-name>ShiroFilter</filter-name> |
| * <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> |
| * <init-param> |
| * <param-name>configPath</param-name> |
| * <param-value>/WEB-INF/someFile.ini</param-value> |
| * </init-param> |
| * </filter> |
| * </pre> |
| * Unqualified (schemeless or 'non-prefixed') paths are assumed to be {@code ServletContext} resource paths, resolvable |
| * via {@link javax.servlet.ServletContext#getResourceAsStream(String) ServletContext#getResourceAsStream}. |
| * <p/> |
| * Non-ServletContext resources may be loaded from qualified locations by specifying prefixes indicating the source, |
| * e.g. {@code file:}, {@code url:}, and {@code classpath:}. See the |
| * {@link ResourceUtils#getInputStreamForPath(String)} JavaDoc for more. |
| * <h3>Inline</h3> |
| * For relatively simple environments, you can embed the INI config directly inside the filter declaration with |
| * the {@code config init-param}: |
| * <pre> |
| * <filter> |
| * <filter-name>ShiroFilter</filter-name> |
| * <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> |
| * <init-param> |
| * <param-name>config</param-name> |
| * <param-value> |
| * #INI config goes here... |
| * </param-value> |
| * </init-param> |
| * </filter> |
| * </pre> |
| * Although this is typically not recommended because any Shiro configuration changes would contribute to version control |
| * 'noise' in the web.xml file. |
| * <p/> |
| * When creating the shiro.ini configuration itself, please see Shiro's |
| * <a href="http://shiro.apache.org/configuration.html">Configuration Documentation</a> and |
| * <a href="http://shiro.apache.org/web.html">Web Documentation</a>. |
| * |
| * @see <a href="http://shiro.apache.org/configuration.html">Apache Shiro INI Configuration</a> |
| * @see <a href="http://shiro.apache.org/web.html">Apache Shiro Web Documentation</a> |
| * @since 1.0 |
| * @deprecated in 1.2 in favor of using the {@link ShiroFilter} |
| */ |
| @Deprecated |
| public class IniShiroFilter extends AbstractShiroFilter { |
| |
| public static final String CONFIG_INIT_PARAM_NAME = "config"; |
| public static final String CONFIG_PATH_INIT_PARAM_NAME = "configPath"; |
| |
| public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini"; |
| |
| private static final Logger log = LoggerFactory.getLogger(IniShiroFilter.class); |
| |
| private String config; |
| private String configPath; |
| |
| public IniShiroFilter() { |
| } |
| |
| /** |
| * Returns the actual INI configuration text to use to build the {@link SecurityManager} and |
| * {@link FilterChainResolver} used by the web application or {@code null} if the |
| * {@link #getConfigPath() configPath} should be used to load a fallback INI source. |
| * <p/> |
| * This value is {@code null} by default, but it will be automatically set to the value of the |
| * '{@code config}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet |
| * container at startup. |
| * |
| * @return the actual INI configuration text to use to build the {@link SecurityManager} and |
| * {@link FilterChainResolver} used by the web application or {@code null} if the |
| * {@link #getConfigPath() configPath} should be used to load a fallback INI source. |
| */ |
| public String getConfig() { |
| return this.config; |
| } |
| |
| /** |
| * Sets the actual INI configuration text to use to build the {@link SecurityManager} and |
| * {@link FilterChainResolver} used by the web application. If this value is {@code null}, the |
| * {@link #getConfigPath() configPath} will be checked to see if a .ini file should be loaded instead. |
| * <p/> |
| * This value is {@code null} by default, but it will be automatically set to the value of the |
| * '{@code config}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet |
| * container at startup. |
| * |
| * @param config the actual INI configuration text to use to build the {@link SecurityManager} and |
| * {@link FilterChainResolver} used by the web application. |
| */ |
| public void setConfig(String config) { |
| this.config = config; |
| } |
| |
| /** |
| * Returns the config path to be used to load a .ini file for configuration if a configuration is |
| * not specified via the {@link #getConfig() config} attribute. |
| * <p/> |
| * This value is {@code null} by default, but it will be automatically set to the value of the |
| * '{@code configPath}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet |
| * container at startup. |
| * |
| * @return the config path to be used to load a .ini file for configuration if a configuration is |
| * not specified via the {@link #getConfig() config} attribute. |
| */ |
| public String getConfigPath() { |
| return configPath; |
| } |
| |
| /** |
| * Sets the config path to be used to load a .ini file for configuration if a configuration is |
| * not specified via the {@link #getConfig() config} attribute. |
| * <p/> |
| * This value is {@code null} by default, but it will be automatically set to the value of the |
| * '{@code configPath}' {@code init-param} if it exists in the {@code FilterConfig} provided by the servlet |
| * container at startup. |
| * |
| * @param configPath the config path to be used to load a .ini file for configuration if a configuration is |
| * not specified via the {@link #getConfig() config} attribute. |
| */ |
| public void setConfigPath(String configPath) { |
| this.configPath = StringUtils.clean(configPath); |
| } |
| |
| public void init() throws Exception { |
| applyInitParams(); |
| configure(); |
| } |
| |
| protected void applyInitParams() throws Exception { |
| String config = getInitParam(CONFIG_INIT_PARAM_NAME); |
| if (config != null) { |
| setConfig(config); |
| } |
| String configPath = getInitParam(CONFIG_PATH_INIT_PARAM_NAME); |
| if (configPath != null) { |
| setConfigPath(configPath); |
| } |
| } |
| |
| protected void configure() throws Exception { |
| Ini ini = loadIniFromConfig(); |
| |
| if (CollectionUtils.isEmpty(ini)) { |
| log.info("Null or empty configuration specified via 'config' init-param. " + |
| "Checking path-based configuration."); |
| ini = loadIniFromPath(); |
| } |
| //added for SHIRO-178: |
| if (CollectionUtils.isEmpty(ini)) { |
| log.info("Null or empty configuration specified via '" + CONFIG_INIT_PARAM_NAME + "' or '" + |
| CONFIG_PATH_INIT_PARAM_NAME + "' filter parameters. Trying the default " + |
| DEFAULT_WEB_INI_RESOURCE_PATH + " file."); |
| ini = getServletContextIniResource(DEFAULT_WEB_INI_RESOURCE_PATH); |
| } |
| //although the preferred default is /WEB-INF/shiro.ini per SHIRO-178, keep this |
| //for backwards compatibility: |
| if (CollectionUtils.isEmpty(ini)) { |
| log.info("Null or empty configuration specified via '" + CONFIG_INIT_PARAM_NAME + "' or '" + |
| CONFIG_PATH_INIT_PARAM_NAME + "' filter parameters. Trying the default " + |
| IniFactorySupport.DEFAULT_INI_RESOURCE_PATH + " file."); |
| ini = IniFactorySupport.loadDefaultClassPathIni(); |
| } |
| |
| Map<String, ?> objects = applySecurityManager(ini); |
| applyFilterChainResolver(ini, objects); |
| } |
| |
| protected Ini loadIniFromConfig() { |
| Ini ini = null; |
| String config = getConfig(); |
| if (config != null) { |
| ini = convertConfigToIni(config); |
| } |
| return ini; |
| } |
| |
| protected Ini loadIniFromPath() { |
| Ini ini = null; |
| String path = getConfigPath(); |
| if (path != null) { |
| ini = convertPathToIni(path); |
| } |
| return ini; |
| } |
| |
| protected Map<String, ?> applySecurityManager(Ini ini) { |
| WebIniSecurityManagerFactory factory; |
| if (CollectionUtils.isEmpty(ini)) { |
| factory = new WebIniSecurityManagerFactory(); |
| } else { |
| factory = new WebIniSecurityManagerFactory(ini); |
| } |
| |
| // Create the security manager and check that it implements WebSecurityManager. |
| // Otherwise, it can't be used with the filter. |
| SecurityManager securityManager = factory.getInstance(); |
| if (!(securityManager instanceof WebSecurityManager)) { |
| String msg = "The configured security manager is not an instance of WebSecurityManager, so " + |
| "it can not be used with the Shiro servlet filter."; |
| throw new ConfigurationException(msg); |
| } |
| |
| setSecurityManager((WebSecurityManager) securityManager); |
| |
| return factory.getBeans(); |
| } |
| |
| protected void applyFilterChainResolver(Ini ini, Map<String, ?> defaults) { |
| if (ini == null || ini.isEmpty()) { |
| //nothing to use to create the resolver, just return |
| //(the AbstractShiroFilter allows a null resolver, in which case the original FilterChain is |
| // always used). |
| return; |
| } |
| |
| //only create a resolver if the 'filters' or 'urls' sections are defined: |
| Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS); |
| Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS); |
| if ((urls != null && !urls.isEmpty()) || (filters != null && !filters.isEmpty())) { |
| //either the urls section or the filters section was defined. Go ahead and create the resolver |
| //and set it: |
| IniFilterChainResolverFactory filterChainResolverFactory = new IniFilterChainResolverFactory(ini, defaults); |
| filterChainResolverFactory.setFilterConfig(getFilterConfig()); |
| FilterChainResolver resolver = filterChainResolverFactory.getInstance(); |
| setFilterChainResolver(resolver); |
| } |
| } |
| |
| protected Ini convertConfigToIni(String config) { |
| Ini ini = new Ini(); |
| ini.load(config); |
| return ini; |
| } |
| |
| /** |
| * Returns the INI instance reflecting the specified servlet context resource path or {@code null} if no |
| * resource was found. |
| * |
| * @param servletContextPath the servlet context resource path of the INI file to load |
| * @return the INI instance reflecting the specified servlet context resource path or {@code null} if no |
| * resource was found. |
| * @since 1.2 |
| */ |
| protected Ini getServletContextIniResource(String servletContextPath) { |
| String path = WebUtils.normalize(servletContextPath); |
| if (getServletContext() != null) { |
| InputStream is = getServletContext().getResourceAsStream(path); |
| if (is != null) { |
| Ini ini = new Ini(); |
| ini.load(is); |
| if (CollectionUtils.isEmpty(ini)) { |
| log.warn("ServletContext INI resource '" + servletContextPath + "' exists, but it did not contain " + |
| "any data."); |
| } |
| return ini; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Converts the specified file path to an {@link Ini} instance. |
| * <p/> |
| * If the path does not have a resource prefix as defined by {@link ResourceUtils#hasResourcePrefix(String)}, the |
| * path is expected to be resolvable by the {@code ServletContext} via |
| * {@link javax.servlet.ServletContext#getResourceAsStream(String)}. |
| * |
| * @param path the path of the INI resource to load into an INI instance. |
| * @return an INI instance populated based on the given INI resource path. |
| */ |
| protected Ini convertPathToIni(String path) { |
| |
| Ini ini = new Ini(); |
| |
| //SHIRO-178: Check for servlet context resource and not |
| //only resource paths: |
| if (!ResourceUtils.hasResourcePrefix(path)) { |
| ini = getServletContextIniResource(path); |
| if (ini == null) { |
| String msg = "There is no servlet context resource corresponding to configPath '" + path + "' If " + |
| "the resource is located elsewhere (not immediately resolvable in the servlet context), " + |
| "specify an appropriate classpath:, url:, or file: resource prefix accordingly."; |
| throw new ConfigurationException(msg); |
| } |
| } else { |
| //normal resource path - load as usual: |
| ini.loadFromPath(path); |
| } |
| |
| return ini; |
| } |
| } |