Issue
Introduction
I recently stumbled across a problem in my Camunda/Spring Boot application. I just want to expose the Camunda REST-API and thus let Maven incorporate the camunda-bpm-spring-boot-starter-rest dependency. Unfortunately, this seems to mess with the Spring Boot configurations I am having already in place for non-Camunda API endpoints.
Specific Problem Description
I have a class of type AccessDecisionVoter in which the RequestContextHolder is utilized to obtain the current request details, while querying a self-made REST endpoint. This decision voter class is involved in method security and basically decides whether a user is authorized for this endpoint. While this approach works fine with all sorts of other Camunda dependencies the above mentioned dependency somehow distorts the request handling for my own API (The Camunda REST-API works fine). The result being a RequestContextHolder that returns null which ultimately leads to an AccessDeniedException.
Using the RequestContextHolder:
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Interpretation and Possible Solution
It seems like the problem could possibly be related to a thread issue in which the request information is not handed down to some child thread. But this would require the dependency to mess with the DispatcherServlet or something else and/or spawn a new thread to handle a request to a non-Camunda API. Seems weird, but on the other hand spawning a Bean of type RequestContextListener (Spring) indeed solves the problem.
@Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
It would be great to understand this problem and how the dependency is messing with my endpoints. Ultimately I am looking for some modification (maybe some property?) that helps me get rid of the RequestContextListener bean. Though it seems fine as a workaround.
Any good explanations?
Cheers barkeldiho
Solution
Luckily, I was able to answer my own question.
1.) In a vanilla Spring Boot environment the DispatcherServlet has a property setThreadContextInheritable
set to false
. This indicates that no request details are shared with possible child threads from the parent thread that handles a certain request. A possible solution to the stated problem would of course be to set this property to true
. But in environments utilizing thread pools such modification would expose request information to all contained threads and thus should not be the prefered solution (Ref).
2.) While debugging I could find that the Camunda REST dependency spawns a bean of Type FilterRegistrationBean which is named requestContextFilter
and thus replaces the original bean of Type OrderedRequestContextFilter which is automatically maintained and spawned by Spring. The original bean exposes the request details to the current thread. Since its missing the details are not shared among child threads and the RequestContextHolder remains empty.
Hence, using a new bean of type RequestContextListener seems like the correct approach to expose request details to the current child thread without messing with the DispatcherServlet properties:
@Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
Answered By - barkeldiho
Answer Checked By - Candace Johnson (JavaFixing Volunteer)