breakline
breakline

Reputation: 6073

Spring Oauth2 with client_credentials does not validate user

I'm trying to setup a simple Oauth2 Server with Spring Boot with only client_credentials flow for now, using in memory users and clients etc. Basically the most basic project so I can build on it. Haven't used Oauth2 with Spring for some time so I'm a bit stuck. I can get access tokens but it seems Spring does not actually validate the username/password sent by the client. Here are the two config classes (AuthorizationServerConfigurerAdapter, WebSecurityConfigurerAdapter):

@Configuration
@EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {

   private final AuthenticationManager authenticationManager;

   private final PasswordEncoder passwordEncoder;

   private final UserDetailsService userService;

   @Value("${jwt.signing-key}")
   private String jwtSigningKey;

   @Value("${jwt.accessTokenValidititySeconds}")
   private int accessTokenValiditySeconds;

   @Value("${jwt.refreshTokenValiditySeconds}")
   private int refreshTokenValiditySeconds;

   public OAuthConfiguration(AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder, UserDetailsService userService) {
       this.authenticationManager = authenticationManager;
       this.passwordEncoder = passwordEncoder;
       this.userService = userService;
   }

   @Override
   public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
       clients.inMemory()
               .withClient("test-client-id")
               .secret(passwordEncoder.encode("test-client-secret"))
               .accessTokenValiditySeconds(accessTokenValiditySeconds)
               .refreshTokenValiditySeconds(refreshTokenValiditySeconds)
               .authorizedGrantTypes("client_credentials")
               .scopes("read", "write")
               .resourceIds("api");
   }

   @Override
   public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
       endpoints
               .accessTokenConverter(accessTokenConverter())
               .userDetailsService(userService)
               .authenticationManager(authenticationManager);
   }

   @Bean
   JwtAccessTokenConverter accessTokenConverter() {
       JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
       converter.setSigningKey(jwtSigningKey);
       return converter;
   }

}

and:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

   public WebSecurityConfiguration(CustomAuthenticationEntryPoint customAuthenticationEntryPoint) {
       this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
   }

   @Bean
   public DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService) {
       DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
       provider.setPasswordEncoder(passwordEncoder());
       provider.setUserDetailsService(userDetailsService);
       return provider;
   }

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

    @Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

    @Bean
   @Override
   public AuthenticationManager authenticationManagerBean() throws Exception {
       return super.authenticationManagerBean();
   }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user1")
            .password("$2a$10$sWszOXuTlN0amQi8vXp4cerb.tJUQo.4FzLAnTCsSqChsYhlLdQWW")
            .roles("USER");
    }

    @Override
   protected void configure(HttpSecurity http) throws Exception {
       http
               .cors().disable().csrf().disable()
               .authorizeRequests()
               .anyRequest().authenticated()
               .and().exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint).accessDeniedHandler(new CustomAccessDeniedHandler());
   }

}

So I can call the "/oauth/token" endpoint with any username/password I get an access token. However the client ID and client secret are being validated.

Any help is appreciated

Upvotes: 1

Views: 882

Answers (1)

b.s
b.s

Reputation: 2755

It's the default behaviour with grant_type client_credentials. So, you don't need to pass the username and password to the token endpoint with this grant_type. In this flow, AuthorizationServer will only validate the client Id and client secret.

POST /token 
Host: authorization-server.com
 
grant_type=client_credentials
&client_id=xxxxxxxxxx
&client_secret=xxxxxxxxxx

Upvotes: 0

Related Questions