9

After a user creates their account, I want to log that user on automatically.

I have standard form logins being handled by Springs filter on /postlogin. If I go to http://localhost/postlogin it attempts to log me in (fails because I didn't include the post parameters), but makes the proper attempt.

But if I want to log the user in programatically and I try to return from the controller: "forward:/postlogin" I get a 404.

I assume the forward: directive is not passing through the filters, thus not getting handled by the UsernamePasswordAuthenticationFilter.

How do I manually induce a login programatically? I want to do this after the user creates a new account (they should be logged into that account immediately upon completion of the registration).

David Parks
  • 30,789
  • 47
  • 185
  • 328

3 Answers3

17

I mis-read another piece of guidance and realized that the correct way of handling this is the following:

1) Manually set the Authentication token on SecurityContextHolder

    UsernamePasswordWithAttributesAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( loadUserByUsername(username), password, authorities );
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);

2) Do Not render a page at this point or use the forward: directive. You must use the redirect: directive.

return "redirect:/accountcreated";

If you render a page the page will load fine, but the session object will be lost because a new j_session_id will be created but will not make it to the browser mid-request and the next request will use the old j_session_id, loosing the new session object & authetication.

Using the forward: directive will bypass the authentication filters, no good.

But redirect: causes the updated session information to make it to the browser.

David Parks
  • 30,789
  • 47
  • 185
  • 328
5

The new filtering feature in Servlet 2.4 basically alleviates the restriction that filters can only operate in the request flow before and after the actual request processing by the application server. Instead, Servlet 2.4 filters can now interact with the request dispatcher at every dispatch point. This means that when a Web resource forwards a request to another resource (for instance, a servlet forwarding the request to a JSP page in the same application), a filter can be operating before the request is handled by the targeted resource. It also means that should a Web resource include the output or function from other Web resources (for instance, a JSP page including the output from multiple other JSP pages), Servlet 2.4 filters can work before and after each of the included resources. .

To turn on that feature you need:

web.xml

<filter>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter>  
<filter-mapping>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <url-pattern>/<strike>*</strike></url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

RegistrationController

return "forward:/login?j_username=" + registrationModel.getUserEmail()
    + "&j_password=" + registrationModel.getPassword();
AlexK
  • 111
  • 2
  • 3
2

Spring authentication via REST (Jersey)

Just to illustrate @David's answer (simplified as much as possible):

@POST
@Path("login")
public Response login(@FormParam("login") String login, @FormParam("pass") String pass)
{
    if (yourCheck(login, pass))
    {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        Authentication auth = new UsernamePasswordAuthenticationToken(login, pass, authorities);
        SecurityContextHolder.getContext().setAuthentication(auth);

        // IMPORTANT: Do not pass any data in the response body

        // show empty 200 page (suitable for REST clients)
        return Response.ok().build();
        // or redirect to your home page (for web UI)
        return Response.temporaryRedirect(new URI("/homepage/")).build();
    }
    else
    {
        return Response.status(Status.UNAUTHORIZED).build();
    }
}
Nikita Bosik
  • 851
  • 1
  • 14
  • 20