Jetty version(s)
Jetty 12.1.9
Jetty Environment
ee10, probably ee11 too
HTTP version
Shouldn't matter
Java version/vendor (use: java -version)
openjdk version "21.0.11" 2026-04-21 LTS
OS type/version
AlmaLinux 9.7 (Moss Jungle Cat)
Description
Issue #14165 has been closed, but I still can't get the example attached to it to work with Jetty 12.1.9. Now, a call to HttpServletRequest.authenticate(HttpServletResponse) fails with an NPE like so:
java.lang.NullPointerException: Cannot invoke "jakarta.servlet.http.HttpServletResponse.setHeader(String, String)" because "response" is null
at org.glassfish.soteria.mechanisms.BasicAuthenticationMechanism.validateRequest(BasicAuthenticationMechanism.java:77)
at org.glassfish.soteria.mechanisms.BasicAuthenticationMechanism$Proxy$_$$_WeldClientProxy.validateRequest(Unknown Source)
at org.glassfish.soteria.mechanisms.jaspic.HttpBridgeServerAuthModule.validateRequest(HttpBridgeServerAuthModule.java:89)
at org.eclipse.jetty.ee10.security.jaspi.provider.SimpleServerAuthContext.validateRequest(SimpleServerAuthContext.java:45)
at org.eclipse.jetty.ee10.security.jaspi.JaspiAuthenticator.validateRequest(JaspiAuthenticator.java:184)
at org.eclipse.jetty.ee10.security.jaspi.JaspiAuthenticator.validateRequest(JaspiAuthenticator.java:163)
at org.eclipse.jetty.security.internal.DeferredAuthenticationState.authenticate(DeferredAuthenticationState.java:87)
at org.eclipse.jetty.ee10.servlet.ServletApiRequest.getUndeferredAuthenticationState(ServletApiRequest.java:296)
at org.eclipse.jetty.ee10.servlet.ServletApiRequest.authenticate(ServletApiRequest.java:616)
at example.TestServlet.doGet(TestServlet.java:96)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
at org.eclipse.jetty.ee10.servlet.ServletHolder.handle(ServletHolder.java:754)
at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1622)
at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1556)
at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:871)
at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:449)
at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:469)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:546)
at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:719)
at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1250)
at org.eclipse.jetty.server.Server.handle(Server.java:197)
at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:793)
at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:419)
at org.eclipse.jetty.server.internal.HttpConnection$FillableCallback.succeeded(HttpConnection.java:1780)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:54)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:1009)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1240)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1194)
at java.base/java.lang.Thread.run(Thread.java:1583)
The problem seems to be that ServletApiRequest.getUndeferredAuthenticationState wraps its argument HttpServletResponse in a ServletCoreResponse, but when Soteria's HttpBridgeServerAuthModule.validateRequest() later tries to unwrap this (via org.glassfish.soteria.mechanisms.HttpMessageContextImpl.getResponse() -> JaspiMessageInfo.getResponseMessage() -> Response.asInContext(), the final function in that chain does not know how, and so returns null.
I tried using a custom org.eclipse.jetty.security.Authenticator$Factory service to unwrap the response object before it gets passed to Jakarta Security, but that instead led to a deadlock in ServletApiRequest.getUndeferredAuthenticationState, because that function chooses to block if the undeferred state is ResponseSent (probably on account of the Soteria BasicAuthenticationMechanism committing a 401 Forbidden response), but it is unclear who should be unblocking it?
How to reproduce?
Attached is a Maven project that by default reproduces the deadlock scenario. Build with mvn package, run with java -jar target/jetty-soteria-integration-0.0.0.jar and then navigate to http://localhost:9000/test, which should never respond. The NPE can be triggered by commenting out the example.CustomJaspiAuthenticator$Factory line in the src/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factory file and rebuilding.
jetty-soteria-integration.zip
Jetty version(s)
Jetty 12.1.9
Jetty Environment
ee10, probably ee11 too
HTTP version
Shouldn't matter
Java version/vendor
(use: java -version)openjdk version "21.0.11" 2026-04-21 LTS
OS type/version
AlmaLinux 9.7 (Moss Jungle Cat)
Description
Issue #14165 has been closed, but I still can't get the example attached to it to work with Jetty 12.1.9. Now, a call to
HttpServletRequest.authenticate(HttpServletResponse)fails with an NPE like so:The problem seems to be that ServletApiRequest.getUndeferredAuthenticationState wraps its argument HttpServletResponse in a ServletCoreResponse, but when Soteria's HttpBridgeServerAuthModule.validateRequest() later tries to unwrap this (via org.glassfish.soteria.mechanisms.HttpMessageContextImpl.getResponse() -> JaspiMessageInfo.getResponseMessage() -> Response.asInContext(), the final function in that chain does not know how, and so returns null.
I tried using a custom org.eclipse.jetty.security.Authenticator$Factory service to unwrap the response object before it gets passed to Jakarta Security, but that instead led to a deadlock in ServletApiRequest.getUndeferredAuthenticationState, because that function chooses to block if the undeferred state is ResponseSent (probably on account of the Soteria BasicAuthenticationMechanism committing a 401 Forbidden response), but it is unclear who should be unblocking it?
How to reproduce?
Attached is a Maven project that by default reproduces the deadlock scenario. Build with
mvn package, run withjava -jar target/jetty-soteria-integration-0.0.0.jarand then navigate to http://localhost:9000/test, which should never respond. The NPE can be triggered by commenting out theexample.CustomJaspiAuthenticator$Factoryline in thesrc/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factoryfile and rebuilding.jetty-soteria-integration.zip