pac4j

NullPointerException when trying to extract credentials in DirectClient class (base class of DirectBearerAuthClient)


I am using PAC4J version 5.7.0 in Java. In our case, we are using JWT with DirectBearerAuthClient for authentication purpose. We have occasionally observed NullPointerException and below is the reproducing steps:

  1. The backend server with PAC4J is up and running 24/7. From time to time, we will need to deploy the backend with newer version and there is expected down time.
  2. It means that those JWTs in use in frontend were invalidated after we have restarted the backend. However, the frontend codes will at least initiate a request before it is aware that the JWT is invalid and there is a need to redirect the users to login page again.
  3. All these functionalities are working, just we have observed NullPointerException as shown below from time to time. It is not always can be reproduced but when it happens, it could confuse our production logging monitoring.

By going through the code in PAC4J, it seems like there is a timing issue that caused the DirectClient object was not initialized properly, while the object of "credentialsExtractor" is invoked but it is still null.

Observed Exception Stack Trace:

2023-05-12T10:17:28.383 ERROR [qtp211001987-60] spark.http.matching.GeneralError - java.lang.NullPointerException: Cannot invoke "org.pac4j.core.credentials.extractor.CredentialsExtractor.extract(org.pac4j.core.context.WebContext, org.pac4j.core.context.session.SessionStore)" because "this.credentialsExtractor" is null at org.pac4j.core.client.BaseClient.retrieveCredentials(BaseClient.java:71) ~[pac4j-core-5.7.0.jar:?] at org.pac4j.http.client.direct.DirectBearerAuthClient.retrieveCredentials(DirectBearerAuthClient.java:58) ~[pac4j-http-5.7.0.jar:?] at org.pac4j.core.client.DirectClient.getCredentials(DirectClient.java:44) ~[pac4j-core-5.7.0.jar:?] at org.pac4j.core.engine.DefaultSecurityLogic.perform(DefaultSecurityLogic.java:108) ~[pac4j-core-5.7.0.jar:?] at org.pac4j.sparkjava.SecurityFilter.handle(SecurityFilter.java:64) ~[spark-pac4j-5.0.1.jar:?] at spark.FilterImpl$1.handle(FilterImpl.java:73) ~[spark-core-2.9.4.jar:?] at spark.http.matching.BeforeFilters.execute(BeforeFilters.java:48) ~[spark-core-2.9.4.jar:?] at spark.http.matching.MatcherFilter.doFilter(MatcherFilter.java:133) ~[spark-core-2.9.4.jar:?] at spark.embeddedserver.jetty.JettyHandler.doHandle(JettyHandler.java:50) ~[spark-core-2.9.4.jar:?] at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1598) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.server.Server.handle(Server.java:516) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) ~[jetty-server-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[jetty-io-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) ~[jetty-io-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) ~[jetty-io-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) ~[jetty-util-9.4.48.v20220622.jar:9.4.48.v20220622] at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) ~[jetty-util-9.4.48.v20220622.jar:9.4.48.v20220622] at java.lang.Thread.run(Thread.java:833) ~[?:?]

I have tried with latest version of PAC4J 5.7.1 but still managed to see the NullPointerException.


Solution

  • This is quite strange. Let's make a test: in your code, just after defining the clients, can you explicitly call .init() on the Clients component and then on all clients? Do you still see the NPE? Thanks