spring-projects / spring-projects/spring-security

JwtIssuerReactiveAuthenticationManagerResolver not resolving

Open
#12,938 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage type: bug
Dominant language
Java
Stars
9.6k
Forks
6.3k
Avg merge
2d 11h
Merged PRs (30d)
52

Description

Describe the bug
Spring security authenticates when using single tenancy with:

  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri:

but the same url doesn't work with multi-tenancy.

To Reproduce
So following the multi-tenancy guide: here.

I have followed the steps and added:
the authentication manager (fake uri):

    JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver
        ("https://jwt.com/token.json");

with the new oauth2ResourceServer:

        .oauth2ResourceServer(oauth2 -> oauth2.
            authenticationManagerResolver(authenticationManagerResolver));

but the code always returns 401. When using the same uri in the single tenancy, it worked successfully, so I am not sure what I am missing. Here is the old way.

yaml:

    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: https://jwt.com/token.json

with the implementation:

        .oauth2ResourceServer(oauth2 -> oauth2.
            jwt(Customizer.withDefaults()));

This successfully authenticates.

I do see a difference in the logs as well.

With the authenticationResolver:

2023-03-21 11:46:11.085 DEBUG 15271 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [cabda122-1] HTTP GET "/api/v1/redacted"
2023-03-21 11:46:11.136 DEBUG 15271 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [cabda122-1] Completed 401 UNAUTHORIZED

and the old way clearly calls the resource server and decodes:

2023-03-21 11:41:53.843 DEBUG 12500 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [963bfd7a-1] HTTP GET "/api/v1/redacted"
2023-03-21 11:41:53.932 DEBUG 12500 --- [ctor-http-nio-3] o.s.w.r.f.client.ExchangeFunctions       : [4740b9ba] HTTP GET https://jwt.com/token.json
2023-03-21 11:41:54.695 DEBUG 12500 --- [ctor-http-nio-3] o.s.w.r.f.client.ExchangeFunctions       : [4740b9ba] [3475d267-1, L:/10.26.8.242:58490 - R:jwt.com/99.64.754.467:443] Response 200 OK
2023-03-21 11:41:54.713 DEBUG 12500 --- [ctor-http-nio-3] o.s.core.codec.StringDecoder             : [4740b9ba] [3475d267-1, L:/10.26.8.242:58490 - R:jwt.com/99.64.754.467:443] Decoded "REDACTED"
2023-03-21 11:41:54.736 DEBUG 12500 --- [     parallel-1] o.s.w.s.s.DefaultWebSessionManager       : Created new WebSession.
2023-03-21 11:41:55.090 DEBUG 12500 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [963bfd7a-1] Completed 200 OK

So what am I missing to have the multi-tenant way actually use the resource server? I don't see any mentions in the docs.

Here is a full example of the code:


Expected behavior
A clear and concise description of what you expected to happen.

Sample

@EnableWebFluxSecurity
public class SecurityConfig {

  private interface GatewayRoutes {
    String ACTUATOR = "/actuator/**";
    String METRICS = "/actuator/prometheus";
  }

  private interface ActuatorScopes {
    String METRICS_SCOPE = "SCOPE_urn:cable:scope:metrics";
  }

  private interface TimelineApiRoutes {
    String ENTITIES = "/api/v2/entity/**";
    String ALL_REMAINING_ROUTES = "/**";
  }

  private interface TimelineApiScopes {
    String TIMELINE_SCOPE = "SCOPE_urn:cable:scope:timeline";
  }

  public SecurityConfig() throws InstantiationException, IllegalAccessException {}

  @Bean
  SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver =
        new JwtIssuerReactiveAuthenticationManagerResolver(
            "https://jwt.com/token.json");

    http.authorizeExchange(
            (exchanges) ->
                exchanges
                    .pathMatchers(ApiRoutes.ENTITIES)
                    .hasAuthority(ApiScopes.API_SCOPE)
                    .pathMatchers(ApiRoutes.ALL_REMAINING_ROUTES)
                    .permitAll()
                    .anyExchange()
                    .authenticated())
        .oauth2ResourceServer(
            oauth2 ->
                oauth2
                    .authenticationManagerResolver(authenticationManagerResolver));
    return http.build();
  }
}

Apologies as this is an internal ResourceServer, I don't have an example to work with fully.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with JwtIssuerReactiveAuthenticationManagerResolver and the reactive oauth2ResourceServer authenticationManagerResolver configuration shown in the issue. Compare its behavior with the working jwt configuration and the linked reactive multitenancy guide; done means reproducing the 401 and identifying the missing or incorrect resolver behavior with a regression test.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
authentication, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.