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>
* <filter>
* <filter-name><b>shiroFilter</b></filter-name>
@@ -51,8 +56,54 @@
* </pre>
* Then, in your spring XML file that defines your web ApplicationContext:
* <pre>
+ * <bean id="<b>shiroFilter</b>" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
+ * <property name="securityManager" ref="securityManager"/>
+ * <!-- other properties as necessary ... -->
+ * </bean>
+ * </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>
+ * <bean id="<b>myCustomFilter</b>" class="com.class.that.implements.javax.servlet.Filter"/>
+ * ...
+ * <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
+ * ...
+ * <property name="filterChainDefinitions">
+ * <value>
+ * /some/path/** = authc, <b>myCustomFilter</b>
+ * </value>
+ * </property>
+ * </bean>
* </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;
}