Expected Behavior

I am using Springboot starter (2.3.3.RELEASE) and the class OAuth2ResourceServerConfigurer brought in by spring-security-config-5.3.4.RELEASE is marked final and does not have any method for fetching the configurer being used (JWT or Opaque). I am presently having a need to get the type of configurer being set by OAuth2ResourceServerConfigurer and do something specific to each flow (JWT or Opaque Token). Since the class is marked final, I am unable to extend it and customize it to fit my need. Any thoughts on how to handle this? Would it be possible to make it non-final (unaware of the side effects).

Current Behavior

  • OAuth2ResourceServerConfigurer is final.
  • No way to get the currently used configurer instance.

Context

Comment From: jzheaux

Hi, @arvindkrishnakumar-okta. Can you share some code to illustrate what it is you'd like to be able to do with the code, say if OAuth2ResourceServerConfigurer were no longer final?

Comment From: arvindkrishnakumar-okta

@jzheaux I'm looking to get a handle of the configurer and determine which of JWT or Opaque token is being configured by Spring internally.

I was able to use customizer with some ugly reflection code to access the private method getAuthenticationProvider of OAuth2ResourceServerConfigurer class and separately handle the JWT and Opaque Token flows.

    @Override
    public void configure(HttpSecurity http) throws Exception {

        ...
        ...

        http.oauth2ResourceServer(httpSecurityOAuth2ResourceServerConfigurer -> {

            try {
                Method getAuthenticationProviderMethod =
                    OAuth2ResourceServerConfigurer.class.getDeclaredMethod("getAuthenticationProvider", null);
                getAuthenticationProviderMethod.setAccessible(true);

                AuthenticationProvider authenticationProvider =
                    (AuthenticationProvider) getAuthenticationProviderMethod.invoke(httpSecurityOAuth2ResourceServerConfigurer, null);

                if (authenticationProvider instanceof OpaqueTokenAuthenticationProvider) {
                    // Opaque Token case 
                   ...
                   ...
                    http.oauth2ResourceServer().opaqueToken();
                } else if (authenticationProvider instanceof JwtAuthenticationProvider) {
                    // JWT case
                    ...
                    ...
                    http.oauth2ResourceServer().jwt();
                }
            } catch (Exception e) {
                log.error("Error occurred while configuring resource server", e);
            }
        });

        ...
        ...
    }

But the problem with this code is that at runtime, I encounter the below exception:

Caused by: java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer@74fab04a to already built object
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:195)
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.apply(AbstractConfiguredSecurityBuilder.java:133)
    at org.springframework.security.config.annotation.web.builders.HttpSecurity.getOrApply(HttpSecurity.java:3028)
    at org.springframework.security.config.annotation.web.builders.HttpSecurity.oauth2ResourceServer(HttpSecurity.java:2362)

On further debugging, it looks like Spring tries to create a brand new configuration instead of overriding the existing one with the above customization as per this.

Comment From: jzheaux

Sorry, @arvindkrishnakumar-okta, I'm still unclear what you are trying to achieve. The code snippet seems circular since oauth2ResourceServer().jwt() is the thing that adds the JwtAuthenticationProvider.

It seems you'd want to use your own application environment, not the configurer's internal state, to determine JWT or Opaque Token.