Search code examples
spring-bootkotlinspring-securityoauth-2.0jwt

JwtDecoder bean is not injected automatically while setting a ressource server using 'spring-boot-starter-oauth2-resource-server'


I am setting a resource server using the 'spring-boot-starter-oauth2-resource-server':

implementation group: 'org.springframework.boot', name: 'spring-boot-starter-oauth2-resource-server'

I have set a simple Security config like this:

@Configuration
@EnableWebSecurity
class EndpointsSecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(web: WebSecurity) {
        web.ignoring().antMatchers("/live")
    }

    override fun configure(http: HttpSecurity?) {
        http?.cors()
        http?.sessionManagement()?.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        http?.csrf()?.disable()
        http
            ?.authorizeRequests()
            ?.anyRequest()
            ?.authenticated()
            ?.and()
            ?.oauth2ResourceServer()
            ?.jwt()
    }
}

And in my application.yml I added the issuer-uri like this :

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://cognito-idp.${AWS_REGION:eu-central-1}.amazonaws.com/${COGNITO_USER_POOL_ID:testUserPoolId}

As I have seen in many tutorials and in the official doc this config is minimalistic and should work out of the box without any extra configs, but my application fails to start with the following error :

Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.oauth2.jwt.JwtDecoder' available
   at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656)

So the problem here is that the JwtDecoder bean is not found even though it is declared in the OAuth2ResourceServerJwtConfiguration class and is conditioned by the issuer-uri which I have set in my application.yml.

As a workaround I redeclared the bean myself like this :

@Configuration
@EnableWebSecurity
class EndpointSecurityConfig(@Value("\${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private val issuerUri: String) : WebSecurityConfigurerAdapter() {

    override fun configure(web: WebSecurity) {
        web.ignoring().antMatchers("/live")
    }

    override fun configure(http: HttpSecurity?) {
        http?.cors()
        http?.sessionManagement()?.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        http?.csrf()?.disable()
        http
            ?.authorizeRequests()
            ?.anyRequest()
            ?.authenticated()
            ?.and()
            ?.oauth2ResourceServer()
            ?.jwt()
    }

    @Bean
    @Conditional(IssuerUriCondition::class)
    fun jwtDecoderByIssuerUri(): JwtDecoder? {
        return JwtDecoders.fromIssuerLocation(issuerUri)
    }
}

And this is working, but I couldn't figure out why the out-of-the-box config is not working for me?

Update: gradle config


plugins {
    id 'java'
    id "io.spring.dependency-management" version "1.0.9.RELEASE"
    id "org.springframework.boot" version "2.2.5.RELEASE"
    id "org.owasp.dependencycheck" version "6.0.2"
}

// irrelevent details

dependencies {
    ktlint "com.pinterest:ktlint:0.34.2"

    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: '1.3.70'
    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.3.70'
    implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.3.0'

    implementation group: 'org.springframework.boot', name: 'spring-boot-starter', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-log4j2', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.3.4.RELEASE'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-oauth2-resource-server', version: '2.3.4.RELEASE'

    implementation group: 'com.amazonaws', name: 'aws-java-sdk-secretsmanager', version: "1.11.875"

    implementation group: 'com.oracle.database.jdbc', name: 'ojdbc8', version: "19.7.0.0"

    implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.10.2'

    implementation group: 'org.springdoc', name: 'springdoc-openapi-kotlin', version: '1.4.3'
    implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.4.3'

    runtime group: 'com.h2database', name: 'h2', version: '1.4.194'

    testImplementation group: 'io.mockk', name: 'mockk', version: '1.9.3'
    testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.3.4.RELEASE'
    testImplementation group:'org.springframework.security', name: 'spring-security-test'
}


Solution

  • I found out that there was a problem with the gradle config of project I am working on (updated the question). The spring boot dependencies were declared with the version '2.3.4.RELEASE' while the org.springframework.boot plugin version was "2.2.5.RELEASE" and I think that must have led to some sort of incompatibility between spring dependencies.

    As a solution, I removed the version declaration from the spring dependencies and set the plugin version to '2.3.4.RELEASE' and now the error is gone and the oauth2 resource server config works without any extra config.

    NB:

    I noticed that when I keep the plugin version at "2.2.5.RELEASE" the error persist and the out of the box config doesn't work unless I remove the plugin io.spring.dependency-management.