2011-10-05 17 views
50

Esiste un tutorial o qualcuno ha dei suggerimenti su come eseguire le seguenti operazioni con Spring Security?Spring Security Autenticazione personalizzata e codifica della password

Task:

ho bisogno di ottenere il sale dal mio database per il nome utente di autenticazione e utilizzarla per cifrare la password fornita (dalla pagina di login) per confrontarlo con la password criptata memorizzata (aka autenticare l'utente).

ulteriori informazioni:

Io uso una struttura di database personalizzato. Un oggetto UserDetails viene creato tramite un custom UserDetailsService che a sua volta utilizza un DAOProvider personalizzato per ottenere le informazioni dal database.

mia security.xml file fino ad ora:

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

ora penso che avrò bisogno

 <password-encoder hash="sha" /> 

ma che altro? Come posso dire a primavera sicurezza di utilizzare il sale in database per codificare la password?


modificare:

ho trovato This SO post per essere informatative ma non sufficiente: Se io definisco una fonte di sale nel mio XML per essere utilizzati dal codificatore della password, in questo modo:

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

Dovrò scrivere un SaltSource personalizzato per utilizzare il mio sale personalizzato. Ma questo non si trova all'interno dell'oggetto UserDetails. Quindi ...

Alternativa 1:

Posso usare un'implementazione personalizzata di UserDetails che potrebbero poi avere la proprietà del sale?

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

e

@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 
} 

personalizzato 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"/> 


Alternativa 2:

Altrimenti avrei dovuto iniettare il mio accountDAO nella SaltSource per estrarre il sale per una data userName dal database.

MA: In che modo Spring Security chiama lo SaltSource?Sempre con saltSource.getSalt(userDetails)?

Quindi dovrei semplicemente assicurarmi che il mio usi il accountDAO per recuperare il sale.


Edit2:

appena saputo che il mio approccio è .. eredità .. :(Quindi credo che mi limiterò a utilizzare il StandardPasswordEncoder (che devo ancora capire come utilizzare esattamente

BTW: ho implementato la prima opzione con una classe UserDetails personalizzata estendendo la classe User e aggiungendo semplicemente una proprietà salt che è stata quindi passata a SaltSource come userPropertyToUse proprio come è stata proposta nel SO post menzionato in Modifica 1 ...


EDIT 3:

Sono appena la StandardPasswordEncoder di lavoro, quindi lascio alcune indicazioni qui:

Utilizzare la StandardPasswordEncoder per l'autenticazione:

<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> 

Questo richiede la spring-security-crypto module nella versione 3.1.0.RC? per quanto ne so. Impossibile trovare alcun repository con 3.0. versione (anche se da qualche parte aveva le versioni elencate che includevano 3.0.6 e così via). Anche le documentazioni parlano della sicurezza di primavera 3.1 quindi ho pensato, ci andrò.

Quando si crea un utente (per me solo un amministratore può farlo), mi basta usare

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

e ho finito.

La sicurezza di primavera crea in modo casuale un salino e lo aggiunge alla stringa della password prima di memorizzarlo nel database, quindi non è più necessaria la colonna di sale.

Si può però anche fornire un sale globale come un argomento del costruttore (new StandardPasswordEncoder("12345");), ma non sapevo come impostare la mia configurazione di sicurezza per recuperare quel valore da un fagiolo, invece di fornire una stringa statica con <constructor-arg name="secret" value "12345" />. Ma non so quanto sia necessario comunque.

risposta

34

sarò segnare questa come risposta, come ho risolto il mio problema e non altri commenti o risposte furono date:

Edit 1 - Alternativa 1 risponde alla domanda originale

MA ho avuto per imparare che salatura della password personalizzata è un approccio legacy che non è necessario in primavera Security 3.1 più, come ho descritto in

Edit 3 dove ho lasciato alcune indicazioni su come utilizzare lo StandardPasswordEncoder per i sali automatici che vengono memorizzati con la password.

+1

Il tuo post mi ha davvero aiutato a riscontrare un problema molto simile. +1 per risolvere autonomamente ^^ – user1431729

+4

Suggerirei BCryptPasswordEncoder invece di StandardPasswordEncoder. BCryptPasswordEncoder è una scelta migliore sia in termini di sicurezza che di interoperabilità con altre lingue – Farm

0

Per recuperare il sale globale da un fagiolo, utilizzare la lingua Primavera Espressione o SPEL.

<beans:bean id="encoder" 
     class="org.springframework.security.crypto.password.StandardPasswordEncoder"> 
    <constructor-arg value="#{someotherBean.somePropertyWithAGetterMethod"/> 
</beans:bean> 
Problemi correlati