-
Notifications
You must be signed in to change notification settings - Fork 2k
Description
Jetty version(s)
Jetty 12.1.5
Jetty Environment
ee10, probably ee11
HTTP version
HTTP 1.1, likely others
Java version/vendor (use: java -version)
openjdk version "21.0.9" 2025-10-21 LTS
OpenJDK Runtime Environment (Red_Hat-21.0.9.0.10-1) (build 21.0.9+10-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-21.0.9.0.10-1) (build 21.0.9+10-LTS, mixed mode, sharing)
OS type/version
AlmaLinux 9.6
Description
I'm having trouble integrating Eclipse Soteria 3.0.4 with embedded Jetty in EE10+ environments. So far I've gotten HttpServletRequest.authenticate calls to go through to Soteria-providede BasicAuthenticationMechanism (with a custom JaspiAuthenticator subclass that sets "jakarta.security.auth.message.MessagePolicy.isMandatory" on the message map), but then they fail with a NPE:
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:175)
at example.CustomJaspiAuthenticator.validateRequest(CustomJaspiAuthenticator.java:36)
at org.eclipse.jetty.security.internal.DeferredAuthenticationState.authenticate(DeferredAuthenticationState.java:52)
at org.eclipse.jetty.ee10.servlet.ServletApiRequest.getUndeferredAuthenticationState(ServletApiRequest.java:280)
at org.eclipse.jetty.ee10.servlet.ServletApiRequest.getUserPrincipal(ServletApiRequest.java:515)
at org.eclipse.jetty.ee10.servlet.ServletApiRequest.authenticate(ServletApiRequest.java:617)
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:752)
at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1620)
at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1554)
at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:868)
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:1224)
at org.eclipse.jetty.server.Server.handle(Server.java:197)
at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:720)
at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:412)
at org.eclipse.jetty.server.internal.HttpConnection$FillableCallback.succeeded(HttpConnection.java:1810)
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:1239)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1194)
at java.base/java.lang.Thread.run(Thread.java:1583)
What seems to happen here is that:
- ServletApiRequest.authenticate is called.
- As its first action, the above function tries to determine if a user is already authenticated by calling ServletApiRequest.getUserPrincipal.
- That function, in turn, tries to resolve the deferred authentication state, but using an overload that takes only the current request object - not the response one.
- DeferredAuthenticationState.authenticate thus has to substitute in its dummy
Response __deferredResponseto the underlying authenticator. - And when JaspiMessageInfo.getResponseMessage later tries to unwrap that into a
HttpServletResponse-compatible class, it fails and returns null.
In EE9 this does not happen, because there the equivalent __deferredResponse object implements HttpServletResponse, which can be successfully unwrapped for BasicAuthenticationMechanism.validateRequest to process.
Am I or Soteria doing something wrong, or is the EE10 deferred auth implementation faulty?
How to reproduce?
jetty-soteria-integration.zip
contains the simplest Maven project I could build to reproduce this issue. mvn package builds a uber-jar target/jetty-soteria-integration-0.0.0.jar that, when run, listens on localhost:9000. Navigating to http://localhost:9000/test attemps basic auth, which will crash with the above stack trace.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status