- changed status to open
Virtual thread pinning on RemoteJWKSet.get
Issue #542
open
We use Java 21 and Spring Boot 3.2.4 (nimbus-jose-jwt 9.24.4) with enabled virtual threads in plain web application. First request to secured resource leads to thread pinning:
com.nimbusds.jose.jwt@9.24.4/com.nimbusds.jose.jwk.source.RemoteJWKSet.get(RemoteJWKSet.java:437) <== monitors:1
Full stack trace:
Thread[#137,ForkJoinPool-1-worker-1,5,CarrierThreads]
java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:185)
java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393)
java.base/java.lang.VirtualThread.park(VirtualThread.java:592)
java.base/java.lang.System$2.parkVirtualThread(System.java:2639)
java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:54)
java.base/java.util.concurrent.locks.LockSupport.park(LockSupport.java:369)
java.base/sun.nio.ch.Poller.pollIndirect(Poller.java:139)
java.base/sun.nio.ch.Poller.poll(Poller.java:102)
java.base/sun.nio.ch.Poller.poll(Poller.java:87)
java.base/sun.nio.ch.NioSocketImpl.park(NioSocketImpl.java:175)
java.base/sun.nio.ch.NioSocketImpl.park(NioSocketImpl.java:201)
java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:346)
java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:796)
java.base/java.net.Socket$SocketInputStream.read(Socket.java:1099)
java.base/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:489)
java.base/sun.security.ssl.SSLSocketInputRecord.readHeader(SSLSocketInputRecord.java:483)
java.base/sun.security.ssl.SSLSocketInputRecord.bytesInCompletePacket(SSLSocketInputRecord.java:70)
java.base/sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1461)
java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:1066)
java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:291)
java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:347)
java.base/java.io.BufferedInputStream.implRead(BufferedInputStream.java:420)
java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:399)
java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:827)
java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:759)
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1690)
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1599)
java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:531)
java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:307)
spring.web@6.1.5/org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:88)
spring.web@6.1.5/org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:70)
spring.web@6.1.5/org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
spring.web@6.1.5/org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:889)
spring.web@6.1.5/org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:730)
spring.security.oauth2.jose@6.2.3/org.springframework.security.oauth2.jwt.NimbusJwtDecoder$JwkSetUriJwtDecoderBuilder$RestOperationsResourceRetriever.getResponse(NimbusJwtDecoder.java:488)
spring.security.oauth2.jose@6.2.3/org.springframework.security.oauth2.jwt.NimbusJwtDecoder$JwkSetUriJwtDecoderBuilder$RestOperationsResourceRetriever.retrieveResource(NimbusJwtDecoder.java:478)
com.nimbusds.jose.jwt@9.24.4/com.nimbusds.jose.jwk.source.RemoteJWKSet.updateJWKSetFromURL(RemoteJWKSet.java:305)
com.nimbusds.jose.jwt@9.24.4/com.nimbusds.jose.jwk.source.RemoteJWKSet.get(RemoteJWKSet.java:437) <== monitors:1
com.nimbusds.jose.jwt@9.24.4/com.nimbusds.jose.proc.JWSVerificationKeySelector.selectJWSKeys(JWSVerificationKeySelector.java:157)
com.nimbusds.jose.jwt@9.24.4/com.nimbusds.jwt.proc.DefaultJWTProcessor.selectKeys(DefaultJWTProcessor.java:283)
com.nimbusds.jose.jwt@9.24.4/com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:354)
com.nimbusds.jose.jwt@9.24.4/com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:303)
spring.security.oauth2.jose@6.2.3/org.springframework.security.oauth2.jwt.NimbusJwtDecoder.createJwt(NimbusJwtDecoder.java:158)
spring.security.oauth2.jose@6.2.3/org.springframework.security.oauth2.jwt.NimbusJwtDecoder.decode(NimbusJwtDecoder.java:138)
spring.security.oauth2.client@6.2.3/org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.getJwt(OidcAuthorizationCodeAuthenticationProvider.java:247)
spring.security.oauth2.client@6.2.3/org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.createOidcToken(OidcAuthorizationCodeAuthenticationProvider.java:238)
spring.security.oauth2.client@6.2.3/org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.authenticate(OidcAuthorizationCodeAuthenticationProvider.java:156)
spring.security.core@6.2.3/org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
spring.security.core@6.2.3/org.springframework.security.authentication.ObservationAuthenticationManager.lambda$authenticate$1(ObservationAuthenticationManager.java:54)
io.micrometer.observation.Observation.observe(Observation.java:565)
spring.security.core@6.2.3/org.springframework.security.authentication.ObservationAuthenticationManager.authenticate(ObservationAuthenticationManager.java:53)
spring.security.oauth2.client@6.2.3/org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:196)
spring.security.web@6.2.3/org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:231)
spring.security.web@6.2.3/org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:221)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.oauth2.client@6.2.3/org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:181)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.web@6.2.3/org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
spring.security.web@6.2.3/org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.web@6.2.3/org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.web@6.1.5/org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.web@6.2.3/org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
spring.security.web@6.2.3/org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.web@6.2.3/org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
spring.security.web@6.2.3/org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.web@6.2.3/org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.web@6.2.3/org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
spring.security.web@6.2.3/org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
spring.security.web@6.2.3/org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
spring.security.web@6.2.3/org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
spring.web@6.1.5/org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
spring.webmvc@6.1.5/org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
spring.web@6.1.5/org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
spring.web@6.1.5/org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
spring.security.config@6.2.3/org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:230)
spring.web@6.1.5/org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
spring.web@6.1.5/org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
spring.web@6.1.5/org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
io.sentry.spring.jakarta@7.6.0-module/io.sentry.spring.jakarta.tracing.SentryTracingFilter.doFilterWithTransaction(SentryTracingFilter.java:107)
io.sentry.spring.jakarta@7.6.0-module/io.sentry.spring.jakarta.tracing.SentryTracingFilter.doFilterInternal(SentryTracingFilter.java:87)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
spring.web@6.1.5/org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
io.sentry.spring.jakarta@7.6.0-module/io.sentry.spring.jakarta.SentrySpringFilter.doFilterInternal(SentrySpringFilter.java:71)
spring.web@6.1.5/org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
org.apache.tomcat.embed.core@10.1.19/org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
org.apache.tomcat.embed.core@10.1.19/org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
org.apache.tomcat.embed.core@10.1.19/org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
org.apache.tomcat.embed.core@10.1.19/org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
org.apache.tomcat.embed.core@10.1.19/org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
org.apache.tomcat.embed.core@10.1.19/org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
java.base/java.lang.VirtualThread.run(VirtualThread.java:311)
Would be nice if Nimbus became Loom-friendly and replace synchronized methods to ReentrantLock for virtual thread support.
This class in pgjdbc seems like an interesting approach.
Comments (2)
-
-
Good and bad news:
- Getting JWKs via code that rely on
ReentrantLock
is already in place - Spring has not yet upgraded from the tested and tried
RemoteJWKSet
, so in the short term this will require some custom code.
So while I guess
RemoteJWKSet
could be upgraded to useReentrantLock
, perhaps filing and issue on the Spring project is best. - Getting JWKs via code that rely on
- Log in to comment
Ouch. Loom is a great thing, but it's still not practised here and as such unknown territory. I'll ask the original contributor for his opinion.