spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.57k stars 40.55k forks source link

Reactive Method Security not working with kotlin from Spring boot version 3.0.3 :The returnType class java.lang.Object on public java.lang.Object #34562

Closed elenavanengelenmaslova closed 1 year ago

elenavanengelenmaslova commented 1 year ago

When using reactive method security on a Kotlin spring boot reactive app with coroutines, I am getting an error

The returnType class java.lang.Object on public java.lang.Object 
java.lang.IllegalStateException: The returnType class java.lang.Object on public java.lang.Object nl.vintik.sample.spring.resource.HelloController.hello(kotlin.coroutines.Continuation) must return an instance of org.reactivestreams.Publisher (for example, a Mono or Flux) in order to support Reactor Context
    at org.springframework.util.Assert.state(Assert.java:97) ~[spring-core-6.0.6.jar:6.0.6]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ⇢ Handler nl.vintik.sample.spring.resource.HelloController#hello(Continuation) [DispatcherHandler]
    *__checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.csrf.CsrfWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
    *__checkpoint ⇢ HTTP GET "/kolin-webflux-rest/v1/hello" [ExceptionHandlingWebHandler]

I am using @EnableReactiveMethodSecurity and @PreAuthorize and spring boot version 3.0.4. With 3.0.3 version same issue, but 3.0.2 issues is not present and all works.

I have reproduced the issue with a hello world example:

@RestController
@RequestMapping("/v1")
class HelloController : Api {

    @Operation(summary = "Get Hello")
    @GetMapping("/hello")
    @PreAuthorize("isAuthenticated()")
    suspend fun hello(): String {
        log.debug { "Hello World!" }
        return "Hello World!"
    }

    @ExceptionHandler(org.springframework.security.access.AccessDeniedException::class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    fun handleException(accessDenied: org.springframework.security.access.AccessDeniedException) {
        log.info ("API call failed", accessDenied)
    }
    companion object {
        val log = KotlinLogging.logger {}
    }
}
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
class SecurityConfig{
    @Bean
    fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http {
           formLogin { disable() }
        }
    }
}

with gradle dependencies:

plugins {
    val springVersion = "3.0.4"
    val kotlinVersion = "1.8.10"
    val openApiGeneratorVersion = "6.4.0"
    val dependencyManagementVersion = "1.1.0"
    kotlin("plugin.spring") version kotlinVersion
    id("org.springframework.boot") version springVersion
    kotlin("jvm") version kotlinVersion
    id("io.spring.dependency-management") version dependencyManagementVersion
    id("org.openapi.generator") version openApiGeneratorVersion
    idea
}

group = "nl.vintik.sample.spring"
version = "0.0.1-SNAPSHOT"

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

dependencies {
    val springdocVersion= "2.0.2"
    val kotlinLoggingVersion = "3.0.5"
    implementation("org.springframework.boot:spring-boot-starter-security")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
    implementation("org.springdoc:springdoc-openapi-starter-webflux-ui:$springdocVersion")
    implementation("io.github.microutils:kotlin-logging:$kotlinLoggingVersion")

    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("io.projectreactor:reactor-test")
    testImplementation("org.springframework.security:spring-security-test")
}

Full public repo to reproduce the issue with integration tests: https://github.com/elenavanengelenmaslova/kotlin-webflux-rest-security-example

https://github.com/spring-projects/spring-security/issues/12857

mhalbritter commented 1 year ago

This looks like a Spring Security issue for me. Please create an issue there, feel free to link back to this issue.

elenavanengelenmaslova commented 1 year ago

created an issue for spring security https://github.com/spring-projects/spring-security/issues/12857