I'm updating an older program to use Spring Security. Previously, it used Acegi security, and cached the credentials after an initial check of the SSO header into a session cookie; with Spring Security 3.1.4, I was able to get the program checking for the SSO username header (SM_USER - and no, we don't use Siteminder anymore, but to avoid painful software updates when we switched to OAM, we configured OAM to insert the SM_USER header into requests), and working locally with a valve setup in tomcat (6.0); however, when deployed out to the dev environment, with live SSO, it fails only on POSTS, and then, only to pages that use the same URL, but the different HTTP RequestMethod. Looking at the network traffic, it seems that the difference between the old code and new is that the new code is making an OAM SSO auth request, and then the post auth redirect drops the POST data and changes the RequestMethod to GET; so I thought perhaps adding credential caching back into the app would fix the issue; but I'm having difficulty finding a configuration that I can add in to get the caching enabled, and that's where I turn to you.
This is the security configuration that is doing per request authentication, and works locally:
<security:http use-expressions="true" auto-config="true" entry-point-ref="http403EntryPoint">
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:intercept-url pattern="/fastjump/auth/admin/*" access="hasRole('ROLE_ADMINISTRATOR')" />
<security:intercept-url pattern="/fastjump/auth/*" access="permitAll" />
<security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
</security:http>
<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>
<!-- This is the class that handles actually looking up the user from the persistent store and associating their
GrantedAuthority objects. This custom implementation uses a PersonService object to do the lookup. -->
<bean id="userDetailsService" class="corporate.fastjump.security.DefaultUserDetailsService">
<property name="personService" ref="personService"/>
<property name="fastJumpService" ref="fastJumpService"/>
</bean>
<bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
I've tried adding the following to the security config:
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map>
<security:filter-chain filters="httpSessionContextIntegrationFilter, securityContextHolderAwareRequest, siteminderFilter" pattern="/fastjump/auth/**"/>
</security:filter-chain-map>
</bean>
<bean id="httpSessionContextIntegrationFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name="securityContextRepository">
<bean class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
<property name="allowSessionCreation" value="false"/>
</bean>
</property>
</bean>
<bean id="securityContextHolderAwareRequest" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter">
</bean>
And this to the web.xml:
<!-- This filter is used to implement request level authorization. -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<!-- Note that we only send requests which require authentication and authorization services through the
Spring Security filters -->
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/auth/*</url-pattern>
</filter-mapping>
But that now adds a basic auth challenge to the /auth context requests. I'm missing the piece that ties together the caching with the pre auth. Does anyone have any suggestions?
So it turns out the SSO was the problem, but not in the way we initially thought. We have multiple different SSO domains (DEV, INT, PROD), and we had an autocompleter on the page in question that was hard coded to go out to a Web Service in the Prod domain, and while the Web Service API is specifically excluded in the Production domain from SSO protection (it's open to all users), the act of querying the Production server caused a query to the Production SSO domain, and overwrote the session with Production credentials. Getting back to the Dev server and trying to perform a POST with the Prod creds failed, and in the process of querying the Dev SSO for the proper credentials, it dropped the POST data, and changed the html request type to GET. Our solution was to update the autocompleter to have logic to determine which server it's running on (via JavaScript, look at the host), and then build the URL for the autocompleter back end based on which environment we're in.