We have a legacy API build on jersey 1.13 (jax-rs 1.x) and deployed to glassfish 3.1.2 server. We have multiple ContainerRequestFilters and the same are configured via web.xml. Below is a sample reference:
<servlet>
<servlet-name>ApplyRestfulService</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
.....
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.api.filter.CorsFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>
com.api.filter.CorsFilter,
com.api.filter.AuthenticationFilter,
com.api.filter.AuthorizationFIlter
</param-value>
</init-param>
</servlet>
My understanding is the Request filter will execute in the order it has been defined above before calling the resouce i.e.
first CorsFilter --> AuthenticationFIlter --> AuthorizationFIlter --> Some API Resource
Within the AuthenticationFilter we set custom securityContext object to ContainerRequest to be consumed in next Filter as below
@Provider
public class AuthenticationFilter implements ContainerRequestFilter {
private static final Logger logger = Logger.getLogger(AuthenticationFilter.class) ;
private static final String PREFIX_JWT = "JWT ";
@Override
public ContainerRequest filter(ContainerRequest request) {
AuthenticationResponse authenticationResponse = someJWTAuthenticationMethod(request);
request.setSecurityContext(new Authorizer(authenticationResponse));
return request;
}
Authorizer is a custom class which implements SecurityContext. The intension of setting the response in SecurityContext is to get it in the next Filter i.e AuthorizationFilter. We use the @Context annotation to read the SecurityContext as shown below
@Provider
@ApplicationScoped
public class AuthorizationFilter implements ContainerRequestFilter {
@Context
private SecurityContext context;
@Inject
private SomeDAO someDAO;
@Override
public ContainerRequest filter(ContainerRequest request) {
String accountId = ((AuthenticationResponse) context.getUserPrincipal()).getSomeId();
UserPrincipal user = getUser(accountId);
request.setSecurityContext(new Authorizer(user));
}
return request;
}
This all seems to work fine but many times we are getting below Exception when we try to access SecurityContext in AuthenticationFilter RequestFilter:
[#|2021-03-02T07:24:55.486+0000|INFO|oracle-glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=40;_ThreadName=http-thread-pool-8080(5);|ERROR [http-thread-pool-8080(5)] - General unhandled exception
java.lang.IllegalStateException
at com.sun.jersey.server.impl.ThreadLocalHttpContext.getRequest(ThreadLocalHttpContext.java:82)
at com.sun.jersey.server.impl.application.WebApplicationImpl$2.invoke(WebApplicationImpl.java:287)
at com.sun.proxy.$Proxy226.getUserPrincipal(Unknown Source)
at com.api.filter.AuthorizationFilter.filter(AuthorizationFilter.java:36)
at com.api.filter.AuthorizationFilter$Proxy$_$$_WeldClientProxy.filter(AuthorizationFilter$Proxy$_$$_WeldClientProxy.java)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1454)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
When we restart the glassfish server the issue gets resolved but that is more of just an workaround and not the real solution.
Could this be because AuthenticationFIlter is ApplicationScoped and when multiple threads are accessing the API causes the above error ?