Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security Custom Authentication and Password Encoding

Is there a tutorial out there or does anyone have pointers on how to do the following with Spring-Security?

Task:

I need to get the salt from my database for the authenticating username and use it to encrypt the provided password (from the login page) to compare it to the stored encrypted password (a.k.a. authenticate the user).

additional information:

I use a custom database structure. A UserDetails object is created via a custom UserDetailsService which in turn uses a custom DAOProvider to get the information from the database.

my security.xml file so far:

<authentication-manager>     <authentication-provider user-service-ref="userDetailsService">     </authentication-provider> </authentication-manager> 

now I guess I'll need

        <password-encoder hash="sha" /> 

but what else? How do I tell spring security to use the databaseprovided salt in order to encode the password?


edit:

I found This SO post to be informatative but not sufficient: If I define a salt source in my xml to be used by the password encoder, like so:

        <password-encoder ref="passwordEncoder">                             <salt-source ref="saltSource"/>         </password-encoder> 

I'll have to write a custom SaltSource to use my custom salt. But that's not to be found inside the UserDetails object. So...

Alternative 1:

Can I use a custom Implementation of UserDetails which might then have the salt property?

<beans:bean id="saltSource" class="path.to.MySaltSource"     p:userPropertyToUse="salt"/> 

and

@Service("userDetailsService")  public class UserDetailsServiceImpl implements UserDetailsService {     public UserDetails loadUserByUsername(String username)             throws UsernameNotFoundException, DataAccessException {          // ...         return buildUserFromAccount(account);     }      @Transactional(readOnly = true)      UserDetailsImpl buildUserFromAccount(Account account){          // ... build User object that contains salt property } 

custom User Class:

public class UserDetailsImpl extends User{      // ...      private String salt;      public String getSalt() { return salt; }      public void setSalt(String salt) { this.salt = salt; } } 

security.xml:

<authentication-manager>     <authentication-provider user-service-ref="userDetailsService">         <password-encoder hash="sha">                         <salt-source ref="saltSource"/>     </password-encoder>     </authentication-provider> </authentication-manager>  <beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource" p:userPropertyToUse="salt"/> 


Alternative 2:

Otherwise I'd have to inject my accountDAO into the SaltSource to extract the salt for a given userName from the database.

BUT: How does Spring Security call the SaltSource? Always with saltSource.getSalt(userDetails)?

Then I'd just have to make sure my SaltSource uses userDetails.accountName on my accountDAO to retrieve the salt.


Edit2:

Just learned that my approach is.. legacy.. :( So I guess I'll just use the StandardPasswordEncoder (which I still have to figure out how to use exactly).

BTW: I implemented the first option with a custom UserDetails class extending the User class and just adding a salt property which an then be passed to the SaltSource as a userPropertyToUse just like it has been proposed in the SO post mentioned in Edit 1...


EDIT 3:

Just got the StandardPasswordEncoder working, so I'll leave some pointers here:

Use the StandardPasswordEncoder for Authentication:

<beans:bean id="encoder"      class="org.springframework.security.crypto.password.StandardPasswordEncoder"> </beans:bean>   <authentication-manager>     <authentication-provider user-service-ref="userDetailsService">         <password-encoder ref="encoder" />              </authentication-provider> </authentication-manager> 

This requires the spring-security-crypto module in version 3.1.0.RC? as far as I know. Couldn't find any repository that has a 3.0. version (even though somewhere it had the versions listed that included 3.0.6 and so on). Also the documentations talks about spring security 3.1 so I figured, I'll just go with that.

When creating a user (for me only an admin can do that), I just use

        StandardPasswordEncoder encoder = new StandardPasswordEncoder();         String result = encoder.encode(password); 

and I'm done.

Spring security will randomly create a salt and add it to the password string before storing it in the database so no salt column is needed anymore.

One can however also provide a global salt as a constructor argument (new StandardPasswordEncoder("12345");), but I didn't know how to set up my security configuration to retrieve that value from a bean instead of supplying a static string with <constructor-arg name="secret" value "12345" />. But I don't know how much that is needed anyway.

like image 956
Pete Avatar asked Oct 05 '11 08:10

Pete


People also ask

Does Spring Security support password encoding?

Spring Security supports many password encoders, for both old and modern algorithms. Also, Spring Security provides methods to work with multiple password encodings in the same application.

How does Spring Security validate username and password?

If you really want to do validation before it hits any Spring Security code you will need to add a Filter before the UsernamePasswordAuthenticationFilter and do your validation there. Alternatively, subclass DaoAuthenticationProvider and override retreiveUser().

How does Spring Security know password?

You use the same code that you already used to hash the password the first time, when the user created their userid/password. With a one way hash you don't decrypt the stored password, you hash the entered value and compare it with the already stored, hashed value.


2 Answers

I'll mark this as answered, as I solved my problem and no other comments or answers were given:

Edit 1 - Alternative 1 answers the original question

BUT I had to learn that customized password salting is a legacy approach that is not needed in Spring Security 3.1 any more, as I describe in

Edit 3 where I left some pointers on how to use the StandardPasswordEncoder for automated Salts that are stored with the password.

like image 130
Pete Avatar answered Sep 20 '22 21:09

Pete


For what it's worth, I wrote this blog post detailing what you've described: http://rtimothy.tumblr.com/post/26527448708/spring-3-1-security-and-salting-passwords

like image 36
rooftop Avatar answered Sep 19 '22 21:09

rooftop