Search code examples
spring-bootspring-securityspring-authorization-server

Spring OAuth2 authorization server: straightforward client_credentials unauthorized


I've deployed an spring-boot authorization server with this configuration:

application-loc.yaml:

server:
  port: 9090

logging:
  level:
    org.springframework.security: trace

management:
  endpoints:
    web:
      exposure:
        include: "*"

spring:
  security:
    oauth2:
      authorizationserver:
        client:
          oidc-client:
            registration:
              client-id: "rdocelec"
              client-secret: "{noop}xxx"
              client-authentication-methods:
                - "client_secret_basic"
              authorization-grant-types:
                - "client_credentials"
              scopes:
                - "api"
                - "adm"
            require-authorization-consent: true

My SecurityConfig.java:

package net.gencat.transversal.espaidoc.oautz.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.info.InfoEndpoint;

@EnableWebSecurity
@Configuration
public class SecurityConfiguration {

  @Bean
  @Order(1)
  public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
      throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
        .oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0

    return http.build();
  }

  @Bean
  @Order(2)
  public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
      throws Exception {
    http
        .csrf(csrfCustomizer -> csrfCustomizer.disable())
        .authorizeHttpRequests(
            authorize -> authorize
                .requestMatchers(
                    EndpointRequest.to(InfoEndpoint.class, HealthEndpoint.class, EnvironmentEndpoint.class,
                        ConfigurationPropertiesReportEndpoint.class))
                .permitAll().anyRequest().permitAll())
        // Form login handles the redirect to the login page from the
        // authorization server filter chain
        .formLogin(c -> c.disable());

    return http.build();
  }
}

Nevertheless, then I'm trying to get credentials using client_credentials grant_type, I'm getting:

❯ http localhost:9090/oauth2/token client_id='rdocelec' client_secret='xxx' grant_type='client_credenctials'
HTTP/1.1 401
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 0
Date: Sun, 19 Nov 2023 06:51:09 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0

authorization service logs:

2023-11-19T07:51:09.154+01:00 DEBUG 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Securing POST /oauth2/token
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking DisableEncodeUrlFilter (1/24)
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking WebAsyncManagerIntegrationFilter (2/24)
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderFilter (3/24)
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking AuthorizationServerContextFilter (4/24)
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking HeaderWriterFilter (5/24)
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking CsrfFilter (6/24)
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.csrf.CsrfFilter         : Did not protect against CSRF since request did not match And [CsrfNotRequired [TRACE, HEAD, GET, OPTIONS], Not [Or [org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer$$Lambda$694/0x000000080100f7d0@62aeddc8]]]
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OidcLogoutEndpointFilter (7/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking LogoutFilter (8/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.a.logout.LogoutFilter            : Did not match request to Ant [pattern='/logout', POST]
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationServerMetadataEndpointFilter (9/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationEndpointFilter (10/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2DeviceVerificationEndpointFilter (11/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OidcProviderConfigurationEndpointFilter (12/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking NimbusJwkSetEndpointFilter (13/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2ClientAuthenticationFilter (14/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking RequestCacheAwareFilter (15/24)
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.s.HttpSessionRequestCache        : matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderAwareRequestFilter (16/24)
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking AnonymousAuthenticationFilter (17/24)
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking ExceptionTranslationFilter (18/24)
2023-11-19T07:51:09.160+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking AuthorizationFilter (19/24)
2023-11-19T07:51:09.160+01:00 TRACE 38145 --- [nio-9090-exec-5] estMatcherDelegatingAuthorizationManager : Authorizing SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@71bd6231]
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] estMatcherDelegatingAuthorizationManager : Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@71bd6231] using org.springframework.security.authorization.AuthenticatedAuthorizationManager@61b6801
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
2023-11-19T07:51:09.162+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.a.ExceptionTranslationFilter     : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied

org.springframework.security.access.AccessDeniedException: Access Denied
        at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:98) ~[spring-security-web-6.1.0.jar:6.1.0]
        at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:238) ~[spring-security-web-6.1.0.jar:6.1.0]
        ...

2023-11-19T07:51:09.166+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.s.HttpSessionRequestCache        : Did not save request since it did not match [And [Ant [pattern='/**', GET], Not [Ant [pattern='/**/favicon.*']], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@50ef02ac, matchingMediaTypes=[application/json], useEquals=false, ignoredMediaTypes=[*/*]]], Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@50ef02ac, matchingMediaTypes=[multipart/form-data], useEquals=false, ignoredMediaTypes=[*/*]]], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@50ef02ac, matchingMediaTypes=[text/event-stream], useEquals=false, ignoredMediaTypes=[*/*]]]]]
2023-11-19T07:51:09.168+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match request to [Is Secure]

2023-11-19T07:51:09.154+01:00 DEBUG 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Securing POST /oauth2/token
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking DisableEncodeUrlFilter (1/24)
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking WebAsyncManagerIntegrationFilter (2/24)
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderFilter (3/24)
2023-11-19T07:51:09.155+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking AuthorizationServerContextFilter (4/24)
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking HeaderWriterFilter (5/24)
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking CsrfFilter (6/24)
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.csrf.CsrfFilter         : Did not protect against CSRF since request did not match And [CsrfNotRequired [TRACE, HEAD, GET, OPTIONS], Not [Or [org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer$$Lambda$694/0x000000080100f7d0@62aeddc8]]]
2023-11-19T07:51:09.156+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OidcLogoutEndpointFilter (7/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking LogoutFilter (8/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.a.logout.LogoutFilter            : Did not match request to Ant [pattern='/logout', POST]
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationServerMetadataEndpointFilter (9/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationEndpointFilter (10/24)
2023-11-19T07:51:09.157+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2DeviceVerificationEndpointFilter (11/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OidcProviderConfigurationEndpointFilter (12/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking NimbusJwkSetEndpointFilter (13/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking OAuth2ClientAuthenticationFilter (14/24)
2023-11-19T07:51:09.158+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking RequestCacheAwareFilter (15/24)
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.s.HttpSessionRequestCache        : matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderAwareRequestFilter (16/24)
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking AnonymousAuthenticationFilter (17/24)
2023-11-19T07:51:09.159+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking ExceptionTranslationFilter (18/24)
2023-11-19T07:51:09.160+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.security.web.FilterChainProxy        : Invoking AuthorizationFilter (19/24)
2023-11-19T07:51:09.160+01:00 TRACE 38145 --- [nio-9090-exec-5] estMatcherDelegatingAuthorizationManager : Authorizing SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@71bd6231]
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] estMatcherDelegatingAuthorizationManager : Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@71bd6231] using org.springframework.security.authorization.AuthenticatedAuthorizationManager@61b6801
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2023-11-19T07:51:09.161+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
2023-11-19T07:51:09.162+01:00 TRACE 38145 --- [nio-9090-exec-5] o.s.s.w.a.ExceptionTranslationFilter     : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied

org.springframework.security.access.AccessDeniedException: Access Denied
        at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:98) ~[spring-security-web-6.1.0.jar:6.1.0]
        ```

Any ideas?


Solution

  • According to the application-loc.yaml configuration file, the parameter passing for correct access to localhost:9090/oauth2/token should be as follows

    url: http://localhost:9090/oauth2/token

    method: post

    header: Authorization Basic cmRvY2VsZWM6eHh4

    parameter: grant_type=client_credentials

    On the other hand, your access parameter grant_type value has an extra letter c

    grant_type='client_credenctials'