You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2010/01/20 23:26:29 UTC

svn commit: r901407 - in /incubator/shiro/trunk: samples/spring-hibernate/src/main/webapp/WEB-INF/ samples/spring/src/main/webapp/WEB-INF/ support/spring/src/main/java/org/apache/shiro/spring/web/ support/spring/src/test/java/org/apache/shiro/spring/we...

Author: lhazlewood
Date: Wed Jan 20 22:26:28 2010
New Revision: 901407

URL: http://svn.apache.org/viewvc?rev=901407&view=rev
Log:
SHIRO-131 - wrapped up initial implementation.  Incorporated and tested with 2 spring sample applications.

Modified:
    incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/applicationContext.xml
    incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/web.xml
    incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/applicationContext.xml
    incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/web.xml
    incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java
    incubator/shiro/trunk/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java
    incubator/shiro/trunk/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/AccessControlFilter.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authc/AuthenticationFilter.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authz/AuthorizationFilter.java

Modified: incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/applicationContext.xml
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/applicationContext.xml?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/applicationContext.xml (original)
+++ incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/applicationContext.xml Wed Jan 20 22:26:28 2010
@@ -23,10 +23,12 @@
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:util="http://www.springframework.org/schema/util"
        xmlns:context="http://www.springframework.org/schema/context"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
-       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
-       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
-       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
+       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
+       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
 
     <!-- Enable annotation configuration -->
     <context:annotation-config/>
@@ -97,8 +99,35 @@
         <property name="sessionMode" value="native"/> -->
     </bean>
 
-
     <!-- Post processor that automatically invokes init() and destroy() methods -->
     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
 
