Spring Security authenticationSuccessHandler for RememberMeAuthenticationFilter

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 is my custom implementation of AuthenticationSuccessHandler

 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 that successful authentication onAuthenticationSuccess is not called at all. I read the answer on StackOverflow that says I need to implement onAuthenticationSuccess instead of SimpleUrlAuthenticationSuccessHandler . I tried to do this, still did not work. Everything else is fine, the only problem is that every time I log in, spring just redirected me to '/' . Which is not what I want, I want it to just return '200 OK'

+4
source share
1 answer

Assuming I understood correctly, you want to break the filter chain and send an HTTP response code when the authentication is successful, regardless of how the authentication occurs; that is, it can be a login form or authentication with authentication.

So, first add the following logic to CustomSavedRequestAwareAuthenticationSuccessHandler :

 // place where applicable if (authentication != null) { response.setStatus(HttpServletResponse.SC_OK); } 

Secondly, define a new filter, for example:

 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 client file in the security:http section as:

 <custom-filter position="LAST" ref="myHttpResponseAuthFilter" /> 

Fourth, add a link for your success handler to your form-login as:

 <form-login ... authentication-success-handler-ref="mySuccessHandler" ... /> 

because it is not in your form authentication.

In addition, based on Spring Security's documentation on filter positions, it is recommended that you do not use auto-config with custom filters.

Notice, that:

  • The reason you see this behavior is because when you see the login form, it doesn't apply to mem-me services. Form processing resolved the final destination URL.
  • After the first time, it will be a mem-me filter that will be authenticated and must again send an HTTP response code.

I also suggest reading this answer as it gives more information about the difference between login forms, http-basic auth and recall services in Spring Security.

+3
source

Source: https://habr.com/ru/post/1502723/


All Articles