I am upgrading my existing Client Credentials Oauth2 to use spring boot 2.
The Authorization Server uses Basic Auth with Base64 encoding of (client:secret)
I am using RedisTokenStore to store the tokens.
I am struggling with the configuration required for Oauth2 configuration with the new upgrade. I could not find a proper documentation that points me to Client Credentials flow.
With updates to Spring 5 Security the password encoding is failing, I am getting :-
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" error
Following is my configuration:-
@Configuration
public class WebConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
csrf().disable().
authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
}
}
AuthorizationServer and ResourceServer
@Configuration
@EnableAuthorizationServer
public class Oauth2Configuration extends AuthorizationServerConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private JedisConnectionFactory jedisConnFactory;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
super.configure(endpoints);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
String idForEncode = "bcrypt";
Map<String, PasswordEncoder> encoderMap = new HashMap<>();
encoderMap.put(idForEncode, new BCryptPasswordEncoder());
return new DelegatingPasswordEncoder(idForEncode, encoderMap);
}
@Bean
public TokenStore tokenStore() {
return new Oauth2TokenStore(jedisConnFactory);
}
@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/verify_token").authenticated()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.GET, "/info").permitAll()
.antMatchers(HttpMethod.GET, "/health").permitAll();
}
}
}
RedisTokenStore
public class Oauth2TokenStore extends RedisTokenStore {
@Autowired
private ClientDetailsService clientDetailsService;
public Oauth2TokenStore(RedisConnectionFactory connectionFactory) {
super(connectionFactory);
}
@Override
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
Object principal = authentication.getPrincipal();
//Principal is consumer key since we only support client credential flow
String consumerKey = (String) principal;
//get client detials
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(consumerKey);
// Logic to Create JWT
.
.
.
//Set it to Authentication
authentication.setDetails(authToken);
super.storeAccessToken(token, authentication);
}
@Override
public OAuth2Authentication readAuthentication(String token) {
OAuth2Authentication oAuth2Authentication = super.readAuthentication(token);
if (oAuth2Authentication == null) {
throw new InvalidTokenException("Access token expired");
}
return oAuth2Authentication;
}
}
}
Also do I need to encode the token when I am storing in the redis store after the updates to spring security password encoding?
This error means that the password stored isn't prefixed with the password type.
For example, your hashed passwords might look something like:
$2a$10$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
But, Spring Security is now expecting:
{bcrypt}$2a$10$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
You basically have two options . The first is to configure your DelegatingPasswordEncoder
with what should be the default:
@Bean
public PasswordEncoder passwordEncoder() {
String idForEncode = "bcrypt";
BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
Map<String, PasswordEncoder> encoderMap =
Collections.singletonMap(idForEncode, bcrypt);
DelegatingPasswordEncoder delegating =
new DelegatingPasswordEncoder(idForEncode, encoderMap);
delegating.setDefaultPasswordEncoderForMatches(bcrypt);
return delegating;
}
Or the second is to do a batch upgrade of your password store (prefixing them with {bcrypt}
).
I'm not certain what your ClientDetailsService
is pulling from, but I would begin looking there.
UPDATE : This assumes, though, that your existing passwords are bcrypted. If they aren't, then you'd supply whatever the appropriate encoder is:
@Bean
public PasswordEncoder passwordEncoder() {
String idForEncode = "bcrypt";
PasswordEncoder existing = new MyPasswordEncoder();
PasswordEncoder updated = new BCryptPasswordEncoder();
Map<String, PasswordEncoder> encoderMap =
Collections.singletonMap(idForEncode, updated);
DelegatingPasswordEncoder delegating =
new DelegatingPasswordEncoder(idForEncode, encoderMap);
delegating.setDefaultPasswordEncoderForMatches(existing);
return delegating;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.