0

I have a quite simple auth system based on SpringSecurity and quite similar to what's found here (a bit more complex).

Nevertheless, when I do the logon procedure, SpringSecurity throws a Bad Credentials error, according to its configuration.

Looking throught the code, I couldn't find what's the reason, because at runtime username, password, enabled and roles are according to what is stored in DB. Thus, I think that it could be derived from bad configuration or a matter of logic.

The only thing that may be a fail, according to log, is: WARNING: Encoded password does not look like BCrypt, but I read that it can be normal to every authentication.

Could anybody help-me to inspect configuration? Thanks!!

package com.company.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("userDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

@Bean
public PasswordEncoder passwordEncoder() {
    PasswordEncoder encoder = new BCryptPasswordEncoder();
    return encoder;
}


@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
            .antMatchers("**/admin/**").access("hasAnyRole('ROLE_ADMIN','ROLE_SUPERADMIN')")
            .antMatchers("/superadmin/**").access("hasRole('ROLE_SUPERADMIN')")
            .antMatchers("**/user/**").access("hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_SUPERADMIN')")
            .antMatchers("/resources/**").permitAll()
            .antMatchers("/messages/**").permitAll() 
            .and()
            .formLogin()
                .loginPage("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .defaultSuccessUrl("/user/home")
                .failureUrl("/403")
                .permitAll()
            .and()
                .exceptionHandling().accessDeniedPage("/403")
            .and()
                .logout().logoutUrl("/logout")
            .and()
                .csrf().disable();
    }
}

package com.company.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.company.dao.UsuarioDao;
import com.company.model.UserRole;
import com.company.model.Usuario;

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService{

    @Autowired
    private UsuarioDao usuarioDao;


    @Transactional(readOnly=true)
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        Usuario usuario = usuarioDao.findByChave(username);
        List<GrantedAuthority> authorities = buildUserAuthority(usuario.getUserRole());

        return buildUserForAuthentication(usuario, authorities);

    }

    private User buildUserForAuthentication(Usuario user, 
        List<GrantedAuthority> authorities) {

        User usr= new User(user.getUsername(), user.getPassword(), 
            user.isEnabled(), true, true, true, authorities);

        System.out.println(usr.toString());
/*
* Prints: org.springframework.security.core.userdetails.User@ae6e27ef: 
* Username: SMITH; Password: [PROTECTED]; Enabled: true; 
* AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: 
* true; Not granted any authorities
*/

        return usr;

    }

    private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles){

        Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

        // Build user's authorities
        for (UserRole userRole : userRoles) {
            setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
        }

        List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

        return Result;  
    }

}
Alex
  • 3,325
  • 11
  • 52
  • 80
  • 2
    If you get that message, it means that what you receive from the database, as password isn't what is expected. Check the encoding, field length... Check the actual value... Apparently you aren't storing the correct hash, that is what that message is telling you. – M. Deinum Apr 05 '16 at 19:00
  • @M.Deinum, problem discovered. If you'd like to view the answer, I think it is valuable. Thanks for the interest. – Alex Apr 06 '16 at 16:12

1 Answers1

0

After some research, I discovered the issue. I'm dealing with an already encripted password provided by third party. Thus, I was storing it directly in DB, while SpringSecurity was working with its own encryption (BCrypt). Thus, SpringSecurity was comparying two different encripted strings, generating the issue (a good tip was given in the WARNING message mentioned in the question).

This way, I disabled the @Bean PasswordEncoder in AppSecurityConfig for it is not necessary to keep it (remember I am already dealing with pre-encripted passwords). After that, stuff worked fine.

For more information, it's valuable take a look in this questions and answers:

Community
  • 1
  • 1
Alex
  • 3,325
  • 11
  • 52
  • 80