Skip to content

Further problems with Soteria and Jetty EE10+ #15129

Description

@lrasku

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

Metadata

Metadata

Labels

BugFor general bugs on Jetty side

Type

No type
No fields configured for issues without a type.

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions