Hi all,
I made progress switching from 0.8.3 to
0.9.0 for the purposes of testing it in our web app, but ran into some issues
that held me up. My
servlet container starts OK and the Spring context starts fine, but
accessing the app brings up a "Filter
is Unavailable" error with an NPE occuring in java.lang.InheritableThreadLocal coming from net.sf.acegisecurity.context.SecurityContextHolder.setContext().
[11/7/05 15:24:43:513 EST] 5a6d5a6d WebGroup E SRVE0026E: [Servlet Error]-[Filter [Acegi Filter Chain Proxy]: filter is unavailable.]: java.lang.NullPointerException
at java.lang.Throwable.<init>(Throwable.java)
at java.lang.Throwable.<init>(Throwable.java)
at java.lang.NullPointerException.<init>(NullPointerException.java:63)
at java.lang.InheritableThreadLocal.set(InheritableThreadLocal.java:95)
at net.sf.acegisecurity.context.SecurityContextHolder.setContext(SecurityContextHolder.java:58)
at net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:207)
at net.sf.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:303)
at net.sf.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:173)
at net.sf.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:120)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:132)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:71)
at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.handleWebAppDispatch(WebAppRequestDispatcher.java:939)
at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.dispatch(WebAppRequestDispatcher.java:530)
at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.forward(WebAppRequestDispatcher.java:176)
at com.ibm.ws.webcontainer.srt.WebAppInvoker.doForward(WebAppInvoker.java:79)
at com.ibm.ws.webcontainer.srt.WebAppInvoker.handleInvocationHook(WebAppInvoker.java:201)
at com.ibm.ws.webcontainer.cache.invocation.CachedInvocation.handleInvocation(CachedInvocation.java:71)
at com.ibm.ws.webcontainer.srp.ServletRequestProcessor.dispatchByURI(ServletRequestProcessor.java:182)
at com.ibm.ws.webcontainer.oselistener.OSEListenerDispatcher.service(OSEListener.java:334)
at com.ibm.ws.webcontainer.http.HttpConnection.handleRequest(HttpConnection.java:56)
at com.ibm.ws.http.HttpConnection.readAndHandleRequest(HttpConnection.java:610)
at com.ibm.ws.http.HttpConnection.run(HttpConnection.java:431)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:593)
If I remove my (single) reference to FilterToBeanProxy from web.xml, no error is encountered ( other than /j_acegi_security_check can't be found, etc.) so it's definately happening in FilterToBeanProxy or one of its delegates (presumably HttpSessionContextIntegrationFilter from the stack trace above).
Here's what the relevant entries in my web.xml
look like:
<!--
- This filter allows Acegi to intercept authentication requests and process them
- using a Spring-defined DAO implementaion. Note that a matching *securityContext.xml
- bean entry must be present for this to work correctly. -->
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
<!-- Filter mappings for Acegi Security System for Spring -->
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Here's my securityApplicationContext.xml file. All this worked great with 0.8.3 but of course some of the classes/packages have changed . What have I missed?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context containing authentication, channel security and web URI beans.
-
- Only used by "filter" artifact.
-
- CVS $Id: securityApplicationContext.xml,v 1.12 2005/08/18 19:46:33 E099544 Exp $
-->
<beans>
<description>
Security settings for Acegi protection.
</description>
<!-- ======================== FILTER CHAIN ======================= -->
<!--
- The web.xml file has a single filter reference to this top-level bean, which
- in turn invokes a chain of sub-filters specified below. This is the recommended
- way of implementing multiple (Acegi) filters.
-->
<bean id="filterChainProxy" class="net.sf.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,securityEnforcementFilter
</value>
</property>
</bean>
<!-- ======================== AUTHENTICATION ======================= -->
<!--
- The top-level Authentication Manager is responsible for all application AUTHENTICATION
- operations. Note that it must reference one or more provider(s) defined below.
-->
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<!--
- This Authentication Provider is used by the Authentication Manager above and uses a
- referenced DAO to retrieve principal (user) details from a central store.
- Also note that a user cache defined below is used to minimize DB hits.
-->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<!-- For PRODUCTION, we look up the users against the IT Risk Standard ID database, etc. -->
<property name="authenticationDao"><ref bean="authenticationService"/></property>
<property name="userCache"><ref local="userCache"/></property>
</bean>
<!-- A user cache (backed by EHCache) is used to minimize DB hits while satisfying auth lookups -->
<bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="cache"><ref local="userCacheBackend"/></property>
</bean>
<bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager"/>
</property>
<property name="cacheName">
<value>userCache</value>
</property>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
<!-- Automatically receives AuthenticationEvent messages from DaoAuthenticationProvider -->
<bean id="loggerListener" class="net.sf.acegisecurity.event.authorization.LoggerListener"/>
<bean id="basicProcessingFilter" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property>
</bean>
<bean id="basicProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
<property name="realmName"><value>GCS PASSPort Realm</value></property>
</bean>
<bean id="httpSessionContextIntegrationFilter" class="net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter">
<property name="context"><value>net.sf.acegisecurity.context.SecurityContextImpl</value></property>
</bean>
<!-- ===================== HTTP REQUEST SECURITY ==================== -->
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
<property name="filterSecurityInterceptor"><ref local="filterInvocationInterceptor"/></property>
<property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
</bean>
<!-- Note the order that entries are placed against the objectDefinitionSource is critical.
The FilterSecurityInterceptor will work from the top of the list down to the FIRST pattern that matches the request URL.
Accordingly, you should place MOST SPECIFIC (ie a/b/c/d.*) expressions first, with LEAST SPECIFIC (ie a/.*) expressions last -->
<bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=ROLE_USER
</value>
</property>
</bean>
<bean id="authenticationProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl"><value>/login.jsp?login_error=0</value></property>
<property name="forceHttps"><value>false</value></property>
</bean>
<bean id="authenticationProcessingFilter" class="net.sf.acegisecurity.ui.webapp.SiteminderAuthenticationProcessingFilter">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="authenticationFailureUrl"><value>/login.jsp?login_error=1</value></property>
<property name="defaultTargetUrl"><value>/security.do?method=getMainMenu</value></property>
<property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
<property name="siteminderUsernameHeaderKey"><value>SM_USER</value></property>
<property name="siteminderPasswordHeaderKey"><value>SM_USER</value></property>
<property name="formUsernameParameterKey"><value>j_username</value></property>
<property name="formPasswordParameterKey"><value>j_password</value></property>
</bean>
<bean id="httpRequestAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
</list>
</property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
<!-- Our Access Decision Manager uses an affirmative based voting system defined below -->
<bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
</list>
</property>
</bean>
<!-- We use Acegi's stock Role Voter to help the Access Decision Manager defined above -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
</beans>
