views:

169

answers:

4

I am relatively new to the Spring Framework and Spring security.

I have used a custom authentication scheme, HTML:

<form action="j_spring_security_check">
    <input type="text" name="j_username" value="abc"/>
    <input type="text" name="j_password" value="abc"/>
    <input type="text" name="myCustom1" value="pqr"/> <!-- maybe type="hidden" -->
    <input type="text" name="myCustom2" value="pqr"/> <!-- maybe type="hidden" -->
</form>

and the corresponding code:

public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider
{
    @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken)
    throws AuthenticationException
    {
        System.out.println("Method invoked : additionalAuthenticationChecks isAuthenticated ? :"+usernamePasswordAuthenticationToken.isAuthenticated());
    }

    @Override protected UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication)
    throws AuthenticationException
    {
        System.out.println("Method invoked : retrieveUser");
        //I have Username,password:
        //HOW CAN I ACCESS "myCustom1", "myCustom2" here ?
    }
}
+1  A: 

If you need to use additional form parameters in order to manipulate the username and password, you can implement your own AuthenticationProcessingFilter

http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/ui/webapp/AuthenticationProcessingFilter.html

This class will have full access to the HttpRequest and therefore all the additional parameters you submit. If your goal is to somehow use these values to modify the username and password, this is where you would do it.

emills
but that would be another class altogether, it would be useful if i had access to it @ CustomAuthenticationProvider itself, where the processing for the user is done.to be frank, I am sending a variable to the server that determines the encryption schema used for the password.this would not make sense in another lcass.
Salvin Francis
If you just need to know what the encryption of the password is, you can do that logic in the AuthenticationProcessingFilter and have the filter return the plain text password, ready to be used by the Provider.
emills
+1  A: 

The trick here is that you need to create a new AuthenicationToken (maybe) extending UsernameAndPasswordAuthenicationToken and as @emills says you need to then implement a new AuthenciationProcessingFilter to map the request values to the token and submit these to the AuthenicationManager.

Basically there are a couple of parts to implementing a custom authenication chain in spring-security

  • AuthenicationToken - details of the authenication request and it's result, ie contains credentials you require to authenticate
  • AuthenicationProvider - registered with the AuthenicationManager, accepts your AuthenicationToken and validates the user and returns a token with the granted authorities set
  • AuthenciationFilter - doesn't actually have to be a filter just using AbstractProcessingFilter will make your life a little easier
Gareth Davis
A: 

I would go this way:

<bean id="authenticationProcessingFilter"  
    class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  ...
  <property name="authenticationDetailsSource">
    <bean class="org.acegisecurity.ui.AuthenticationDetailsSourceImpl">
        <property name="clazz"  
           value="com.MyAuthenticationDetails"/>
    </bean>
  </property>
</bean>

This is the class that holds the properties:

package com;
import javax.servlet.http.HttpServletRequest;
import org.acegisecurity.ui.WebAuthenticationDetails;
public class MyAuthenticationDetails extends WebAuthenticationDetails {
    public MyAuthenticationDetails() {
      super();
    }
    //This constructor will be invoqued by the filter
    public MyAuthenticationDetails(HttpServletRequest request) {
        super(request);
        this.myCustom1 = request.getParameter("myCustom1");
    }
    public String getMyCustom1() {
        return myCustom1;
    }
    private String myCustom1;
}

Now you have the username, password and the details.

rodrigoap
+1  A: 

I've done a similar thing, but different then anyone has suggested here. I am not saying this is the "right" way to do it - but it's worked very well for me. In the Principal object there is the user and there is also a Details object in the AuthenticationToken that you can store a Map(String, String) of other login info.

public class RequestFormDeatils extends SpringSecurityFilter {

   protected void doFilterHttp(HttpServletRequest request, ...) {
      SecurityContext sec = SecurityContextHolder.getContent();
      AbstractAuthenticationToken auth = (AbstractAuthenticationToken)sec.getAuthentication();
      Map<String, String> m = new HashMap<String, String>;
      m.put("myCustom1", request.getParamtere("myCustom1"));
      m.put("myCustom2", request.getParameter("myCustom2"));
      auth.setDetails(m);
}

Now anywhere in your code you get use the SecurityContext to propagate this security related info without having to couple it to your UserDetails object, or pass it as arguments. I do this code in a SecurityFilter at the end of the Spring Security Filter chain.

<bean id="requestFormFilter" class="...RequestFormDetails">
   <custom-filter position="LAST" />
</bean>
Gandalf
Thanks for the out of the box suggestion.I will definately give this a try.
Salvin Francis