Saturday, March 8, 2008

More on How to make Acegi work on Sun Application Server 8.x?

Applying the solution mentioned in my previous post IMHO: How to make Acegi work on Sun Application Server 8.x? has been proved working quite well. Well, until I encountered the same ClassCastException again. This time it was because the access was denied. Looking into the stack trace, I found that it was because Acegi's AccessDeniedHandlerImpl forwards the SecurityContextHolderAwareRequestWrapper to show the error page.

Similar to the solution in the previous post, I creates a NullPrincipalAccessDeniedHandlerImpl, which extends Acegi's AccessDeniedHandlerImpl but wrap the HttpServletRequest with the NullPrincipalHttpServletRequestWrapper.

Following is the source code of NullPrincipalAccessDeniedHandlerImpl:

package au.net.ozgwei.util.spring.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.ui.AccessDeniedHandlerImpl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import au.net.ozgwei.util.httpservlet.NullPrincipalHttpServletRequestWrapper;

/**
* An Acegi AccessDeniedHandler implementation designed specific to get around
* the bug in Sun Application Server 8.x where a custom security framework's
* implementation of Principal is casted to Sun Application Server's own
* implementation.
*
* @author Alex
* @version 1.0
*/
public class NullPrincipalAccessDeniedHandlerImpl extends
AccessDeniedHandlerImpl {

@SuppressWarnings("unused")
private static final Log log =
LogFactory.getTrace(
NullPrincipalAccessDeniedHandlerImpl.class);

/**
* Default no-arg constructor.
*/
public NullPrincipalAccessDeniedHandlerImpl() {
super();
}

@Override
public void handle(ServletRequest aRequest, ServletResponse aResponse,
AccessDeniedException aAccessDeniedException) throws IOException,
ServletException {

super.handle(new NullPrincipalHttpServletRequestWrapper(
(HttpServletRequest)aRequest), aResponse, aAccessDeniedException);
}

}

Of course, the Spring application context must be changed to replace the original AccessDeniedHandler implementation with this in the definition of the exceptionTranslationFilter bean:
<bean id="exceptionTranslationFilter"
class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<ref local="authenticationProcessingFilterEntryPoint"/>
</property>

<property name="accessDeniedHandler">
<bean class="au.com.cardlink.common.util.spring.security.NullPrincipalAccessDeniedHandlerImpl">
<property name="errorPage" value="/faces/ForbiddenAccess.jsp"/>
</bean>
</property>

</bean>

Now it works even if user's access to a protected URL is denied by Acegi.

No comments: