I've got a strange problem with redirecting from a Controller implementing class to a SimpleFormController by returning the name in the returned ModelAndView object. The first time... ACEGI filters the request, sees no security, and sends to the login page. After logging in, they are sent to the SecTestController which implements Controller and return a new ModelAndView which corresponds to a RedirectView. This name is then resolved and picked up by the xxx-servlet.xml and sends the request to a SimpleFormController which doesn't really do much. I have dummied down the majority of the code to make it do as little as possible and still demonstrate the problem.

I just find it really odd that the problem only exhibits itself after the login occurs. Once you log in, if you go back to the main page and go through the scenario, it will just hang instead of the filter figuring out that the user is already logged in and continuing along the chain as expected. If I am doing something wrong here let me know, and if it's a bug (i've looked but haven't found anything regarding it), please let me know.

Code follows:

web.xml
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app PUBLIC
	"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
	"http&#58;//java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

	<display-name>Sec Test</display-name>

	<description>
		Simple app to test the authentication system.
	</description>

	<!--
		- Key of the system property that should specify the root directory of this
		- web app. Applied by WebAppRootListener or Log4jConfigListener.
	-->
	<context-param>
		<param-name>webAppRootKey</param-name>
		<param-value>sectest.root</param-value>
	</context-param>

	<!--
		- Location of the Log4J config file, for initialization and refresh checks.
		- Applied by Log4jConfigListener.
	-->


	<!--
		- Location of the XML file that defines the root application context.
		- Applied by ContextLoaderServlet.		
	-->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
	</context-param>

	<!-- Acegi Filters -->

	<filter>
		<filter-name>Acegi Channel Processing Filter</filter-name>
		<filter-class>
			net.sf.acegisecurity.util.FilterToBeanProxy
		</filter-class>
		<init-param>
			<param-name>targetClass</param-name>
			<param-value>
				net.sf.acegisecurity.securechannel.ChannelProcessingFilter
			</param-value>
		</init-param>
	</filter>

	<filter>
		<filter-name>Acegi CAS Processing Filter</filter-name>
		<filter-class>
			net.sf.acegisecurity.util.FilterToBeanProxy
		</filter-class>
		<init-param>
			<param-name>targetClass</param-name>
			<param-value>
				net.sf.acegisecurity.ui.cas.CasProcessingFilter
			</param-value>
		</init-param>
	</filter>

	<filter>
		<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
		<filter-class>
			net.sf.acegisecurity.util.FilterToBeanProxy
		</filter-class>
		<init-param>
			<param-name>targetClass</param-name>
			<param-value>
				net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter
			</param-value>
		</init-param>
	</filter>

	<!-- Obtains Authentication from HttpSession attribute, puts it into
		ContextHolder for request duration, proceeds with request, then
		copies Authentication from ContextHolder back into HttpSession -->
	<filter>
		<filter-name>
			Acegi Security System for Spring HttpSession Integration
			Filter
		</filter-name>
		<filter-class>
			net.sf.acegisecurity.util.FilterToBeanProxy
		</filter-class>
		<init-param>
			<param-name>targetClass</param-name>
			<param-value>
				net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter
			</param-value>
		</init-param>
	</filter>

	<filter>
		<filter-name>Acegi HTTP Request Security Filter</filter-name>
		<filter-class>
			net.sf.acegisecurity.util.FilterToBeanProxy
		</filter-class>
		<init-param>
			<param-name>targetClass</param-name>
			<param-value>
				net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter
			</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>Acegi Channel Processing Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter-mapping>
		<filter-name>Acegi CAS Processing Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter-mapping>
		<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter-mapping>
		<filter-name>
			Acegi Security System for Spring HttpSession Integration
			Filter
		</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter-mapping>
		<filter-name>Acegi HTTP Request Security Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>



	<!-- Uncomment for JBoss -->


	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<!--
		- Loads the root application context of this web app at startup,
		- by default from "/WEB-INF/applicationContext.xml".
		- Note that it is preferable to use ContextLoaderListener in a servlet container
		- that follows the Servlet 2.4 initialization order &#40;most Servlet 2.3 containers do&#41;.
		-
		- Use WebApplicationContextUtils.getWebApplicationContext&#40;servletContext&#41;
		- to access it anywhere in the web application, outside of the framework.
		-
		- The root context is the parent of all servlet-specific contexts.
		- This means that its beans are automatically available in these child contexts,
		- both for getBean&#40;name&#41; calls and &#40;external&#41; bean references.
	-->
	<servlet>
		<servlet-name>context</servlet-name>
		<servlet-class>
			org.springframework.web.context.ContextLoaderServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!--
		- Spring web MVC servlet that dispatches requests to registered handlers.
		- Has its own application context, by default defined in "&#123;servlet-name&#125;-servlet.xml",
		- i.e. "locknload-servlet.xml" in this case.
	-->
	<servlet>
		<servlet-name>sectest</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>2</load-on-startup>
	</servlet>

	<!--
		- Dispatcher servlet mapping for the main web user interface.
	-->
	<servlet-mapping>
		<servlet-name>sectest</servlet-name>
		<url-pattern>*.htm</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

