-
Notifications
You must be signed in to change notification settings - Fork 38.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Spring Boot 2.4 upgrade breaks injection of Principal #26117
Comments
I have found a resolution to the issue by adding the following:
The new |
Yes it looks like the fix in #25981 was incomplete. |
@rstoyanchev i am still experiencing this issue. Is the fix @electrified recommending required for this. Or is there another reason why this is closed? |
Same issue as @petergphillips fun createPayment(
request: HttpServletRequest,
@ApiIgnore @AuthenticationPrincipal authentication: JwtAuthentication<PaymentGatewayClaim>,
@RequestBody @Valid paymentCreateRequest: PaymentCreateRequest
): PaymentCreateResponse { Adding this did fix this, but i don't understand why this was changed? @Configuration
class WebConfig : WebMvcConfigurer {
override fun addArgumentResolvers(resolvers: MutableList<HandlerMethodArgumentResolver>) {
super.addArgumentResolvers(resolvers)
resolvers.add(PrincipalMethodArgumentResolver())
}
} |
@michaelbrewer if you look at the timeline you will see that it was closed with a commit. That commit adds the same resolver and there are tests for it. Can you check that you are running with the fix from that commit, which should be included in version 5.3.2? |
@rstoyanchev i am still experiencing this with SpringBoot 2.4.1 (maybe i will have to manually bump spring-framework to 5.3.2?) |
@rstoyanchev So i have to use the |
@michaelbrewer please check the fix 05e3f27. It does exactly the same. If you can double check in the source that this change is present. Also maybe debug to see what happens? I don't see why you have to add this resolver if it is there. |
@rstoyanchev still does not work for me. But i am using manual |
@rstoyanchev I see your point, that the fix does indeed add the resolver. Nevertheless, I can confirm that I also suffer this problem under Spring Boot 2.4.1, and I have confirmed that the fix is visible in the code. When I add the following (Java version of @electrified's fix), then the problem disappears.
Is the order of the resolvers relevant? I debugged a bit and with the |
@michaelbrewer, I'm not sure what manual @fletchgqc a search on usages for where the resolver is instantiated does not explain why it would be added twice. Could it be that it's twice because you're adding it as well? The framework adds it once only. Can either of you provide a sample that demonstrates the issue? |
@rstoyanchev It's added twice, because I use Spring 2.4.1 (which has your fix), and also the fix mentioned at the top of this thread. With plain Spring 2.4.1 it's only added once, but that doesn't fix the problem. |
Our issue is fixed in Spring 2.4.1. We've removed @electrified fix and the application still works as expected 😁 |
Attempted upgrade from boot 2.3.4 to 2.4.1 and @AuthenticationPrincipal is now null in our relatively large application as well. Will try to debug a bit. |
@krm1312 thanks and if there is a regression please create a separate issue to provide the details. |
@rstoyanchev Still not fixed for me. Following code works fine on SpringBoot 2.3.8 but on SpringBoot 2.4.2 the
package temp
import okhttp3.OkHttpClient
import okhttp3.Request
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.web.server.LocalServerPort
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.core.Authentication
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.filter.GenericFilterBean
import javax.servlet.FilterChain
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
@SpringBootApplication
class FakeApplication
class FakeSecurityFilter : GenericFilterBean() {
override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
SecurityContextHolder.getContext().authentication = UsernamePasswordAuthenticationToken("x", "y")
chain.doFilter(request, response)
}
}
@Configuration
class CustomWebSecurityConfigurerAdapter : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http.addFilterAfter(FakeSecurityFilter(), BasicAuthenticationFilter::class.java)
}
}
@RestController
class FakeController {
@GetMapping(path = ["/fake"])
fun fake(@AuthenticationPrincipal auth: Authentication) {
println(auth)
}
}
@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = [FakeApplication::class])
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class Tests {
@LocalServerPort
private val port = 0
@Test
fun checkCall() {
val request = Request.Builder().get().url("http://localhost:$port/fake").build()
val response = OkHttpClient().newCall(request).execute()
Assertions.assertEquals(200, response.code)
}
}
|
@michaelbrewer sounds like a duplicate of #26380. |
Ok thanks so you are not supposed to use |
So removing the OR putting in this. @Configuration
class WebConfig : WebMvcConfigurer {
override fun addArgumentResolvers(resolvers: MutableList<HandlerMethodArgumentResolver>) {
super.addArgumentResolvers(resolvers)
resolvers.add(PrincipalMethodArgumentResolver())
}
} |
No, it's not that you are not supposed but that it doesn't provide what you are trying to get. Your argument is |
Thanks for the clarification, interesting that adding |
It is a bit confusing because the word "principal" is used in multiple contexts but there is no bug I think.
Therefore when injecting with the annotation, it is important to use the correct user type. At the same time it is perfectly legitimate to inject |
In addition to the above change, the wiki has also been updated. |
…al, since an old bug got fixed and changed the behavior of which got populated first spring-projects/spring-framework#26117
Affects: 2.4.0
Our code:
used to inject the
principal
in Spring Boot versions prior to 2.4.0. Under 2.4.0 the argument is thennull
and our application breaks.If the
@ApiIgnore
annotation is removed then theprincipal
is then injected, however we don't want theprincipal
to be exposed in our API documentation since it is an internal parameter.It appears that the bug was introduced in #25780. That PR doesn't check to see if there is a
AuthenticationPrincipal
annotation on the field, merely that the parameter has any annotations at all so evenNonnull
will break the injection.We've tried adding the
AuthenticationPrincipal
annotation on the field, however that doesn't work since the parameter resolver tries to injectauthentication.getPrincipal
which in our case is aString
since we're using spring security oauth2. We want thePrincipal
injected instead.The text was updated successfully, but these errors were encountered: