11

i have strange issue of for login sucess and redirect to page.

below is my spring security configuration.

<http auto-config="true" use-expressions="true">
    <intercept-url pattern="/login.hst**" access="anonymous or authenticated" />
    <intercept-url pattern="/**/*.hst" access="authenticated" />
    <form-login login-page="/login.hst"
        authentication-failure-url="/login.hst?error=true"
        authentication-success-handler-ref="loginSucessHandler" />
    <logout invalidate-session="true" logout-success-url="/home.hst"
        logout-url="/logout.hst" />
    <remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>
    <session-management>
    <concurrency-control max-sessions="1" />
</session-management>
</http>

LoginSuessHandler class:

@Service
public class LoginSucessHandler extends
        SavedRequestAwareAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication authentication)
            throws ServletException, IOException {
            ...
        super.setUseReferer(true);
        super.onAuthenticationSuccess(request, response, authentication);
    }

}

now problem of redirect to requested page on success. if i directly refer to any secure url spring redirects me to login page and on successful login to original requested link. but this is not working in case if user had earlier selected remember-me and then closing browser and now requesting direct URL, he is being properly authenticated but instead of redirecting him to requested page spring redirects to /. i have checked log and some spring source code and found it is not able to determine target url.

i have tried to set refer but referer value is null. but one strange thing i have noticed that in spring security configuration if i remove authentication-success-handler from remember-me configuration then it works.

    <remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>

not able to figure out issue. is authentication-success-handler implementation requied to be different for form login and remember-me?

Mansuro
  • 4,558
  • 4
  • 36
  • 76
Jigar Parekh
  • 6,163
  • 7
  • 44
  • 64
  • What is the version of spring security? 3.1 or 3.0? Have you set the property alwaysUseDefaultTargetUrl to true? – Vincent Devillers Jul 24 '12 at 13:42
  • i am using spring security 3.1. yes i have used property alwaysUseDefaultTargetUrl. if i set this to true then it always redirect me to / for both cases (remember-me and normal login) – Jigar Parekh Jul 24 '12 at 14:11
  • I was asking you about the version because this problem happens to me: my spring xml files was using the 3.1 namespace but the pom.xml was stilling use the 3.0... Bad day for me... :) So why do you need a custom success handler? – Vincent Devillers Jul 24 '12 at 14:21
  • i am using custom success handler to initlize certain data for user who logged in, and for also storing some data in session. i am also managing multiple tab access [using](http://stackoverflow.com/questions/6128134/can-i-manage-multiple-browser-tabs-with-spring-security/11358163#11358163) – Jigar Parekh Jul 24 '12 at 14:25
  • Could you change maxSessions to more than 1? Also, turn on debug level logging for Spring Security – jasop Jul 26 '12 at 08:45
  • jasop i have increased maxSessions to 2 and tried but got same result. – Jigar Parekh Jul 26 '12 at 09:23

4 Answers4

15

Remember-me differs from form-login in that authentication occurs during the actual request the user makes. For form-login, the user must first be redirected to the login page, submit the login form and after that they are redirected to the original target (which is usually cached in the session). So form-login requires a redirect, whereas remember-me doesn't. With a remember-me request, the user can be authenticated, and the request allowed to proceed without any intervention.

The primary purpose of an AuthenticationSuccessHandler is to control the navigation flow after authentication, so you wouldn't normally use one with remember-me at all. Using SavedRequestAwareAuthenticationSuccessHandler isn't a good idea, as there won't be a saved request available. If there is no saved request, then by default it will perform a redirect to "/" as you have observed.

If all you want is to add some functionality during a remember-me login, then you can implement the AuthenticationSuccessHandler interface directly without performing a redirect or a forward. As I explained above, you can't use the same implementation for form-login, since the current request is the submission of the login form (usually to the URL j_spring_security_check), and not a request to a URL within your application. So you need a redirect for form-login.

Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100
  • Thanks Luke, i had same doubt which you have mentioned about form login redirect and remember-me direct authentication. let me change my implementation from SavedRequestAwareAuthenticationSuccessHandler to SimpleUrlAuthenticationSuccessHandler and check. – Jigar Parekh Jul 27 '12 at 09:55
  • No, that wont work either. SimpleUrlAuthenticationSuccessHandler redirects to a URL. Just create your own bean implementing AuthenticationSuccessHandler and use that for remember-me. – Shaun the Sheep Jul 27 '12 at 10:04
  • this is also not working and not redirecting to any URL or no content is retuned from server. – Jigar Parekh Jul 30 '12 at 12:32
  • I assumed that when you wrote "closing browser and now requesting direct URL, he is being properly authenticated but instead of redirecting him to requested page spring redirects to /" that you didn't want the user redirected fro remember-me, since they are directly requesting a URL and there is nothing to redirect to. If you want some other behaviour you'll need to clarify your question and explain more clearly what you've already done. – Shaun the Sheep Jul 30 '12 at 13:18
  • not sure what i missed to explain. i think i have clearly mentioned that i want same behaviour (redirecting to requested URL) in both cases normal form login and remember me. – Jigar Parekh Jul 30 '12 at 13:54
  • I think you need to explain why you want a redirect in the case of remember-me, since it isn't normally required (as I explained in my answer). It might help if you list the exact request-response sequence you expect in both the form-login and remember-me cases, including redirects. – Shaun the Sheep Jul 30 '12 at 13:58
  • Thanks Luke for effort, my problem is still not solved moving to spring forum for solution. will update answer once i have solution. – Jigar Parekh Jul 31 '12 at 08:17
  • @JigarParekh Hey, have you solved your problem? I'm having the same problem as you did. – William Wino Sep 17 '13 at 06:26
  • 1
    @William still problem exist, posted to spring but no confirmed solution to it. – Jigar Parekh Sep 17 '13 at 07:34
  • @JigarParekh damn..I just want to return "200 OK" after a successful authentication. Thanks for the reply. – William Wino Sep 17 '13 at 17:57
  • 2
    what you want is not possible since if you provide a successHandler the filter will return and does not call chain.doFilter(request, response); Try using an AuthenticationApplicationListener instead as kabak mentions. – AndiDev Apr 06 '14 at 11:45
13

You would rather use ApplicationListener and look for the event InteractiveAuthenticationSuccessEvent.

InteractiveAuthenticationSuccessEvent has a property generatedBy which will be the filter, ie UsernamePasswordAuthenticationFilter (form logins) and RememberMeAuthenticationFilter (remeber me logins)

@Component
class AuthenticationApplicationListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {

  @Override
  void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
    //do something
  }

}

