I am new to OAuth2 and I am receiving a 401 Unauthorized when trying to obtain my access token through a password grant flow. My UserDetailsService is implemented with a MySQL database backend, but I never hit the loadUserByUsername method before I receive my 401 Unauthorized message, so I think it may be a problem with my OAuth2 configuration. My AuthorizationConfigurerAdapter is as follows:
...imports
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Value("${signing-key:oui214}")
private String signingKey;
public AuthorizationServerConfig() {
super();
}
// beans
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter jwtAccessTokenConverter = new
JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey(signingKey);
return jwtAccessTokenConverter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
return tokenServices;
}
// config
@Override
public void configure(final ClientDetailsServiceConfigurer clients)
throws Exception {
// @formatter:off
clients.inMemory()
.withClient("password-flow-client")
.secret("publicpass")
.authorizedGrantTypes("password")
.scopes("qlc-webapp")
.accessTokenValiditySeconds(3600 * 12);
// @formatter:on
}
@Override
public void configure(final AuthorizationServerEndpointsConfigurer
endpoints) {
// @formatter:off
endpoints.tokenStore(tokenStore()).
tokenEnhancer(tokenEnhancerChain).
authenticationManager(authenticationManager);
endpoints.tokenStore(tokenStore()).
authenticationManager(authenticationManager).
userDetailsService(userDetailsService).
allowedTokenEndpointRequestMethods(HttpMethod.GET,
HttpMethod.POST).accessTokenConverter(accessTokenConverter());
// @formatter:on
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security)
throws Exception {
security.checkTokenAccess("permitAll()");
super.configure(security);
}
}
My ResourceConfigurerAdapter is as follows:
...imports
@Configuration
@EnableResourceServer
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@ComponentScan({ "org.quickloanconnect.spring.security" })
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Value("${signing-key:oui214}")
private String signingKey;
public ResourceServerConfig() {
super();
}
// global security concerns
@Bean
public AuthenticationProvider authProvider() {
final DaoAuthenticationProvider authProvider = new
DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
return authProvider;
}
@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authProvider());
}
// http security concerns
@Override
public void configure(final HttpSecurity http) throws Exception {
// @formatter:off
http.
authorizeRequests().
// antMatchers("/oauth/token").permitAll().
anyRequest().authenticated().and().
sessionManagement().
sessionCreationPolicy(SessionCreationPolicy.STATELESS).
and().
csrf().disable();
// @formatter:on
}
}
MyUserDetailsService implementation of UserDetailsService
@Component
public final class MyUserDetailsService implements UserDetailsService {
@Autowired
private IUsersService userService;
public MyUserDetailsService() {
super();
}
@Override
public final UserDetails loadUserByUsername(final String username) {
Preconditions.checkNotNull(username);
final User user = userService.findUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Username was not found: " +
username);
}
return new
org.springframework.security.core.userdetails.User(username,
user.getPassword(), Lists.newArrayList());
}
I had this working with inMemory user setup (no user details service at that time), but when switching to the userDetailsService backend and eliminating my in memory user, my configuration does not seem to work and I get 401 Unauthorized. Are there changes in my configuration that I need to do now that I am using UserDetailsService? Am I missing something?