
Originally Posted by
warer
Hi
I tried the dispatcher suggestion from above and it work great on my error page.
Unfortunetly now it dosen't work on my other normal pages.
Code:
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
<!-- <dispatcher>FORWARD</dispatcher>-->
<!-- <dispatcher>INCLUDE</dispatcher>-->
<!-- <dispatcher>ERROR</dispatcher>-->
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
With request on, it works on normal pages.
with error on and the other two without request it works on error pages.
with all on it works on normal pages but not error pages.
Any ideas?
According to the servlet specification, a single dispatcher element with value REQUEST is equivalent to having none, so the correct configuration is
Code:
<dispatcher>ERROR</dispatcher>
<dispatcher>REQUEST</dispatcher>
I believe the reason it does not work is that the HttpSessionContextIntegrationFilter is not designed to work with error pages, because it is designed to be applied only one per request. I have not got around to file a Jira issue for this yet, but I will.
Lets take the simple example that you have set up an error page config for handling authrorization failures, like
Code:
<error-page>
<error-code>403</error-code>
<location>/unauthorized.jsp</location>
</error-page>
If a user lacks a required role, ExceptionTranslationFilter by default issues a sendError on the response. When the request processing returns up the filter chain, it eventually reaches the HttpSessionContextIntegrationFilter and it executes
Code:
// Remove SecurityContextHolder contents
SecurityContextHolder.clearContext();
When the container finds out that it should generate an error page, it is filtered though acegi (because of the <dispatcher>ERROR</dispatcher> element). When the HttpSessionContextIntegrationFilter is invoked for the second time on the same request, it just passes control down the filter chain without setting the proper security context. The code snippet below from HttpSessionContextIntegrationFilter explains the behaviour
Code:
if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {
// ensure that filter is only applied once per request
chain.doFilter(request, response);
} else {
if (request != null) {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
}
<normal processing of session context integration>
I would suggest that the attribute is set to null when the context is cleared, like
Code:
// Remove SecurityContextHolder contents
SecurityContextHolder.clearContext();
request.setAttribute(FILTER_APPLIED, null);
But I really do not know the ramifications of this, and the Acegi team may know a better solution.
A safe workaournd would be to write a simple filter
Code:
public class RemoveFilterAppliedFilter implements Filter {
public void init( FilterConfig filterConfig ) throws ServletException {}
public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain ) throws IOException, ServletException {
servletRequest.setAttribute( "__acegi_session_integration_filter_applied", null );
filterChain.doFilter( servletRequest, servletResponse );
}
public void destroy() {}
}
Then in web.xml, set up the filter
Code:
<filter>
<filter-name>ErrorPageFilter</filter-name>
<filter-class>RemoveFilterAppliedFilter</filter-class>
</filter>
and place if BEFORE acegi filter (also in web.xml)
Code:
<filter-mapping>
<filter-name>ErrorPageFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>AcegiFilterChainProxy</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Cheers,
Rolf Arne