using a custom implementation of AuthenticationSuccessHandler on rememberMe will cause problems. Take a look at the flow in RememberMeAuthenticationFilter. if the successHandler is used, the filter chain is bypassed

kabal
  • 2,085
  • 4
  • 29
  • 43
3

Using an AuthenticationSuccessHandler does not work. As stated in another answer, the spring security filter chain will be bypassed!
What works, is to use an ApplicationListener - as another answer also proposes. But to find out, if your user is authenticated by remember me, the idea to use InteractiveAuthenticationSuccessEvent.getGeneratedBy() is not working: getGeneratedBy returns Class<T>, that means a generic. Therefore at runtime you cannot find out, if T is a RememberMeAuthenticationFilter.

What worked fine for me: Use InteractiveAuthenticationSuccessEvent.getAuthentication().

Here an example (by the way: @EventListener is used since Spring Security 4.2 - if you use an earlier version, do the following via implementing ApplicationListener<InteractiveAuthenticationSuccessEvent>):

@Component
public class AuthenticationApplicationListener {

    @EventListener
    public void handleInteractiveAuthenticationSuccess(InteractiveAuthenticationSuccessEvent event) {
        if (RememberMeAuthenticationToken.class.isAssignableFrom(event.getAuthentication().getClass())) {
            .... do some stuff
    }
  }
 }
Divyang Desai
  • 7,483
  • 13
  • 50
  • 76
olivmir
  • 692
  • 10
  • 29
1

You should implement different authentication-success-handler for login form and for remember-me. If you want to perform redirect in remeber-me handler you can use SimpleUrlAuthenticationSuccessHandler and set DefaultTargetUrl.

public class RememberMeAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
    Authentication authentication) throws IOException, ServletException {

    // ...

    super.setAlwaysUseDefaultTargetUrl(true);
    super.setDefaultTargetUrl(request.getRequestURL().toString());
    super.onAuthenticationSuccess(request, response, authentication);
}
cmenti
  • 116
  • 4