web-dev-qa-db-fra.com

Authentification personnalisée Spring Security et encodage de mot de passe

Existe-t-il un didacticiel ou quelqu'un a-t-il des conseils sur la façon d'effectuer les opérations suivantes avec Spring-Security?

Tâche:

J'ai besoin d'obtenir le sel de ma base de données pour le nom d'utilisateur d'authentification et de l'utiliser pour crypter le mot de passe fourni (à partir de la page de connexion) pour le comparer au mot de passe crypté stocké (alias authentifier l'utilisateur).

informations supplémentaires:

J'utilise une structure de base de données personnalisée. Un objet UserDetails est créé via un UserDetailsService personnalisé qui à son tour utilise un DAOProvider personnalisé pour obtenir les informations de la base de données.

mon fichier security.xml jusqu'à présent:

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

maintenant je suppose que j'aurai besoin

        <password-encoder hash="sha" />

mais quoi d'autre? Comment puis-je dire à la sécurité de printemps d'utiliser le sel fourni par la base de données pour coder le mot de passe?


modifier :

J'ai trouvé Ce SO poste à titre informatif mais pas suffisant: Si je définis une source de sel dans mon xml à utiliser par l'encodeur de mot de passe, comme ceci:

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

Je vais devoir écrire un SaltSource personnalisé pour utiliser mon sel personnalisé. Mais cela ne se trouve pas à l'intérieur de l'objet UserDetails. Donc...

Alternative 1:

Puis-je utiliser une implémentation personnalisée de UserDetails qui pourrait alors avoir la propriété salt?

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

et

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

classe d'utilisateurs personnalisée:

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:

Sinon, je devrais injecter mon accountDAO dans le SaltSource pour extraire le sel d'un userName donné de la base de données.

MAIS: Comment Spring Security appelle-t-il le SaltSource? Toujours avec saltSource.getSalt(userDetails)?

Ensuite, je devrais juste m'assurer que mon SaltSource utilise userDetails.accountName Sur mon accountDAO pour récupérer le sel.


Edit2:

Je viens d'apprendre que mon approche est .. héritée .. :( Donc je suppose que je vais juste utiliser le StandardPasswordEncoder (que je dois encore comprendre exactement comment utiliser).

BTW: J'ai implémenté la première option avec une classe UserDetails personnalisée étendant la classe User et ajoutant simplement une propriété salt qui peut ensuite être transmise à SaltSource en tant que userPropertyToUse comme cela a été proposé dans le SO = poste mentionné dans Edit 1 ...


EDIT 3:

Je viens de faire fonctionner le StandardPasswordEncoder, donc je vais laisser quelques pointeurs ici:

Utilisez le StandardPasswordEncoder pour l'authentification:

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

Cela nécessite le module spring-security-crypto dans la version 3.1.0.RC? Pour autant que je sache. Impossible de trouver un référentiel contenant un 3.0. version (même si quelque part il y avait les versions répertoriées qui incluaient 3.0.6 et ainsi de suite). De plus, les documentations parlent de la sécurité du printemps 3.1, donc je me suis dit, je vais juste y aller.

Lors de la création d'un utilisateur (pour moi, seul un administrateur peut le faire), j'utilise simplement

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

et j'ai fini.

La sécurité de Spring créera au hasard un sel et l'ajoutera à la chaîne de mot de passe avant de le stocker dans la base de données afin qu'aucune colonne de sel ne soit plus nécessaire .

On peut cependant également fournir un sel global comme argument constructeur (new StandardPasswordEncoder("12345");), mais je ne savais pas comment configurer ma configuration de sécurité pour récupérer cette valeur à partir d'un bean au lieu de fournir une chaîne statique avec <constructor-arg name="secret" value "12345" />. Mais je ne sais pas combien cela est nécessaire de toute façon.

52
Pete

Je vais marquer cela comme une réponse, car j'ai résolu mon problème et aucun autre commentaire ou réponse n'a été donné:

Edit 1 - Alternative 1 répond à la question d'origine

MAIS J'ai dû apprendre que le salage de mot de passe personnalisé est une approche héritée qui n'est plus nécessaire dans Spring Security 3.1, comme je le décris dans

Edit où j'ai laissé quelques conseils sur la façon d'utiliser le StandardPasswordEncoder pour les sels automatisés qui sont stockés avec le mot de passe.

34
Pete

Pour ce que ça vaut, j'ai écrit ce billet de blog détaillant ce que vous avez décrit: http://rtimothy.tumblr.com/post/26527448708/spring-3-1-security-and-salting-passwords =

4
rooftop

Pour récupérer le sel global d'un bean, utilisez le Spring Expression Language ou SpEL.

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