почему весенняя безопасность дает пустой пароль для кодировщика паролей? - PullRequest
1 голос
/ 31 мая 2019

Я использую Spring Security с BCrypt Password Encoder для аутентификации. Когда я хочу войти в систему, Spring Security правильно выбирает данные пользователя с помощью JPA, но для проверки необработанного пароля с зашифрованным паролем в кодировщике паролей возвращается пустая строка.

Конфигурация безопасности пружины:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService)
        .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").hasAuthority("USER")
                .antMatchers("/css/**","/font/**","/js/**","/image/**").permitAll()
                .antMatchers("/register").permitAll()
                .and().formLogin().loginPage("/login").successForwardUrl("/").permitAll()
                .and().logout().logoutSuccessUrl("/login");
    }
}

userDetailsServise:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    private UserRepository userRepo;

    @Autowired
    public UserDetailsServiceImpl(UserRepository userRepo){
        this.userRepo = userRepo;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
         User user = userRepo.findByUsername(username);
         if(user != null) {
             System.out.println(user.toString());
             return user;
         }
         throw new UsernameNotFoundException("User "+ username +" not found");
    }
}

пользовательская сущность:

@Entity
@Table(name = "users")
public class User implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
    @SequenceGenerator(name = "user_seq", sequenceName = "users_id_seq",allocationSize = 1)
    private long id;

    @NotEmpty
    @Column(nullable = false, unique=true)
    private String username;

    @Email
    @Column(nullable = false, updatable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private boolean enabled;

    @CreationTimestamp
    @Column(name = "creation_time")
    private Timestamp creationTime;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(joinColumns = @JoinColumn(name="user_id"))
    private List<Authority> authorities;
...

пиловочник:

2019-05-31 19:51:58.888 DEBUG 7181 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication
2019-05-31 19:51:58.889 DEBUG 7181 --- [nio-8080-exec-3] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2019-05-31 19:51:59.245 DEBUG 7181 --- [nio-8080-exec-3] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-05-31 19:51:59.388  INFO 7181 --- [nio-8080-exec-3] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_1_, user0_.creation_time as creation2_1_, user0_.email as email3_1_, user0_.enabled as enabled4_1_, user0_.password as password5_1_, user0_.username as username6_1_ from users user0_ where user0_.username=?
Hibernate: select authoritie0_.user_id as user_id1_0_0_, authoritie0_.authorities as authorit2_0_0_ from user_authorities authoritie0_ where authoritie0_.user_id=?
User{
id=8
, username='username'
, email='mail@example.com'
, password='$2a$10$TyQ8x0KUP9Nrtzo2ljfNfei4S3h1kFpYEb5/CDs2lKSDzMJECQ./q'
, enabled=true
, creationTime=2019-05-31 19:32:12.948
, authorities=[USER]}
2019-05-31 19:51:59.758  WARN 7181 --- [nio-8080-exec-3] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Empty encoded password
2019-05-31 19:51:59.758 DEBUG 7181 --- [nio-8080-exec-3] o.s.s.a.dao.DaoAuthenticationProvider    : Authentication failed: password does not match stored value
2019-05-31 19:51:59.773 DEBUG 7181 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials

Я создаю следующий кодировщик паролей и выясняю, что Spring Security дает нулевую строку в качестве закодированного пароля для кодировщика паролей.

@Component
public class MyPasswordEncoder implements PasswordEncoder {

    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    @Override
    public String encode(CharSequence rawPassword) {
        return encoder.encode(rawPassword);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {

        System.out.println("raw password: " + rawPassword + "\t encoded passwod: "+ encodedPassword);

        return encoder.matches(rawPassword,encodedPassword);
    }
}

Журналы с пользовательским паролем:

2019-06-01 03:19:52.759 DEBUG 7870 --- [nio-8080-exec-5] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication
2019-06-01 03:19:52.759 DEBUG 7870 --- [nio-8080-exec-5] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2019-06-01 03:19:53.036 DEBUG 7870 --- [nio-8080-exec-5] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-06-01 03:19:53.095  INFO 7870 --- [nio-8080-exec-5] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_1_, user0_.creation_time as creation2_1_, user0_.email as email3_1_, user0_.enabled as enabled4_1_, user0_.password as password5_1_, user0_.username as username6_1_ from users user0_ where user0_.username=?
Hibernate: select authoritie0_.user_id as user_id1_0_0_, authoritie0_.authorities as authorit2_0_0_ from user_authorities authoritie0_ where authoritie0_.user_id=?
User{
id=8
, username='username'
, email='mail@example.com'
, password='$2a$10$TyQ8x0KUP9Nrtzo2ljfNfei4S3h1kFpYEb5/CDs2lKSDzMJECQ./q'
, enabled=true
, creationTime=2019-05-31 19:32:12.948
, authorities=[USER]}
raw password: password   encoded passwod: null
2019-06-01 03:19:53.413  WARN 7870 --- [nio-8080-exec-5] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Empty encoded password
2019-06-01 03:19:53.413 DEBUG 7870 --- [nio-8080-exec-5] o.s.s.a.dao.DaoAuthenticationProvider    : Authentication failed: password does not match stored value
2019-06-01 03:19:53.415 DEBUG 7870 --- [nio-8080-exec-5] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials

полный исходный код на github: https://github.com/yrostami/spring_sample

1 Ответ

0 голосов
/ 01 июня 2019

BCryptPasswordEncoder сравнит пароль от загруженного пользователя с паролем, введенным в форме входа в систему, чтобы увидеть, совпадают ли они. Если значение равно нулю, оно выдаст Empty encoded password предупреждение.

Итак, глядя на то, как вы загружаете пользователей, получается, что ваш UserDetailsService всегда будет возвращать User с нулевым паролем , потому что вы жестко закодировали его в getPassword() (Btw, getUsername() также имеет ту же проблему). Поэтому изменение на следующее должно исправить это:

@Override
public String getPassword() {
    return this.password;
}

@Override
public String getUsername() {
    return this.username;
}
...