All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.shiro.web.env.EnvironmentLoader Maven / Gradle / Ivy

There is a newer version: 2.0.2
Show newest version
/*
 * 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.env;

import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.config.ResourceConfigurable;
import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.util.LifecycleUtils;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.util.UnknownClassException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;


/**
 * An {@code EnvironmentLoader} is responsible for loading a web application's Shiro {@link WebEnvironment}
 * (which includes the web app's {@link org.apache.shiro.web.mgt.WebSecurityManager WebSecurityManager}) into the
 * {@code ServletContext} at application startup.
 * 

* In Shiro 1.1 and earlier, the Shiro ServletFilter was responsible for creating the {@code WebSecurityManager} and * any additional objects (security filters, etc). However, any component not filtered by the Shiro Filter (such * as other context listeners) was not able to easily acquire the these objects to perform security operations. *

* Due to this, in Shiro 1.2 and later, this {@code EnvironmentLoader} (or more likely, the * {@link EnvironmentLoaderListener} subclass) is the preferred mechanism to initialize * a Shiro environment. The Shiro Filter, while still required for request filtering, will not perform this * initialization at startup if the {@code EnvironmentLoader} (or listener) runs first. *

Usage

* This implementation will look for two servlet context {@code context-param}s in {@code web.xml}: * {@code shiroEnvironmentClass} and {@code shiroConfigLocations} that customize how the {@code WebEnvironment} instance * will be initialized. *

shiroEnvironmentClass

* The {@code shiroEnvironmentClass} {@code context-param}, if it exists, allows you to specify the * fully-qualified implementation class name of the {@link WebEnvironment} to instantiate. For example: *
 * <context-param>
 *     <param-name>shiroEnvironmentClass</param-name>
 *     <param-value>com.foo.bar.shiro.MyWebEnvironment</param-value>
 * </context-param>
 * 
* If not specified, the default value is the {@link IniWebEnvironment} class, which assumes Shiro's default * INI configuration format *

shiroConfigLocations

* The {@code shiroConfigLocations} {@code context-param}, if it exists, allows you to specify the config location(s) * (resource path(s)) that will be relayed to the instantiated {@link WebEnvironment}. For example: *
 * <context-param>
 *     <param-name>shiroConfigLocations</param-name>
 *     <param-value>/WEB-INF/someLocation/shiro.ini</param-value>
 * </context-param>
 * 
* The {@code WebEnvironment} implementation must implement the {@link ResourceConfigurable} interface if it is to * acquire the {@code shiroConfigLocations} value. *

* If this {@code context-param} is not specified, the {@code WebEnvironment} instance determines default resource * lookup behavior. For example, the {@link IniWebEnvironment} will check the following two locations for INI config * by default (in order): *

    *
  1. /WEB-INF/shiro.ini
  2. *
  3. classpath:shiro.ini
  4. *
*

Web Security Enforcement

* Using this loader will only initialize Shiro's environment in a web application - it will not filter web requests or * perform web-specific security operations. To do this, you must ensure that you have also configured the * {@link org.apache.shiro.web.servlet.ShiroFilter ShiroFilter} in {@code web.xml}. *

* Finally, it should be noted that this implementation was based on ideas in Spring 3's * {@code org.springframework.web.context.ContextLoader} implementation - no need to reinvent the wheel for this common * behavior. * * @see EnvironmentLoaderListener * @see org.apache.shiro.web.servlet.ShiroFilter ShiroFilter * @since 1.2 */ public class EnvironmentLoader { /** * Servlet Context config param for specifying the {@link WebEnvironment} implementation class to use: * {@code shiroEnvironmentClass} */ public static final String ENVIRONMENT_CLASS_PARAM = "shiroEnvironmentClass"; /** * Servlet Context config param for the resource path to use for configuring the {@link WebEnvironment} instance: * {@code shiroConfigLocations} */ public static final String CONFIG_LOCATIONS_PARAM = "shiroConfigLocations"; public static final String ENVIRONMENT_ATTRIBUTE_KEY = EnvironmentLoader.class.getName() + ".ENVIRONMENT_ATTRIBUTE_KEY"; private static final Logger log = LoggerFactory.getLogger(EnvironmentLoader.class); /** * Initializes Shiro's {@link WebEnvironment} instance for the specified {@code ServletContext} based on the * {@link #CONFIG_LOCATIONS_PARAM} value. * * @param servletContext current servlet context * @return the new Shiro {@code WebEnvironment} instance. * @throws IllegalStateException if an existing WebEnvironment has already been initialized and associated with * the specified {@code ServletContext}. */ public WebEnvironment initEnvironment(ServletContext servletContext) throws IllegalStateException { if (servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY) != null) { String msg = "There is already a Shiro environment associated with the current ServletContext. " + "Check if you have multiple EnvironmentLoader* definitions in your web.xml!"; throw new IllegalStateException(msg); } servletContext.log("Initializing Shiro environment"); log.info("Starting Shiro environment initialization."); long startTime = System.currentTimeMillis(); try { WebEnvironment environment = createEnvironment(servletContext); servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY,environment); log.debug("Published WebEnvironment as ServletContext attribute with name [{}]", ENVIRONMENT_ATTRIBUTE_KEY); if (log.isInfoEnabled()) { long elapsed = System.currentTimeMillis() - startTime; log.info("Shiro environment initialized in {} ms.", elapsed); } return environment; } catch (RuntimeException ex) { log.error("Shiro environment initialization failed", ex); servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, ex); throw ex; } catch (Error err) { log.error("Shiro environment initialization failed", err); servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, err); throw err; } } /** * Return the WebEnvironment implementation class to use, either the default * {@link IniWebEnvironment} or a custom class if specified. * * @param servletContext current servlet context * @return the WebEnvironment implementation class to use * @see #ENVIRONMENT_CLASS_PARAM * @see IniWebEnvironment * @see #determineWebEnvironment(ServletContext) * @see #getDefaultWebEnvironmentClass() * @deprecated This method is not longer used by Shiro, and will be removed in future versions, * use {@link #determineWebEnvironment(ServletContext)} or {@link #determineWebEnvironment(ServletContext)} */ @Deprecated protected Class determineWebEnvironmentClass(ServletContext servletContext) { Class webEnvironmentClass = webEnvironmentClassFromServletContext(servletContext); if( webEnvironmentClass != null) { return webEnvironmentClass; } else { return getDefaultWebEnvironmentClass(); } } private Class webEnvironmentClassFromServletContext(ServletContext servletContext) { Class webEnvironmentClass = null; String className = servletContext.getInitParameter(ENVIRONMENT_CLASS_PARAM); if (className != null) { try { webEnvironmentClass = ClassUtils.forName(className); } catch (UnknownClassException ex) { throw new ConfigurationException( "Failed to load custom WebEnvironment class [" + className + "]", ex); } } return webEnvironmentClass; } private WebEnvironment webEnvironmentFromServiceLoader() { WebEnvironment webEnvironment = null; // try to load WebEnvironment as a service ServiceLoader serviceLoader = ServiceLoader.load(WebEnvironment.class); Iterator iterator = serviceLoader.iterator(); // Use the first one if (iterator.hasNext()) { webEnvironment = iterator.next(); } // if there are others, throw an error if (iterator.hasNext()) { List allWebEnvironments = new ArrayList(); allWebEnvironments.add(webEnvironment.getClass().getName()); while (iterator.hasNext()) { allWebEnvironments.add(iterator.next().getClass().getName()); } throw new ConfigurationException("ServiceLoader for class [" + WebEnvironment.class + "] returned more then one " + "result. ServiceLoader must return zero or exactly one result for this class. Select one using the " + "servlet init parameter '"+ ENVIRONMENT_CLASS_PARAM +"'. Found: " + allWebEnvironments); } return webEnvironment; } /** * Returns the default WebEnvironment class, which is unless overridden: {@link IniWebEnvironment}. * @return the default WebEnvironment class. */ protected Class getDefaultWebEnvironmentClass() { return IniWebEnvironment.class; } /** * Return the WebEnvironment implementation class to use, based on the order of: *

    *
  • A custom WebEnvironment class - specified in the {@code servletContext} {@link #ENVIRONMENT_ATTRIBUTE_KEY} property
  • *
  • {@code ServiceLoader.load(WebEnvironment.class)} - (if more then one instance is found a {@link ConfigurationException} will be thrown
  • *
  • A call to {@link #getDefaultWebEnvironmentClass()} (default: {@link IniWebEnvironment})
  • *
* * @param servletContext current servlet context * @return the WebEnvironment implementation class to use * @see #ENVIRONMENT_CLASS_PARAM * @param servletContext the {@code servletContext} to query the {@code ENVIRONMENT_ATTRIBUTE_KEY} property from * @return the {@code WebEnvironment} to be used */ protected WebEnvironment determineWebEnvironment(ServletContext servletContext) { Class webEnvironmentClass = webEnvironmentClassFromServletContext(servletContext); WebEnvironment webEnvironment = null; // try service loader next if (webEnvironmentClass == null) { webEnvironment = webEnvironmentFromServiceLoader(); } // if webEnvironment is not set, and ENVIRONMENT_CLASS_PARAM prop was not set, use the default if (webEnvironmentClass == null && webEnvironment == null) { webEnvironmentClass = getDefaultWebEnvironmentClass(); } // at this point, we anything is set for the webEnvironmentClass, load it. if (webEnvironmentClass != null) { webEnvironment = (WebEnvironment) ClassUtils.newInstance(webEnvironmentClass); } return webEnvironment; } /** * Instantiates a {@link WebEnvironment} based on the specified ServletContext. *

* This implementation {@link #determineWebEnvironmentClass(javax.servlet.ServletContext) determines} a * {@link WebEnvironment} implementation class to use. That class is instantiated, configured, and returned. *

* This allows custom {@code WebEnvironment} implementations to be specified via a ServletContext init-param if * desired. If not specified, the default {@link IniWebEnvironment} implementation will be used. * * @param sc current servlet context * @return the constructed Shiro WebEnvironment instance * @see MutableWebEnvironment * @see ResourceConfigurable */ protected WebEnvironment createEnvironment(ServletContext sc) { WebEnvironment webEnvironment = determineWebEnvironment(sc); if (!MutableWebEnvironment.class.isInstance(webEnvironment)) { throw new ConfigurationException("Custom WebEnvironment class [" + webEnvironment.getClass().getName() + "] is not of required type [" + MutableWebEnvironment.class.getName() + "]"); } String configLocations = sc.getInitParameter(CONFIG_LOCATIONS_PARAM); boolean configSpecified = StringUtils.hasText(configLocations); if (configSpecified && !(ResourceConfigurable.class.isInstance(webEnvironment))) { String msg = "WebEnvironment class [" + webEnvironment.getClass().getName() + "] does not implement the " + ResourceConfigurable.class.getName() + "interface. This is required to accept any " + "configured " + CONFIG_LOCATIONS_PARAM + "value(s)."; throw new ConfigurationException(msg); } MutableWebEnvironment environment = (MutableWebEnvironment) webEnvironment; environment.setServletContext(sc); if (configSpecified && (environment instanceof ResourceConfigurable)) { ((ResourceConfigurable) environment).setConfigLocations(configLocations); } customizeEnvironment(environment); LifecycleUtils.init(environment); return environment; } /** * Any additional customization of the Environment can be by overriding this method. For example setup shared * resources, etc. By default this method does nothing. * @param environment */ protected void customizeEnvironment(WebEnvironment environment) { } /** * Destroys the {@link WebEnvironment} for the given servlet context. * * @param servletContext the ServletContext attributed to the WebSecurityManager */ public void destroyEnvironment(ServletContext servletContext) { servletContext.log("Cleaning up Shiro Environment"); try { Object environment = servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY); if (environment instanceof WebEnvironment) { finalizeEnvironment((WebEnvironment) environment); } LifecycleUtils.destroy(environment); } finally { servletContext.removeAttribute(ENVIRONMENT_ATTRIBUTE_KEY); } } /** * Any additional cleanup of the Environment can be done by overriding this method. For example clean up shared * resources, etc. By default this method does nothing. * @param environment * @since 1.3 */ protected void finalizeEnvironment(WebEnvironment environment) { } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy