views:

63

answers:

3

I have a custom-authentication-provider defined in my Spring Security configuration. This class implements AuthenticationProvider, and I can successfully log in using the form defined on my page. The issue is I want to call this class not just on the login page, but from the registration page as well.

The registration page uses a different command class and collects more information than the login form. Right now, when the user registers, I call the appropriate controller, add the record to the database and they can then log in but they aren't logged in automatically. As they've just given me their user name/password on the registration page, can I then pass this to the custom AuthenticationProvider class so they are also logged in?

I've tried creating an org.springframework.security.Authentication class in the registration controller and calling the authenticate method on my customer AuthenticationProvider class, and this doesn't error out, but the user isn't logged in. Do I have to call a method higher in the Spring Security filter chain to accomplish this? Should I redirect the controller to the j_spring_security_check URL? If so, how would I pass the username/password?

A: 

Your form needs to be submitted to j_spring_security_check. You need two input fields with these names: j_username and j_password. Upon form submission, Spring Security will pass the credential to your custom authentication provider to do the work.

limc
That's how I have the login form, but for registration, I have a controller so I can do different logic. Or are you saying submit both the login and registration forms to the j_spring_security_check URL and add the login/registration logic in the custom AuthenticationProvider? In the registration controller, I can return a ModelAndView object so I can control what page the user goes to next - would I have to add another controller after the login to then check where the user should be redirected to? There can be multiple places - after login, or 2 after registration depending on the user type
David Buckley
When you set up Spring Security, the way it works is it checks whether a page requires some authentication before displaying it. If it does, it will automatically redirect the user to the login page first. Depending on how you set up, you can allow the user to proceed to the registration page (which I think is what you want) OR you can redirect them to a standard welcome page upon successful authentication.
limc
How does your intercept-url pattern looks like? This intercept-url pattern should catch your registration page for authentication, in another word, you don't need to 1) create additional login form, or 2) explicitly redirect your user to the login page. That should be done automatically by Spring Security. Your entire application *should* have just one login page. Spring Security will redirect your user to it when it is needed.
limc
The registration page does not require authentication. How it works is if the user has not used the site before, they click on register and create a username/password. This saves their info in the db. If they've already registered, they go to the login page and enter their username/password. I don't want to require any authentication before getting to the registration page-I know those are brand new users. What I want is to allow these new users to register and then immediately log them in, instead of having them register, then have to go to the login page and enter the same username/password.
David Buckley
I think your justification is reasonable. While there has to be a way to programmatically notify SS to authenticate the user upon successful user creation, would it be possible for you to redirect the request to a "loading" page that will perform an automaitc hidden form submission with the newly created username/password?
limc
+1  A: 

You need to put the result of AuthenticationProvider.authenticate() into SecurityContext (obtained from SecurityContextHolder).

Also be aware of AuthenticationSuccessEvent - if your application rely on this event (some Spring Security features may use it, too), you should publish it (you can obtain the default AuthenticationEventPublisher via autowiring). It may be useful to wrap your authentication provider with ProviderManager, it publishes the event automatically using the given publisher.

axtavt
+1  A: 

The problem you are having is that although you have successfully authenticated the user you have not stored the result of this authentication in the user's SecurityContext. In a web application this is a ThreadLocal object which the SecurityContextPersistenceFilter will use to store the user's credentials in the HTTPSession

You should also avoid authenticating directly with your custom authentication provider if you can. Your xml configuration should contain an AuthenticationManager which your custom authentication provider has been wired into. For example,

<bean id="customAuthenticationProvider" 
  class="com.foo.CustomAuthenticationProvider">
  <property name="accountService" ref="accountService"/>
</bean>
<security:authentication-manager alias="authenticationManager">
  <security:authentication-provider ref="customAuthenticationProvider"/>
</security:authentication-manager>

If you wire the authenticationManager into your registration service and authenticate using that it will additionally,

Our registration service does this as follows

final UsernamePasswordAuthenticationToken authRequest = new 
  UsernamePasswordAuthenticationToken(username, password);

final Authentication authentication = 
  authenticationManager.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);

We also optionally store the authentication result at this point in a remember-me cookie using the onLoginSuccess() method of TokenBasedRememberMeServices.

Caoilte