</web-app>
applicationContext.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">

<!--
  - Application context definition for LockNLoad's business layer.
	- Contains bean references to the transaction manager and to the DAOs in
	- dataAccessContext-local.xml &#40;see web.xml's "contextConfigLocation"&#41;.
	-->
<beans>
   
    <!-- ========================= GENERAL DEFINITIONS ========================= -->

	
	
	<!-- ========================= BUSINESS OBJECT DEFINITIONS ======================== -->

	<!-- AOP advice used to send confirmation email after ticket has been submitted -->
	
	<!-- a parent bean definition which is a 'template' or base definition for
	     transaction proxies. It is set as lazy-init, since it is never
		 supposed to be instantiated itself. -->
	<bean id="baseTxProxy" lazy-init="true"
	      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager"><ref bean="myTransactionManager"/></property>
		<property name="transactionAttributes">
			<props>
				<prop key="*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
	
	<!-- =================== SECURITY SYSTEM DEFINITIONS ================== -->
	
	<!-- RunAsManager -->
	<bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl">
     	<property name="key"><value>my_run_as_password</value></property>
 	</bean>

	<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHENTICATION DEFINITIONS ~~~~~~~~~~~~~~~~~~ -->
	
 	<bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider">
     	<property name="key"><value>my_run_as_password</value></property>
 	</bean>

	<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
		<property name="providers">
		  <list>
		    <ref local="runAsAuthenticationProvider"/>
		    <ref local="casAuthenticationProvider"/>
		  </list>
		</property>
	</bean>

	<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
  		<property name="userMap">
			<value>
				jwinans=PASSWORD_NOT_USED,ROLE_SUPPORT
				tbrown=PASSWORD_NOT_USED,ROLE_MANAGER
				jonw=PASSWORD_NOT_USED,ROLE_CSR
			</value>
		</property>
	</bean>
	
	<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>SecTest Realm</value></property>
	</bean>

	<bean id="httpSessionIntegrationFilter" class="net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter"/>

	<bean id="casAuthenticationProvider" class="net.sf.acegisecurity.providers.cas.CasAuthenticationProvider">
		<property name="casAuthoritiesPopulator"><ref local="casAuthoritiesPopulator"/></property>
		<property name="casProxyDecider"><ref local="casProxyDecider"/></property>
		<property name="ticketValidator"><ref local="casProxyTicketValidator"/></property>
		<property name="statelessTicketCache"><ref local="statelessTicketCache"/></property>
		<property name="key"><value>my_password_for_this_auth_provider_only</value></property>
	</bean>

	<bean id="casProxyTicketValidator" class="net.sf.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator">
		<property name="casValidate"><value>https&#58;//localhost&#58;8443/cas/proxyValidate</value></property>
		<!-- <property name="proxyCallbackUrl"><value>https&#58;//localhost&#58;8443/locknload/casProxy/receptor</value></property> -->
		<property name="serviceProperties"><ref local="serviceProperties"/></property>
        <property name="trustStore"><value>C&#58;/java/lib/security/cacerts</value></property>
	</bean>

	<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
    
   <bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
      <property name="cacheManager">
         <ref local="cacheManager"/>
      </property>
      <property name="cacheName">
         <value>statelessTicketCache</value>
      </property>
   </bean>
	<bean id="statelessTicketCache" class="net.sf.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache">
		<property name="cache"><ref local="userCacheBackend"/></property>
	</bean>

	<bean id="casAuthoritiesPopulator" class="net.sf.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator">
		<property name="authenticationDao"><ref local="inMemoryDaoImpl"/></property>
	</bean>

	<bean id="casProxyDecider" class="net.sf.acegisecurity.providers.cas.proxy.RejectProxyTickets">
	</bean>

	<bean id="serviceProperties" class="net.sf.acegisecurity.ui.cas.ServiceProperties">
		<property name="service"><value>https&#58;//localhost&#58;8443/sectest/j_acegi_cas_security_check</value></property>
		<property name="sendRenew"><value>false</value></property>
	</bean>
	
	<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ -->

	<!-- An access decision voter that reads ROLE_* configuaration settings -->
	<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
	
	
	<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
	
	<bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter">
		<property name="channelDecisionManager"><ref local="channelDecisionManager"/></property>
 		<property name="filterInvocationDefinitionSource">
			<value>
			    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
				\A/secure/.*\Z=REQUIRES_SECURE_CHANNEL
				\A/j_acegi_cas_security_check.*\Z=REQUIRES_SECURE_CHANNEL	
				\A.*\Z=REQUIRES_INSECURE_CHANNEL
			</value>
		</property>
	</bean>

	<bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl">
	    <property name="channelProcessors">
      		<list>
 	        	<ref local="secureChannelProcessor"/>
        		<ref local="insecureChannelProcessor"/>
     		</list>
	    </property>
	</bean>

	<bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/>
	<bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/>

	<!-- ===================== HTTP REQUEST SECURITY ==================== -->

	<bean id="casProcessingFilter" class="net.sf.acegisecurity.ui.cas.CasProcessingFilter">
		<property name="authenticationManager"><ref local="authenticationManager"/></property>
		<property name="authenticationFailureUrl"><value>/casfailed.jsp</value></property>
		<property name="defaultTargetUrl"><value>/</value></property>
		<property name="filterProcessesUrl"><value>/j_acegi_cas_security_check</value></property>
	</bean>

	<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
		<property name="filterSecurityInterceptor"><ref local="filterInvocationInterceptor"/></property>
		<property name="authenticationEntryPoint"><ref local="casProcessingFilterEntryPoint"/></property>
	</bean>

	<bean id="casProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.cas.CasProcessingFilterEntryPoint">
		<property name="loginUrl"><value>https&#58;//localhost&#58;8443/cas/login</value></property>
		<property name="serviceProperties"><ref local="serviceProperties"/></property>
	</bean>

	<bean id="httpRequestAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
   		<property name="allowIfAllAbstainDecisions"><value>false</value></property>
		<property name="decisionVoters">
		  <list>
		    <ref local="roleVoter"/>
		  </list>
		</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 &#40;ie a/b/c/d.*&#41; expressions first, with LEAST SPECIFIC &#40;ie a/.*&#41; expressions last -->
	<bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
    	<property name="authenticationManager"><ref local="authenticationManager"/></property>
    	<property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
    	<property name="runAsManager"><ref local="runAsManager"/></property>
 		<property name="objectDefinitionSource">
			<value>
			    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
				\A/secure/support/.*\Z=ROLE_SUPPORT
				\A/secure/manage/.*\Z=ROLE_SUPPORT,ROLE_MANAGER
				\A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_CSR,ROLE_SUPPORT,ROLE_MANAGER
			</value>
		</property>
	</bean>
	
	<!-- BASIC Regular Expression Syntax &#40;for beginners&#41;&#58;
	     
	     \A means the start of the string &#40;ie the beginning of the URL&#41;
	     \Z means the end of the string &#40;ie the end of the URL&#41;
	     .  means any single character
	     *  means null or any number of repetitions of the last expression &#40;so .* means zero or more characters&#41;
	     
	     Some examples&#58;
	     
	     Expression&#58;   \A/my/directory/.*\Z
	     Would match&#58;    /my/directory/
	                     /my/directory/hello.html
	     
	     Expression&#58;   \A/.*\Z
	     Would match&#58;    /hello.html
	                     /
	     
	     Expression&#58;   \A/.*/secret.html\Z
	     Would match&#58;    /some/directory/secret.html
	                     /another/secret.html
	     Not match&#58;      /anothersecret.html &#40;missing required /&#41;
	-->
	
	