+    <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -
+         web.xml uses the DelegatingFilterProxy to access this bean.  This allows us
+         to wire things with more control as well utilize nice Spring things such as
+         PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: -->
+    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
+        <property name="securityManager" ref="securityManager"/>
+        <property name="loginUrl" value="/s/login"/>
+        <property name="successUrl" value="/s/home"/>
+        <property name="unauthorizedUrl" value="/unauthorized"/>
+        <!-- The 'filters' property is usually not necessary unless performing an override, which we
+             want to do here (make authc point to a PassthruAuthenticationFilter instead of the
+             default FormAuthenticationFilter: -->
+        <property name="filters">
+            <util:map>
+                <entry key="authc">
+                    <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>
+                </entry>
+            </util:map>
+        </property>
+        <property name="filterChainDefinitions">
+            <value>
+                /s/signup = anon
+                /s/manageUsers = perms[user:manage]
+                /s/** = authc
+            </value>
+        </property>
+    </bean>
+
 </beans>

Modified: incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/web.xml?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/web.xml (original)
+++ incubator/shiro/trunk/samples/spring-hibernate/src/main/webapp/WEB-INF/web.xml Wed Jan 20 22:26:28 2010
@@ -59,35 +59,10 @@
         <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
     </filter>
 
+    <!-- Shiro Filter is defined in the spring application context: -->
     <filter>
-        <filter-name>ShiroFilter</filter-name>
-        <filter-class>org.apache.shiro.spring.SpringShiroFilter</filter-class>
-        <init-param>
-            <param-name>config</param-name>
-            <param-value>
-
-                # The ShiroFilter configuration is very powerful and flexible, while still remaining succinct.
-                # Please read the comprehensive example, with full comments and explanations, in the JavaDoc:
-                #
-                # http://shiro.apache.org/api/org/apache/shiro/web/servlet/ShiroFilter.html
-
-                # If you'd prefer to not have this configuration in web.xml, you can create a file called shiro.ini
-                # in the root of your classpath and Shiro will automatically pick it up.
-
-                [filters]
-                # Override the authentication filter to pass thru so we can handle login logic in our controller
-                authc = org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter
-                shiro.loginUrl = /s/login
-                shiro.unauthorizedUrl = /unauthorized.jsp
-                authc.successUrl = /s/home
-
-                [urls]
-                /s/signup=anon
-                /s/manageUsers=perms[user:manage]
-                /s/**=authc
-            </param-value>
-        </init-param>
-
+        <filter-name>shiroFilter</filter-name>
+        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     </filter>
 
     <filter-mapping>
@@ -96,7 +71,7 @@
     </filter-mapping>
 
     <filter-mapping>
-        <filter-name>ShiroFilter</filter-name>
+        <filter-name>shiroFilter</filter-name>
         <url-pattern>/s/*</url-pattern>
     </filter-mapping>
 

Modified: incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/applicationContext.xml
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/applicationContext.xml?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/applicationContext.xml (original)
+++ incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/applicationContext.xml Wed Jan 20 22:26:28 2010
@@ -17,9 +17,12 @@
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
-<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
-
-<beans>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">
 
     <!-- Sample RDBMS data source that would exist in any application - not Shiro related. -->
     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
@@ -88,21 +91,30 @@
         <property name="securityManager" ref="securityManager"/>
     </bean>
 
-    <!-- Define the Shiro Filter here instead of directly in web.xml (web.xml will use the
-         DelegatingFilterProxy to reference this bean).  This allows us to wire things with more
-         control as well utilize nice Spring things such as PropertiesPlaceholderConfigurer and
-         anything else we might need: -->
-    <bean id="shiroFilter" class="org.apache.shiro.web.servlet.IniShiroFilter">
+    <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -
+         web.xml uses the DelegatingFilterProxy to access this bean.  This allows us
+         to wire things with more control as well utilize nice Spring things such as
+         PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: -->
+    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
         <property name="securityManager" ref="securityManager"/>
-        <property name="filterChainResolver">
-            <bean class="org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver">
-                <property name="filterChainManager">
-                    <bean class="org.apache.shiro.web.filter.mgt.DefaultFilterChainManager">
-
-                    </bean>
-                </property>
-
-            </bean>
+        <property name="loginUrl" value="/s/login"/>
+        <property name="successUrl" value="/s/index"/>
+        <property name="unauthorizedUrl" value="/s/unauthorized"/>
+        <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean
+             defined will be automatically acquired and available via its beanName in chain
+             definitions, but you can perform overrides or parent/child consolidated configuration
+             here if you like: -->
+        <!-- <property name="filters">
+            <util:map>
+                <entry key="aName" value-ref="someFilterPojo"/>
+            </util:map>
+        </property> -->
+        <property name="filterChainDefinitions">
+            <value>
+                /s/index = authc
+                /s/shiro.jnlp = authc, user
+                /remoting/** = authc, perms[remote:invoke]
+            </value>
         </property>
     </bean>
 

Modified: incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/web.xml?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/web.xml (original)
+++ incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/web.xml Wed Jan 20 22:26:28 2010
@@ -55,37 +55,18 @@
     <!-- ==================================================================
          Filters
          ================================================================== -->
+    <!-- Shiro Filter is defined in the spring application context: -->
     <filter>
-        <filter-name>ShiroFilter</filter-name>
-        <filter-class>org.apache.shiro.spring.SpringShiroFilter</filter-class>
-
-        <init-param>
-            <param-name>config</param-name>
-            <param-value>
-                # The ShiroFilter configuration is very powerful and flexible, while still remaining succinct.
-                # Please read the comprehensive example, with full comments and explanations, in the JavaDoc:
-                #
-                # http://shiro.apache.org/api/org/apache/shiro/web/servlet/ShiroFilter.html
-
-                [filters]
-                shiro.loginUrl = /s/login
-                authc.successUrl = /s/index
-
-                [urls]
-                /s/index=authc
-                /s/shiro.jnlp=authc,user
-                /remoting/**=authc, perms[remote:invoke]
-            </param-value>
-        </init-param>
-
+        <filter-name>shiroFilter</filter-name>
+        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     </filter>
 
     <filter-mapping>
-        <filter-name>ShiroFilter</filter-name>
+        <filter-name>shiroFilter</filter-name>
         <url-pattern>/s/*</url-pattern>
     </filter-mapping>
     <filter-mapping>
-        <filter-name>ShiroFilter</filter-name>
+        <filter-name>shiroFilter</filter-name>
         <url-pattern>/remoting/*</url-pattern>
     </filter-mapping>
 

Modified: incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java (original)
+++ incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java Wed Jan 20 22:26:28 2010
@@ -22,7 +22,11 @@
 import org.apache.shiro.mgt.SecurityManager;
 import org.apache.shiro.util.CollectionUtils;
 import org.apache.shiro.util.Nameable;
+import org.apache.shiro.util.StringUtils;
 import org.apache.shiro.web.config.IniFilterChainResolverFactory;
+import org.apache.shiro.web.filter.AccessControlFilter;
+import org.apache.shiro.web.filter.authc.AuthenticationFilter;
+import org.apache.shiro.web.filter.authz.AuthorizationFilter;
 import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
 import org.apache.shiro.web.filter.mgt.FilterChainManager;
 import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
@@ -40,9 +44,10 @@
 import java.util.Map;
 
 /**
- * {@link org.springframework.beans.factory.FactoryBean FactoryBean} to be used in Spring-based web applications.
+ * {@link org.springframework.beans.factory.FactoryBean FactoryBean} to be used in Spring-based web applications for
+ * defining the master Shiro Filter.
  * <h4>Usage</h4>
- * Declare a DelegatingFilterProxy in {@code web.xml}:
+ * Declare a DelegatingFilterProxy in {@code web.xml}, matching the filter name to the bean id:
  * <pre>
  * &lt;filter&gt;
  *   &lt;filter-name&gt;<b>shiroFilter</b>&lt;/filter-name&gt;
@@ -51,8 +56,54 @@
  * </pre>
  * Then, in your spring XML file that defines your web ApplicationContext:
  * <pre>
+ * &lt;bean id="<b>shiroFilter</b>" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&gt;
+ *    &lt;property name="securityManager" ref="securityManager"/&gt;
+ *    &lt;!-- other properties as necessary ... --&gt;
+ * &lt;/bean&gt;
+ * </pre>
+ * <h4>Filter Auto-Discovery</h4>
+ * While there is a {@link #setFilters(java.util.Map) filters} property that allows you to assign a filter beans
+ * to the 'pool' of filters available when defining {@link #setFilterChainDefinitions(String) filter chains}, it is
+ * optional.
  * <p/>
+ * This implementation is also a {@link BeanPostProcessor} and will acquire
+ * any {@link javax.servlet.Filter Filter} beans defined independently in your Spring application context.  Upon
+ * discovery, they will be automatically added to the {@link #setFilters(java.util.Map) map} keyed by the bean ID.
+ * That ID can then be used in the filter chain definitions, for example:
+ *
+ * <pre>
+ * &lt;bean id="<b>myCustomFilter</b>" class="com.class.that.implements.javax.servlet.Filter"/&gt;
+ * ...
+ * &lt;bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&gt;
+ *    ...
+ *    &lt;property name="filterChainDefinitions"&gt;
+ *        &lt;value&gt;
+ *            /some/path/** = authc, <b>myCustomFilter</b>
+ *        &lt;/value&gt;
+ *    &lt;/property&gt;
+ * &lt;/bean&gt;
  * </pre>
+ * <h4>Global Property Values</h4>
+ * Most Shiro servlet Filter implementations exist for defining custom Filter
+ * {@link #setFilterChainDefinitions(String) chain definitions}.  Most implementations subclass one of the
+ * {@link AccessControlFilter}, {@link AuthenticationFilter}, {@link AuthorizationFilter} classes to simplify things,
+ * and each of these 3 classes has configurable properties that are application-specific.
+ * <p/>
+ * A dilemma arises where, if you want to for example set the application's 'loginUrl' for any Filter, you don't want
+ * to have to manually specify that value for <em>each</em> filter instance definied.
+ * <p/>
+ * To prevent configuration duplication, this implementation provides the following properties to allow you
+ * to set relevant values in only one place:
+ * <ul>
+ * <li>{@link #setLoginUrl(String)}</li>
+ * <li>{@link #setSuccessUrl(String)}</li>
+ * <li>{@link #setUnauthorizedUrl(String)}</li>
+ * </ul>
+ *
+ * Then at startup, any values specified via these 3 properties will be applied to all configured
+ * Filter instances so you don't have to specify them individually on each filter instance.  To ensure your own custom
+ * filters benefit from this convenience, your filter implementation should subclass one of the 3 mentioned
+ * earlier.
  *
  * @author The Apache Shiro Project (shiro-dev@incubator.apache.org)
  * @since 1.0
@@ -67,6 +118,10 @@
 
     private Map<String, String> filterChainDefinitionMap; //urlPathExpression_to_comma-delimited-filter-chain-definition
 
+    private String loginUrl;
+    private String successUrl;
+    private String unauthorizedUrl;
+
     private AbstractShiroFilter instance;
 
     public ShiroFilterFactoryBean() {
@@ -74,21 +129,125 @@
         this.filterChainDefinitionMap = new LinkedHashMap<String, String>(); //order matters!
     }
 
+    /**
+     * Sets the application {@code SecurityManager} instance to be used by the constructed Shiro Filter.  This is a
+     * required property - failure to set it will throw an initialization exception.
+     *
+     * @return the application {@code SecurityManager} instance to be used by the constructed Shiro Filter.
+     */
     public SecurityManager getSecurityManager() {
         return securityManager;
     }
 
+    /**
+     * Sets the application {@code SecurityManager} instance to be used by the constructed Shiro Filter.  This is a
+     * required property - failure to set it will throw an initialization exception.
+     *
+     * @param securityManager the application {@code SecurityManager} instance to be used by the constructed Shiro Filter.
+     */
     public void setSecurityManager(SecurityManager securityManager) {
         this.securityManager = securityManager;
     }
 
     /**
+     * Returns the application's login URL to be assigned to all acquired Filters that subclass
+     * {@link AccessControlFilter} or {@code null} if no value should be assigned globally. The default value
+     * is {@code null}.
+     *
+     * @return the application's login URL to be assigned to all acquired Filters that subclass
+     *         {@link AccessControlFilter} or {@code null} if no value should be assigned globally.
+     * @see #setLoginUrl
+     */
+    public String getLoginUrl() {
+        return loginUrl;
+    }
+
+    /**
+     * Sets the application's login URL to be assigned to all acquired Filters that subclass
+     * {@link AccessControlFilter}.  This is a convenience mechanism: for all configured {@link #setFilters filters},
+     * as well for any default ones ({@code authc}, {@code user}, etc), this value will be passed on to each Filter
+     * via the {@link AccessControlFilter#setLoginUrl(String)} method<b>*</b>.  This eliminates the need to
+     * configure the 'loginUrl' property manually on each filter instance, and instead that can be configured once
+     * via this attribute.
+     * <p/>
+     * <b>*</b>If a filter already has already been explicitly configured with a value, it will
+     * <em>not</em> receive this value. Individual filter configuration overrides this global convenience property.
+     *
+     * @param loginUrl the application's login URL to apply to as a convenience to all discovered
+     *                 {@link AccessControlFilter} instances.
+     * @see AccessControlFilter#setLoginUrl(String)
+     */
+    public void setLoginUrl(String loginUrl) {
+        this.loginUrl = loginUrl;
+    }
+
+    /**
+     * Returns the application's after-login success URL to be assigned to all acquired Filters that subclass
+     * {@link AuthenticationFilter} or {@code null} if no value should be assigned globally. The default value
+     * is {@code null}.
+     *
+     * @return the application's after-login success URL to be assigned to all acquired Filters that subclass
+     *         {@link AuthenticationFilter} or {@code null} if no value should be assigned globally.
+     * @see #setSuccessUrl
+     */
+    public String getSuccessUrl() {
+        return successUrl;
+    }
+
+    /**
+     * Sets the application's after-login success URL to be assigned to all acquired Filters that subclass
+     * {@link AuthenticationFilter}.  This is a convenience mechanism: for all configured {@link #setFilters filters},
+     * as well for any default ones ({@code authc}, {@code user}, etc), this value will be passed on to each Filter
+     * via the {@link AuthenticationFilter#setSuccessUrl(String)} method<b>*</b>.  This eliminates the need to
+     * configure the 'successUrl' property manually on each filter instance, and instead that can be configured once
+     * via this attribute.
+     * <p/>
+     * <b>*</b>If a filter already has already been explicitly configured with a value, it will
+     * <em>not</em> receive this value. Individual filter configuration overrides this global convenience property.
+     *
+     * @param successUrl the application's after-login success URL to apply to as a convenience to all discovered
+     *                   {@link AccessControlFilter} instances.
+     * @see AuthenticationFilter#setSuccessUrl(String)
+     */
+    public void setSuccessUrl(String successUrl) {
+        this.successUrl = successUrl;
+    }
+
+    /**
+     * Returns the application's after-login success URL to be assigned to all acquired Filters that subclass
+     * {@link AuthenticationFilter} or {@code null} if no value should be assigned globally. The default value
+     * is {@code null}.
+     *
+     * @return the application's after-login success URL to be assigned to all acquired Filters that subclass
+     *         {@link AuthenticationFilter} or {@code null} if no value should be assigned globally.
+     * @see #setSuccessUrl
+     */
+    public String getUnauthorizedUrl() {
+        return unauthorizedUrl;
+    }
+
+    /**
+     * Sets the application's 'unauthorized' URL to be assigned to all acquired Filters that subclass
+     * {@link AuthorizationFilter}.  This is a convenience mechanism: for all configured {@link #setFilters filters},
+     * as well for any default ones ({@code roles}, {@code perms}, etc), this value will be passed on to each Filter
+     * via the {@link AuthorizationFilter#setUnauthorizedUrl(String)} method<b>*</b>.  This eliminates the need to
+     * configure the 'unauthorizedUrl' property manually on each filter instance, and instead that can be configured once
+     * via this attribute.
+     * <p/>
+     * <b>*</b>If a filter already has already been explicitly configured with a value, it will
+     * <em>not</em> receive this value. Individual filter configuration overrides this global convenience property.
+     *
+     * @param unauthorizedUrl the application's 'unauthorized' URL to apply to as a convenience to all discovered
+     *                        {@link AuthorizationFilter} instances.
+     * @see AuthorizationFilter#setUnauthorizedUrl(String)
+     */
+    public void setUnauthorizedUrl(String unauthorizedUrl) {
+        this.unauthorizedUrl = unauthorizedUrl;
+    }
+
+    /**
      * Returns the filterName-to-Filter map of filters available for reference when defining filter chain definitions.
      * All filter chain definitions will reference filters by the names in this map (i.e. the keys).
-     * <p/>
-     * Note that this map is often a merging of Shiro's default Filters ({@code authc}
-     * This map will contain all
-     * Note that most end-users will not need configure in spring the corresponding {@link #setFilters} method
      *
      * @return the filterName-to-Filter map of filters available for reference when defining filter chain definitions.
      */
@@ -121,7 +280,7 @@
     /**
      * Returns the chainName-to-chainDefinition map of chain definitions to use for creating filter chains intercepted
      * by the Shiro Filter.  Each map entry should conform to the format defined by the
-     * {@link FilterChainManager#createChain(String, String)} JavaDoc, where the map key is the chain name (i.e. URL
+     * {@link FilterChainManager#createChain(String, String)} JavaDoc, where the map key is the chain name (e.g. URL
      * path expression) and the map value is the comma-delimited string chain definition.
      *
      * @return he chainName-to-chainDefinition map of chain definitions to use for creating filter chains intercepted
@@ -134,22 +293,32 @@
     /**
      * Sets the chainName-to-chainDefinition map of chain definitions to use for creating filter chains intercepted
      * by the Shiro Filter.  Each map entry should conform to the format defined by the
-     * {@link FilterChainManager#createChain(String, String)} JavaDoc, where the map key is the chain name (i.e. URL
+     * {@link FilterChainManager#createChain(String, String)} JavaDoc, where the map key is the chain name (e.g. URL
      * path expression) and the map value is the comma-delimited string chain definition.
      *
      * @param filterChainDefinitionMap the chainName-to-chainDefinition map of chain definitions to use for creating
-     *                               filter chains intercepted by the Shiro Filter.
+     *                                 filter chains intercepted by the Shiro Filter.
      */
     public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {
         this.filterChainDefinitionMap = filterChainDefinitionMap;
     }
 
+    /**
+     * A convenience method that sets the {@link #setFilterChainDefinitionMap(java.util.Map) filterChainDefinitionMap}
+     * property by accepting a {@link java.util.Properties Properties}-compatible string (multi-line key/value pairs).
+     * Each key/value pair must conform to the format defined by the
+     * {@link FilterChainManager#createChain(String,String)} JavaDoc - each property key is an ant URL
+     * path expression and the value is the comma-delimited chain definition.
+     *
+     * @param definitions a {@link java.util.Properties Properties}-compatible string (multi-line key/value pairs)
+     *                    where each key/value pair represents a single urlPathExpression-commaDelimitedChainDefinition.
+     */
     public void setFilterChainDefinitions(String definitions) {
         Ini ini = new Ini();
         ini.load(definitions);
         //did they explicitly state a 'urls' section?  Not necessary, but just in case:
         Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
-        if ( CollectionUtils.isEmpty(section) ) {
+        if (CollectionUtils.isEmpty(section)) {
             //no urls section.  Since this _is_ a urls chain definition property, just assume the
             //default section contains only the definitions:
             section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
@@ -157,17 +326,34 @@
         setFilterChainDefinitionMap(section);
     }
 
+    /**
+     * Lazily creates and returns a {@link AbstractShiroFilter} concrete instance via the
+     * {@link #createInstance} method.
+     *
+     * @return the application's Shiro Filter instance used to filter incoming web requests.
+     * @throws Exception if there is a problem creating the {@code Filter} instance.
+     */
     public Object getObject() throws Exception {
         if (instance == null) {
-            instance = (AbstractShiroFilter)createInstance();
+            instance = createInstance();
         }
         return instance;
     }
 
+    /**
+     * Returns <code>{@link org.apache.shiro.web.servlet.AbstractShiroFilter}.class</code>
+     *
+     * @return <code>{@link org.apache.shiro.web.servlet.AbstractShiroFilter}.class</code>
+     */
     public Class getObjectType() {
         return AbstractShiroFilter.class;
     }
 
+    /**
+     * Returns {@code true} always.  There is almost always only ever 1 Shiro {@code Filter} per web application.
+     *
+     * @return {@code true} always.  There is almost always only ever 1 Shiro {@code Filter} per web application.
+     */
     public boolean isSingleton() {
         return true;
     }
@@ -175,6 +361,11 @@
     protected FilterChainManager createFilterChainManager() {
 
         DefaultFilterChainManager manager = new DefaultFilterChainManager();
+        Map<String, Filter> defaultFilters = manager.getFilters();
+        //apply global settings if necessary:
+        for (Filter filter : defaultFilters.values()) {
+            applyGlobalPropertiesIfNecessary(filter);
+        }
 
         //Apply the acquired and/or configured filters:
         Map<String, Filter> filters = getFilters();
@@ -182,6 +373,7 @@
             for (Map.Entry<String, Filter> entry : filters.entrySet()) {
                 String name = entry.getKey();
                 Filter filter = entry.getValue();
+                applyGlobalPropertiesIfNecessary(filter);
                 if (filter instanceof Nameable) {
                     ((Nameable) filter).setName(name);
                 }
@@ -207,10 +399,10 @@
     /**
      * This implementation:
      * <ol>
-     * <li>Ensures the {@link #setSecurityManager(org.apache.shiro.mgt.SecurityManager) securityManager} property
-     * has been set</li>
-     * <li>Creates a {@link FilterChainManager} instance that reflects the configured
-     * {@link #setFilters(java.util.Map) filters} and
+     * <li>Ensures the required {@link #setSecurityManager(org.apache.shiro.mgt.SecurityManager) securityManager}
+     * property has been set</li>
+     * <li>{@link #createFilterChainManager() Creates} a {@link FilterChainManager} instance that reflects the
+     * configured {@link #setFilters(java.util.Map) filters} and
      * {@link #setFilterChainDefinitionMap(java.util.Map) filter chain definitions}</li>
      * <li>Wraps the FilterChainManager with a suitable
      * {@link org.apache.shiro.web.filter.mgt.FilterChainResolver FilterChainResolver} since the Shiro Filter
@@ -222,7 +414,7 @@
      * @return a new Shiro Filter reflecting any configured filters and filter chain definitions.
      * @throws Exception if there is a problem creating the ShiroFilter instance.
      */
-    protected Object createInstance() throws Exception {
+    protected AbstractShiroFilter createInstance() throws Exception {
 
         log.debug("Creating Shiro Filter instance.");
 
@@ -251,6 +443,48 @@
         return shiroFilter;
     }
 
+    private void applyLoginUrlIfNecessary(Filter filter) {
+        String loginUrl = getLoginUrl();
+        if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter)) {
+            AccessControlFilter acFilter = (AccessControlFilter) filter;
+            //only apply the login url if they haven't explicitly configured one already:
+            String existingLoginUrl = acFilter.getLoginUrl();
+            if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) {
+                acFilter.setLoginUrl(loginUrl);
+            }
+        }
+    }
+
+    private void applySuccessUrlIfNecessary(Filter filter) {
+        String successUrl = getSuccessUrl();
+        if (StringUtils.hasText(successUrl) && (filter instanceof AuthenticationFilter)) {
+            AuthenticationFilter authcFilter = (AuthenticationFilter) filter;
+            //only apply the successUrl if they haven't explicitly configured one already:
+            String existingSuccessUrl = authcFilter.getSuccessUrl();
+            if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl)) {
+                authcFilter.setSuccessUrl(successUrl);
+            }
+        }
+    }
+
+    private void applyUnauthorizedUrlIfNecessary(Filter filter) {
+        String unauthorizedUrl = getUnauthorizedUrl();
+        if (StringUtils.hasText(unauthorizedUrl) && (filter instanceof AuthorizationFilter)) {
+            AuthorizationFilter authzFilter = (AuthorizationFilter) filter;
+            //only apply the unauthorizedUrl if they haven't explicitly configured one already:
+            String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();
+            if (existingUnauthorizedUrl == null) {
+                authzFilter.setUnauthorizedUrl(unauthorizedUrl);
+            }
+        }
+    }
+
+    private void applyGlobalPropertiesIfNecessary(Filter filter) {
+        applyLoginUrlIfNecessary(filter);
+        applySuccessUrlIfNecessary(filter);
+        applyUnauthorizedUrlIfNecessary(filter);
+    }
+
     /**
      * Inspects a bean, and if it implements the {@link Filter} interface, automatically adds that filter
      * instance to the internal {@link #setFilters(java.util.Map) filters map} that will be referenced
@@ -259,7 +493,9 @@
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
         if (bean instanceof Filter) {
             log.debug("Found filter chain candidate filter '{}'", beanName);
-            getFilters().put(beanName, (Filter) bean);
+            Filter filter = (Filter) bean;
+            applyGlobalPropertiesIfNecessary(filter);
+            getFilters().put(beanName, filter);
         } else {
             log.trace("Ignoring non-Filter bean '{}'", beanName);
         }

Modified: incubator/shiro/trunk/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java (original)
+++ incubator/shiro/trunk/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java Wed Jan 20 22:26:28 2010
@@ -18,6 +18,7 @@
  */
 package org.apache.shiro.spring.web;
 
+import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
 import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
 import org.apache.shiro.web.filter.mgt.NamedFilterList;
 import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
@@ -25,7 +26,9 @@
 import org.junit.Test;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
-import static org.junit.Assert.assertNotNull;
+import javax.servlet.Filter;
+
+import static org.junit.Assert.*;
 
 /**
  * Created by IntelliJ IDEA.
@@ -50,5 +53,10 @@
         DefaultFilterChainManager fcManager = (DefaultFilterChainManager)resolver.getFilterChainManager();
         NamedFilterList chain = fcManager.getChain("/test");
         assertNotNull(chain);
+        assertEquals(chain.size(), 2);
+        Filter[] filters = new Filter[chain.size()];
+        filters = chain.toArray(filters);
+        assertTrue(filters[0] instanceof DummyFilter);
+        assertTrue(filters[1] instanceof FormAuthenticationFilter);
     }
 }

Modified: incubator/shiro/trunk/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml (original)
+++ incubator/shiro/trunk/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml Wed Jan 20 22:26:28 2010
@@ -44,13 +44,6 @@
 
     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
         <property name="securityManager" ref="securityManager"/>
-        <!-- This property is not necessary since declared filters will be automatically acquired, but
-             you can perform overrides here if you like: -->
-        <!-- <property name="filters">
-            <util:map>
-                <entry key="testFilter" value-ref="testFilter"/>
-            </util:map>
-        </property> -->
         <property name="filterChainDefinitions">
             <value>
                 /test = testFilter, authc

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/AccessControlFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/AccessControlFilter.java?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/AccessControlFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/AccessControlFilter.java Wed Jan 20 22:26:28 2010
@@ -18,14 +18,14 @@
  */
 package org.apache.shiro.web.filter;
 
-import java.io.IOException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.subject.Subject;
 import org.apache.shiro.web.WebUtils;
 
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
 /**
  * Superclass for any filter that controls access to a resource and may redirect the user to the login page
  * if they are not authenticated.  This superclass provides the method
@@ -69,7 +69,7 @@
      *
      * @return the login URL used to authenticate a user, used when redirecting users if authentication is required.
      */
-    protected String getLoginUrl() {
+    public String getLoginUrl() {
         return loginUrl;
     }
 

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authc/AuthenticationFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authc/AuthenticationFilter.java?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authc/AuthenticationFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authc/AuthenticationFilter.java Wed Jan 20 22:26:28 2010
@@ -52,7 +52,7 @@
      *
      * @return the success url to use as the default location a user is sent after logging in.
      */
-    protected String getSuccessUrl() {
+    public String getSuccessUrl() {
         return successUrl;
     }
 

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authz/AuthorizationFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authz/AuthorizationFilter.java?rev=901407&r1=901406&r2=901407&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authz/AuthorizationFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authz/AuthorizationFilter.java Wed Jan 20 22:26:28 2010
@@ -59,7 +59,7 @@
      * @return the URL to which users should be redirected if they are denied access to an underlying path or resource,
      *         or {@code null} if a raw {@link HttpServletResponse#SC_UNAUTHORIZED} response should be issued (401 Unauthorized).
      */
-    protected String getUnauthorizedUrl() {
+    public String getUnauthorizedUrl() {
         return unauthorizedUrl;
     }