I am trying to implement a spring AuthorizationServer with JWT. I was able to produce JWT tokens and login until I added BCrypt to the mix. Now, when I am trying to login, I get "Bad credentials" from the API.
OAuth2Configuration.java
@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
private DataSource dataSource;
private AuthenticationManager authenticationManager;
private BCryptPasswordEncoder passwordEncoder;
public OAuth2Configuration(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
this.dataSource = new Jdbc3PoolingDataSource();
this.passwordEncoder = new BCryptPasswordEncoder();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("api-client")
.secret("verysecretivesecret")
.scopes("READ", "WRITE", "DELETE")
.authorizedGrantTypes("implicit", "refresh_tokens", "password", "authorization_code");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authorizationCodeServices(authorizationCodeServices())
.tokenStore(tokenStore())
.tokenEnhancer(jwtTokenEnhancer())
.authenticationManager(authenticationManager);
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
@Bean
protected JwtAccessTokenConverter jwtTokenEnhancer() {
return new JwtAccessTokenConverter();
}
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
}
WebSecurityConfig.java
@Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private AccountDetailsService accountDetailsService;
private BCryptPasswordEncoder passwordEncoder;
private DataSource dataSource;
WebSecurityConfig(AccountDetailsService accountDetailsService) {
this.accountDetailsService = accountDetailsService;
this.dataSource = new Jdbc3PoolingDataSource();
this.passwordEncoder = new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(accountDetailsService).passwordEncoder(passwordEncoder).and().jdbcAuthentication().dataSource(dataSource);
}
}
SeedData.java
@Override
public void run(String... args) throws Exception {
Stream.of("alan,test").map(x -> x.split(","))
.forEach(tuple -> {
Account user = new Account();
user.setUsername(tuple[0]);
user.setPassword(new BCryptPasswordEncoder().encode(tuple[1]));
user.setEmail(tuple[0]);
user.setRoles(Collections.singletonList(role));
user.setActive(true);
this.accountRepository.save(user);
});
}
Thanks for your help.
To fix the login issue and get rid of the warning “Encoded password does not look like BCrypt”, either remove the {bcrypt} prefix or remove the password encoder declaration.
There are a few encoding mechanisms supported by Spring Security, and for this tutorial, we'll use BCrypt, as it's usually the best solution available.
Spring Security supports many password encoders, for both old and modern algorithms. Also, Spring Security provides methods to work with multiple password encodings in the same application.
Class NoOpPasswordEncoder. Deprecated. This PasswordEncoder is not secure. Instead use an adaptive one way function like BCryptPasswordEncoder, Pbkdf2PasswordEncoder, or SCryptPasswordEncoder.
I needed to make the following change to get it to work. If anyone else needs it.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(accountDetailsService)
.passwordEncoder(passwordEncoder)
.and()
.authenticationProvider(authenticationProvider())
.jdbcAuthentication()
.dataSource(dataSource);
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(accountDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder);
return authenticationProvider;
}
This is because you applied a BCrypt both to WebSecurity and AuthorizationServer. So you need to keep not only BCrypt encrypted user passwords in your store, but also BCrypt encrypted client secrets for OAuth2. I guess this was not what you tried to approach.
In order to make your code working, either remove
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
}
or manually encrypt your "verysecretivesecret"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With