</beans>
sectest-servlet.xml
Code:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">


<beans>
	
	<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
		<property name="basename"><value>views</value></property>
	</bean>
	
	
	<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/secure/secTest.htm">secTestController</prop>
				<prop key="/secure/test.htm">testFormController</prop>			
			</props>
		</property>
	</bean>

 	
 	<!--  Just an extended Controller which makes the decision on where to forward / redirect -->
	<bean id="secTestController" class="tut.sectest.SecTestController">
		<property name="testView"><value>testFormRedirect</value></property>
	</bean>
	
	<!--  An extended SimpleFormController which shows a simple message -->
	<bean id="testFormController" class="tut.sectest.TestFormController">
		<property name="formView"><value>testForm</value></property>
		<property name="successView"><value>testFormRedirect</value></property>
		<property name="msg"><value>Hello, I work now.</value></property>
		<property name="commandName"><value>message</value></property>
		<property name="commandClass"><value>java.lang.String</value></property>
		
	</bean>

	
</beans>
views.properties
Code:
testFormRedirect.class=org.springframework.web.servlet.view.RedirectView
testFormRedirect.url=/sectest/secure/test.htm

testForm.class=org.springframework.web.servlet.view.JstlView
testForm.url=/WEB-INF/secure/test.jsp
index.jsp
Code:
<% response.sendRedirect&#40;"/sectest/secure/secTest.htm"&#41;;%>
test.jsp
Code:
<%@ include file="includeLibs.jsp" %>
<html>
<head>
<title>Sec Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<body>
This is a test.
</body>
</html>
tut.sectest.SecTestController
Code:
package tut.sectest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.*;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

/**
 * @author tbrown
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class SecTestController implements Controller &#123;

	private String testView;
	
	public void setTestView&#40;String testView&#41; &#123; this.testView = testView; &#125;
	
	public ModelAndView handleRequest&#40;HttpServletRequest request, HttpServletResponse response&#41;
		throws Exception &#123;
		
		return new ModelAndView&#40;testView&#41;;		
		
	&#125;
&#125;
tut.sectest.TestFormController
Code:
package tut.sectest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;


/**
 * @author tbrown
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class TestFormController extends SimpleFormController &#123;
	
	private String msg;
	
	public void setMsg&#40;String msg&#41; &#123; this.msg = msg; &#125;
	

	protected ModelAndView onSubmit&#40;HttpServletRequest request, HttpServletResponse response, Object command,
		BindException errors&#41; throws Exception &#123;
		
		return new ModelAndView&#40;getSuccessView&#40;&#41;&#41;;			
	&#125;
	
	protected Object formBackingObject&#40;HttpServletRequest request&#41; throws Exception &#123;
		
		return msg;		
	&#125;
&#125;
[/b]