IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Java Discussion :

Spring security : authentification avec MySQL


Sujet :

Spring Java

  1. #1
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2009
    Messages : 391
    Points : 185
    Points
    185
    Par défaut Spring security : authentification avec MySQL
    Bonjour à tous ,



    j'essaie de mettre en place un système d'authentification sur mon app web à l'aide de Spring Security. Pour le moment, j'ai suivi ce tuto. https://spring.io/guides/tutorials/s...dd-a-home-page.

    Ca fonctionne mais pas de la façon que je voudrais. Pour le moment, ça utilise le webservice REST suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	@RequestMapping("/user")
    	public Principal user(Principal user){
    		return user;
    	}
    Moi, ce que j'aimerais, c'est envoyer le login+mdp et vérifier dans ma base MySQL si ça correspond. J'ai donc fait le webservice suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    @RequestMapping("/check-login")
    	public User login(FormulaireLoginDto formulaireLoginDto){
    		User user = null;
     
    		try {
    			user = userDao.findByLogin(formulaireLoginDto.getLogin());
    		} catch (Exception e) {
    			return null;
    		}
     
    		return user;
    	}
    Le problème c'est que je ne peux pas appeler ce web service. C'est comme si une première authentification était demandée.

    Je m'explique. Lorsque je lance mon app. qui est composée de Spring Boot + Spring Security + AngularJs; je peux accéder à mon webservice si j'utilise le plugin Advanced Rest Client de Chrome via l'adresse http://localhost:8080/check-login. Ca me renvoi bien un statut 200:OK.

    Par contre, si je passe par mon navigateur en entrant http://localhost:8080, j'arrive sur ma page d'accueil et dans les log de l'outil de développement Chrome j'ai le message suivant : http://localhost:8080/check-login 401 (Unauthorized)

    Pour information, si je rentre directement le lien http://localhost:8080/check-login dans mon navigateur, une fenêtre d'authentification s'ouvre et si je rentre mon login+mdp Spring security, j'ai accès au webservice.

    Avez-vous une idée de ce qu'il se passe ? Merci.

  2. #2
    Membre averti
    Inscrit en
    Octobre 2005
    Messages
    135
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 135
    Points : 391
    Points
    391
    Par défaut
    Tu t'y prend mal en faites.

    garde le code originale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @RequestMapping("/user")
    	public Principal user(Principal user){
    		return user;
    	}
    Ce qu'il te faut c'est ton propre UserDetailsService.
    http://docs.spring.io/spring-securit...w.html#d0e1613

    C'est ce service qui va chercher en base l'utilisateur ( avec son password et toutes les info qui vont bien).
    Et tu laisse spring security verifier comme pour l'instant le password.

    Le Principal sera remplie grâce au info de ce user details service.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
     
    @Service("userDetailsService")
    public class UserDetailsServiceImpl implements UserDetailsService {
     
        private final UserDao userDao;
     
        @Autowired
        public UserDetailsServiceImpl(UserDao userDao) {
    	super();
    	this.userDao= userDao;
        }
     
        @Override
        public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException {
    	// userName is Email.
    	User user = userDao.findByLogin(arg0);
    	if (account == null) {
    	    throw new UsernameNotFoundException("login.error.notfound");
    	}
     
    	return new UserDetailsImpl(account);
        }
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    class UserDetailsImpl implements UserDetails {
     
     /** toutes les infos qu'il faut **/
     
      public UserDetailsImpl  ( User user ) {
     
     
      }
     
     
    }

  3. #3
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2009
    Messages : 391
    Points : 185
    Points
    185
    Par défaut
    Bien reçu. Merci .

    Alors petit résumé pour voir si je comprend bien :

    1/ L'utilisateur rempli un champ avec son login et un autre avec son mot de passe (login et mdp de MySQL)

    2/ Mon code Javascript/AngularJs envoi toujours en POST le login/mdp Spring Security dans le header + le login/mdp de l'utilisateur ?

    3/ J'ai toujours ma méthode "user" avec le Principal qui reste comme elle est.

    4/ J'ajoute un "Service" (quel est la différence entre un @Service et un @RestController ?) qui implémente "UserDetailsService" fourni par Spring Security

    5/ J'ajoute une classe qui implémente "UserDetails".

    C'est bien ça ? Et tout ça fonctionne grâce à la magie de Spring ?

    Merci d'avance.

  4. #4
    Membre averti
    Inscrit en
    Octobre 2005
    Messages
    135
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 135
    Points : 391
    Points
    391
    Par défaut
    Citation Envoyé par paladice Voir le message
    Bien reçu. Merci .

    1/ L'utilisateur rempli un champ avec son login et un autre avec son mot de passe (login et mdp de MySQL)
    Oui.

    2/ Mon code Javascript/AngularJs envoi toujours en POST le login/mdp Spring Security dans le header + le login/mdp de l'utilisateur ?
    Seulement le login/mdp de mysql.
    Spring security n'as pas de mot de passe à lui en faite.
    Par défaut Spring boot fait une authentification en mémoire.
    En lui fournissant un UserDetailsService, il l'utilisera à la place.
    Attention ! tes login mot de passe doivent être hasher (en Bcrypt par défaut).

    3/ J'ai toujours ma méthode "user" avec le Principal qui reste comme elle est.
    Oui

    4/ J'ajoute un "Service" (quel est la différence entre un @Service et un @RestController ?) qui implémente "UserDetailsService" fourni par Spring Security
    Un RestController est comme son nom l'indique un controller REST. Son boulot est de fournir du JSON au navigateur Web.
    Un service est la pour fournir un service (!!) à d'autre méthode Java. UserDetailService est la pour fournir des information d'un utilisateur.
    ( Comme ton Dao peut être considéré comme un service, il permet d'aller chercher des information en base).

    5/ J'ajoute une classe qui implémente "UserDetails".
    Oui

    C'est bien ça ? Et tout ça fonctionne grâce à la magie de Spring ?
    Spring n'est pas magique ^^.

    Quand Spring Security recoit une demande POST par angular, déjà il se demande si cette utilisateur existe.
    Pour cela, il demande à UserDetailService de lui fournir un utilisateur suivant le login.
    Une fois l'utilisateur en main, il prend le password fournie, le hash (en Bcrypt par défaut) et le compare.
    Bingo, ca match, on as donc le bon couple User/Paswword.
    Spring te met en session le Principal contenant le UserDetails.

    Si un jour tu veux viré la BDD et mettre un Ldap a la place ?
    Pas de problème tu remplace le UserDetailService ( Spring en fournit un d'ailleurs ).

    Tu peut regarder la doc sur les AuthentProvider.
    http://docs.spring.io/spring-securit...auth-providers
    ( lien vers la 3.0, je te laisse chercher pour la 4.0 ).

    Tu as d'autre tuto sur juste la partie authent si tu fouille bien les samples de Spring.

  5. #5
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2009
    Messages : 391
    Points : 185
    Points
    185
    Par défaut
    Bien reçu =D merci.

    Je pense avoir (grâce à tes conseils) implémenté presque tout ce que qu'il me fallait. Il doit me manquer une configuration Spring Boot surement pour indiquer que je veux utiliser le UserDetailsService parce que malgré tout ce que j'ai fait, ça fonctionne toujours avec le login/mdp par défaut mais toujours pas avec le login/mdp de la BDD :/.

    Je post mon code au cas où tu aurais une dernière idée pour m'aider ou si ça peut aider quelqu'un qui se poserait la même question que moi :

    Etape 1 (le formulaire HTML) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    <form role="form" ng-submit="controller.login()">
     
        <div class="form-group">
            <label for="username">Username:</label> 
            <input type="text" class="form-control" id="username" name="username" ng-model="controller.credentials.username"/>
        </div>
     
        <div class="form-group">
            <label for="password">Password:</label> 
            <input type="password" class="form-control" id="password" name="password" ng-model="controller.credentials.password"/>
        </div>
     
        <button type="submit" class="btn btn-primary">Submit</button>
     
    </form>
    Il appelera la fonction javascript "login".

    Etape 2 (Le code JS/AngularJS) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    myModule.controller('NavCtrl',function($rootScope, $location, $http){
     
        var self = this
     
        var authenticate = function(credentials, callback) {
     
     
            var headers = credentials ? {authorization : "Basic " + btoa(credentials.username + ":" + credentials.password)} : {};
     
            $http.get('user', {headers : headers}).then(
                function(response) {
                    if (response.data.name) {
                        $rootScope.authenticated = true;
                    } else {
                        $rootScope.authenticated = false;
                    }
                    callback && callback();
                }, 
                function() {
                    $rootScope.authenticated = false;
                    callback && callback();
                }
            );
     
        }
     
        authenticate();
        self.credentials = {};
     
        self.login = function() {
            authenticate(self.credentials, function() {
                if ($rootScope.authenticated) {
                    $location.path("/");
                    self.error = false;
                } else {
                    $location.path("/login");
                    self.error = true;
                }
            });
        };
     
    	self.logout = function() {
    		$http.post('logout', {}).finally(function() {
    			$rootScope.authenticated = false;
    			$location.path("/");
    		});
    	}
     
    });
    Tout d'abord on rentre dans la fonction "login" appelée précédemment, puis on rentre dans la fonction "authenticate" qui va faire un appel du webservice 'user' en passant en Header le login et mot de passe.

    Etape 3 (le web service REST) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @RestController
    public class TestRest {
     
    	@RequestMapping("/user")
    	public Principal user(Principal user){
    		return user;
    	}
     
    }
    Etape 4 (le UserDetailsService) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    @Service("userDetailsService")
    public class UserDetailsServiceImpl implements UserDetailsService {
     
    	public UserDao userDao;
     
    	@Autowired
    	public UserDetailsServiceImpl(UserDao _userDao) {
    		super();
    		userDao = _userDao;
    	}
     
    	@Override
    	public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException {
     
    		UserDetailsImpl userDetailsImpl = null;
     
    		User user = userDao.findByLogin(arg0);
     
    		if(user == null){
    			throw new UsernameNotFoundException("Login not found");
    		} else{
    			userDetailsImpl = new UserDetailsImpl(user);
    		}
     
    		return userDetailsImpl;
    	}
     
    }
    Ici, on indique que l'on veut utiliser une authentification plus poussée que la simple authentification par défaut.

    Etape 4bis (la classe qui représente l'objet User avec le login et mdp) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
     
    public class UserDetailsImpl implements UserDetails {
     
    	/** The Constant serialVersionUID. */
    	private static final long serialVersionUID = 1L;
     
    	/** The _username. */
    	private String username;
     
    	/** The _password. */
    	private String password;
     
    	public UserDetailsImpl(User user) {
    		username = user.getLogin();
    		password = user.getPwd();
    	}
     
    	/**
             * @param password the password to set
             */
    	public void setPassword(String password) {
    		this.password = password;
    	}
     
    	@Override
    	public Collection<? extends GrantedAuthority> getAuthorities() {
    		// TODO Auto-generated method stub
    		return null;
    	}
     
    	@Override
    	public String getPassword() {
    		// TODO Auto-generated method stub
    		return null;
    	}
     
    	/**
             * @param username the username to set
             */
    	public void setUsername(String username) {
    		this.username = username;
    	}
     
    	@Override
    	public String getUsername() {
    		// TODO Auto-generated method stub
    		return null;
    	}
     
    	@Override
    	public boolean isAccountNonExpired() {
    		// TODO Auto-generated method stub
    		return false;
    	}
     
    	@Override
    	public boolean isAccountNonLocked() {
    		// TODO Auto-generated method stub
    		return false;
    	}
     
    	@Override
    	public boolean isCredentialsNonExpired() {
    		// TODO Auto-generated method stub
    		return false;
    	}
     
    	@Override
    	public boolean isEnabled() {
    		// TODO Auto-generated method stub
    		return false;
    	}
     
    }
    Mais j'ai cru comprendre qu'on pouvait ajouter d'autres choses que le login et mot de passe dedans.

    Etape 5 (la configuration Spring Boot) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    @SpringBootApplication
    public class BusinessBootApplication {
     
    	public static void main(String[] args) {
    		SpringApplication.run(BusinessBootApplication.class, args);
    	}
     
    	@Configuration
    	@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
    	protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter{
    		@Override
    		protected void configure(HttpSecurity http) throws Exception {
    			http
    			.httpBasic()
    			.and()
    			.authorizeRequests()
    			.antMatchers("/index.html","/home.html","/login.html","/").permitAll()
    			.anyRequest()
    			.authenticated()
    			.and()
    			.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
    			.csrf()
    			.csrfTokenRepository(csrfTokenRepository());
    		}
     
    		private CsrfTokenRepository csrfTokenRepository() {
    			HttpSessionCsrfTokenRepository repo = new HttpSessionCsrfTokenRepository();
    			repo.setHeaderName("X-XSRF-TOKEN");
    			return repo;
    		}
    	}
    }
    Il doit manquer quelque chose pour que le tout fonctionne. Probablement dans la configuration Spring Boot...

    Edit : J'ai trouvé, il fallait ajouter le ".userDetailsService(userDetailsServiceImpl);" dans la configuration Spring Boot.

    Merci encore.

  6. #6
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2009
    Messages : 391
    Points : 185
    Points
    185
    Par défaut
    Voilà voilà. Ca avance petit à petit grâce à vous mais il y a de nouveau un problème et maintenant ça surgit dans une classe fournie par Spring (Security je pense).

    La classe s'appelle "AbstractUserDetailsAuthenticationProvider". J'ai vu que l'erreur venait surement de là car j'ai parcouru l'exécution en mode debug.

    L’exécution passe par cette classe et notamment par le try/catch suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    		try {
    			preAuthenticationChecks.check(user);
    			additionalAuthenticationChecks(user,
    					(UsernamePasswordAuthenticationToken) authentication);
    		}
    		catch (AuthenticationException exception) {
    			if (cacheWasUsed) {
    				// There was a problem, so try again after checking
    				// we're using latest data (i.e. not from the cache)
    				cacheWasUsed = false;
    				user = retrieveUser(username,
    						(UsernamePasswordAuthenticationToken) authentication);
    				preAuthenticationChecks.check(user);
    				additionalAuthenticationChecks(user,
    						(UsernamePasswordAuthenticationToken) authentication);
    			}
    			else {
    				throw exception;
    			}
    		}
    et comme vous l'aurez deviné, l'exception est levé sur l'instruction : "preAuthenticationChecks.check(user);"

    Alors, en passant dans cette fonction je découvre les tests suivants :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    public void check(UserDetails user) {
    			if (!user.isAccountNonLocked()) {
    				logger.debug("User account is locked");
     
    				throw new LockedException(messages.getMessage(
    						"AbstractUserDetailsAuthenticationProvider.locked",
    						"User account is locked"));
    			}
     
    			if (!user.isEnabled()) {
    				logger.debug("User account is disabled");
     
    				throw new DisabledException(messages.getMessage(
    						"AbstractUserDetailsAuthenticationProvider.disabled",
    						"User is disabled"));
    			}
     
    			if (!user.isAccountNonExpired()) {
    				logger.debug("User account is expired");
     
    				throw new AccountExpiredException(messages.getMessage(
    						"AbstractUserDetailsAuthenticationProvider.expired",
    						"User account has expired"));
    			}
    		}
    	}
    Ce sont donc des tests pour savoir si l'User est non locked, enabled et non expired.

    Quand je regarde ma classe UserDetailsImpl qui implémente UserDetails, je peux m'apercevoir que ces trois informations peuvent être surchargées. J'ai donc fait un test : j'ai ajouté dans ma base une colonne NonLocked (de toute façon ça peut être utile). Et j'ai donc ajouté dans ma classe UserDetailsImpl la gestion du AccountNonLocked. Si je fais ça, c'est bien, ça passe le premier test. Cependant, je du mal à imaginer qu'il faut que je surcharge aussi enabled et accountNonExpired...

    Est-ce utile ? Si oui, je suppose que nonexpired fait référence à une durée de session, dans ce cas, pourquoi le surchargé ?

    Ma classe ressemble à ça maintenant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
     
    public class UserDetailsImpl implements UserDetails {
     
    	/** The Constant serialVersionUID. */
    	private static final long serialVersionUID = 1L;
     
    	/** The _username. */
    	private String username;
     
    	/** The _password. */
    	private String password;
     
    	/** User is locked ? */
    	private boolean accountNonLocked;
     
    	public UserDetailsImpl(User user) {
    		username = user.getLogin();
    		password = user.getPwd();
    		// ATTENTION : Si locked=F pour false, alors on renvoi true car accountNONlocked
    		accountNonLocked = "F".equals(user.getLocked()) ? true : false;
    	}
     
    	/**
             * @param password the password to set
             */
    	public void setPassword(String password) {
    		this.password = password;
    	}
     
    	@Override
    	public Collection<? extends GrantedAuthority> getAuthorities() {
    		// TODO Auto-generated method stub
    		return null;
    	}
     
    	@Override
    	public String getPassword() {
    		// TODO Auto-generated method stub
    		return null;
    	}
     
    	/**
             * @param username the username to set
             */
    	public void setUsername(String username) {
    		this.username = username;
    	}
     
    	@Override
    	public String getUsername() {
    		// TODO Auto-generated method stub
    		return null;
    	}
     
    	@Override
    	public boolean isAccountNonExpired() {
    		// TODO Auto-generated method stub
    		return false;
    	}
     
    	/**
             * @param accountNonLocked the accountNonLocked to set
             */
    	public void setAccountNonLocked(boolean accountNonLocked) {
    		this.accountNonLocked = accountNonLocked;
    	}
     
    	@Override
    	public boolean isAccountNonLocked() {
    		return accountNonLocked;
    	}
     
    	@Override
    	public boolean isCredentialsNonExpired() {
    		// TODO Auto-generated method stub
    		return false;
    	}
     
    	@Override
    	public boolean isEnabled() {
    		// TODO Auto-generated method stub
    		return false;
    	}
     
    }
    Autre question : dans une réponse plus haut tu avais écrit "Attention ! tes login mot de passe doivent être hasher (en Bcrypt par défaut).". Pense-tu que ce soit mieux que je crypte en javascript (si c'est possible) avant l'envoi ou que je le fasse en Java dans le webservice ? (pour la création de l'user bien évidemment, je pense que l'authentification le fait tout seul ça).

    Merci d'avance

  7. #7
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 274
    Points : 4 141
    Points
    4 141
    Par défaut
    La bonne pratique est de hasher le mot de passe sur le serveur en Java et d'utiliser HTTPS pour le transférer de manière sécurisée.
    Ne jamais faire confiance à ce qu'envoie le client (navigateur ou autre).

  8. #8
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2009
    Messages : 391
    Points : 185
    Points
    185
    Par défaut
    Citation Envoyé par fr1man Voir le message
    La bonne pratique est de hasher le mot de passe sur le serveur en Java et d'utiliser HTTPS pour le transférer de manière sécurisée.
    Ne jamais faire confiance à ce qu'envoie le client (navigateur ou autre).
    Merci .

    C'est presque bon grâce à vous tous .

    Ça fonctionne presque .

    Ça fonctionne quand je test avec un user qui a un password en clair dans la base, mais si je tente de me connecter avec un user qui a un password crypté (BCryptage), ça ne fonctionne pas. J'ai trouvé la portion de code qui posait problème (dans une des classes fournies par Spring Sec.) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
     
        // [...]
     
    	@SuppressWarnings("deprecation")
    	protected void additionalAuthenticationChecks(UserDetails userDetails,
    			UsernamePasswordAuthenticationToken authentication)
    			throws AuthenticationException {
    		Object salt = null;
     
            /* ISSUE : saltSource is null */
    		if (this.saltSource != null) {
                /* ISSUE : Moreover, my class UserDetailsImpl which implement UserDetails has no salt attribute */
    			salt = this.saltSource.getSalt(userDetails);
    		}
     
    		if (authentication.getCredentials() == null) {
    			logger.debug("Authentication failed: no credentials provided");
     
    			throw new BadCredentialsException(messages.getMessage(
    					"AbstractUserDetailsAuthenticationProvider.badCredentials",
    					"Bad credentials"));
    		}
     
    		String presentedPassword = authentication.getCredentials().toString();
     
            /* ISSUE : Has salt is null, authentication with crypted password doesn't work */
    		if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
    				presentedPassword, salt)) {
    			logger.debug("Authentication failed: password does not match stored value");
     
    			throw new BadCredentialsException(messages.getMessage(
    					"AbstractUserDetailsAuthenticationProvider.badCredentials",
    					"Bad credentials"));
    		}
    	}
     
        // [...]
    }
    Mais je cherche encore sur la solution.

    Une idée ?

    Merci encore.

  9. #9
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2009
    Messages : 391
    Points : 185
    Points
    185
    Par défaut
    Ça y est, ça fonctionne. Quel prise de tête toute cette configuration >_<...

    Pour information, il a fallu que j'ajoute :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    		@Override
    		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
     
    			ReflectionSaltSource rss = new ReflectionSaltSource();
    			rss.setUserPropertyToUse("salt");
    			DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
    			daoAuthenticationProvider.setSaltSource(rss);
    			daoAuthenticationProvider.setUserDetailsService(userDetailsService);
    			daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
     
    			//auth.userDetailsService(userDetailsService);
     
    			auth.authenticationProvider(daoAuthenticationProvider);
    		}
    dans ma classe de configuration.

    Ensuite, il a fallu que j'ajoute un champ "private String salt" dans mon UserDetails avec son getter qui renvoi null...

    Et maintenant, la magie de Spring fait que ça fonctionne.

    Merci à vous pour votre aide précieuse .

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Utilisation de Spring Security 3 avec JSF 2
    Par _sept_ dans le forum JSF
    Réponses: 2
    Dernier message: 10/08/2011, 12h51
  2. [Security] spring security authentification
    Par smiles dans le forum Spring
    Réponses: 5
    Dernier message: 27/04/2010, 13h32
  3. Réponses: 1
    Dernier message: 11/09/2009, 15h46
  4. [Spring Security] Authentification par groupe LDAP
    Par titeuf92 dans le forum Spring Web
    Réponses: 2
    Dernier message: 25/06/2008, 10h28
  5. [MySQL] Authentification avec MYSQL ?
    Par Kenshin86 dans le forum PHP & Base de données
    Réponses: 15
    Dernier message: 23/03/2007, 21h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo