I want to implement a custom AuthenticationSuccessHandler
for my login filter which is org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter
.
Here is my spring security configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http entry-point-ref="restAuthenticationEntryPoint" disable-url-rewriting = "true" auto-config="true" use-expressions="true">
<security:intercept-url pattern="/api/*" access="hasRole('AUTHENTICATED_USER')"/>
<security:remember-me key="spring_login_detail" services-ref="rememberMeServices"/>
<security:form-login login-processing-url="/login"/>
<security:logout
invalidate-session="true"
delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"
logout-url="/logout"
/>
</security:http>
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
<security:authentication-provider user-service-ref="customUserDetailsService">
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
<bean id="mySuccessHandler" class="com.projectname.security.CustomSavedRequestAwareAuthenticationSuccessHandler"/>
<bean id="customUserDetailsService" class="com.projectname.security.CustomUserDetailsService"/>
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="key" value="jsfspring-sec" />
<property name="userDetailsService" ref="customUserDetailsService" />
<property name="alwaysRemember" value="false" />
<property name="tokenValiditySeconds" value="1209600" />
<property name="parameter" value="_spring_security_remember_me_input"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="spring_login_detail"/>
</bean>
<bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationSuccessHandler" ref="mySuccessHandler"/>
</bean>
</beans>
Here's my custom AuthenticationSuccessHandler
implementation
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.util.StringUtils;
public class CustomSavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private RequestCache requestCache = new HttpSessionRequestCache();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest == null) {
clearAuthenticationAttributes(request);
return;
}
String targetUrlParam = getTargetUrlParameter();
if (isAlwaysUseDefaultTargetUrl()
|| (targetUrlParam != null
&& StringUtils.hasText(request.getParameter(targetUrlParam)))) {
requestCache.removeRequest(request, response);
clearAuthenticationAttributes(request);
return;
}
clearAuthenticationAttributes(request);
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
}
The problem is after a successful authentication the onAuthenticationSuccess
isn't called at all. I've read an answer on StackOverflow that says that I need to implement onAuthenticationSuccess
instead of SimpleUrlAuthenticationSuccessHandler
. I've tried to do that, still didn't work. Everything else is fine, the only problem is each time I log in, spring just redirected me to '/'
. Which is not what I want, I want it just to return '200 OK'
Assuming that I've understood correctly, you want to break the filter chain and send an HTTP response code when an authentication succeeds no matter how the authentication happens; i.e. it can be login form or remember-me authentication.
So, first, add the following logic to your CustomSavedRequestAwareAuthenticationSuccessHandler
:
// place where applicable
if (authentication != null) {
response.setStatus(HttpServletResponse.SC_OK);
}
Second, define a new filter such as :
class HttpResponseAuthenticationFilter extends RememberMeAuthenticationFilter {
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
super.onSuccessfulAuthentication(request, response, authResult);
if (authResult != null) {
response.setStatus(HttpServletResponse.SC_OK);
}
}
}
Third, define the customer filer in security:http
section as:
<custom-filter position="LAST" ref="myHttpResponseAuthFilter" />
Fourth, add a reference for your success handler to your form-login
as:
<form-login ... authentication-success-handler-ref="mySuccessHandler" ... />
because this is missing from your form authentication.
Additionally, based on Spring Security documentation on filter positions, it is advised that you do not use auto-config
with custom filters.
Observe that:
I also suggest reading this answer as it gives more insight into the difference between form-login, http-basic auth, and remember-me services in Spring Security.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With