Describe the bug
https://github.com/spring-projects/spring-security/blob/5.7.3/docs/modules/ROOT/pages/servlet/test/mockmvc/result-matchers.adoc#authenticated-assertion
The Kotlin examples for the MockMvc assertions call the Java functions, but these methods are not compatible with the Kotlin DSL, and so this test will always pass:
fun `user should be authenticated`() {
mvc
.perform(formLogin())
.andExpect { authenticated() }
.andExpect { unauthenticated() }
.andExpect { authenticated().withRoles("USER", "ADMIN") }
.andExpect { authenticated().withRoles("blah", "qwerty") }
}
authenticated() returns a AuthenticatedMatcher instance, but the returned value isn't used for anything.
Expected behavior
The examples for Kotlin SecurityMockMvcResultMatchers are corrected.
Sample
Comment From: sjohnr
Thanks for the report, @aSemy!
I believe the example doesn't work because the Kotlin code (e.g. .andExpect { authenticated() }) implements the functional interface ResultMatcher as a no-op.
these methods are not compatible with the Kotlin DSL
I don't believe the framework is intending to expose a Kotlin DSL (though the Kotlin compiler allows a functional parameter that is the last parameter of a method call to be expressed this way). Code similar to Java should work in Kotlin:
@Test
fun `user should be authenticated`() {
mvc
.perform(formLogin())
.andExpect(authenticated())
.andExpect(unauthenticated())
.andExpect(authenticated().withRoles("USER", "ADMIN"))
.andExpect(authenticated().withRoles("blah", "qwerty"))
}
Do you agree? If so, would you be interested in submitting a PR to correct the Kotlin example(s) in the docs?
Comment From: aSemy
Hi @sjohnr, I've done a bit of looking into it and I think this is more than just documentation problem.
There is a Spring Test Kotlin DSL for MockMVC https://github.com/spring-projects/spring-framework/blob/eeebea1da32e6decae381e33c4ef0aa2cafbf620/spring-test/src/main/kotlin/org/springframework/test/web/servlet/MockMvcExtensions.kt
However, this DSL is not compatible with the Java .andExpect() functions. They're not available when using the Kotlin DSL. For example:
import org.junit.jupiter.api.Test
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
lateinit var mvc: MockMvc
@Test
fun test() {
mvc.get("/admin") {
with(SecurityMockMvcRequestPostProcessors.user("admin").password("pass").roles("USER","ADMIN"))
}.andExpect(SecurityMockMvcResultMatchers.authenticated())
// ERROR Type mismatch.
// Required: MockMvcResultMatchersDsl.() → Unit
// Found: SecurityMockMvcResultMatchers.AuthenticatedMatcher!
}
So there's no 'correct' way to document this. The Kotlin DSL needs to be adjusted, either to be compatible with the existing andExpect() functions, or to make .andExpect { authenticated() } work.
I think making .andExpect { authenticated() } work is much more preferable because users will have already copied and pasted the docs, and those assertions will be silently ignored. However, I'm not sure if it's technically possible (a new function might require a specific import).
I ended up working around this by not using the Kotlin DSL at all, which is a shame, but at least it works.