I am developing an Api using spring boot. I need to call a dependent service asynchronously.
I have an interceptor which uses RequestContextHolder from spring to get the httpservletrequest. But as the calls to dependent service is happening ashnchronously, a new thread is created for executing the dependent call and requestContextHolder.getAttributes returns null for the requests started in new thread. Any suggestions to overcome this?
Code :
CompletableFuture.supplyAsyn(()-> dependentService.getSomething());
Interceptor:
HttpServletRequest request = (ServletRequest) (RequestContextHolder.getAttributes()).getRequest();
Here RequestContextHolder.getAttributes() returns null for the requests happening in new threads.Anyway to hold the requestcontext ?
Related
i have a spring boot microservice with 4 endpoints, i have a custom filter which extends OncePerRequestFilter, the logic in the filter is as below:
call a Rest API with some query params, based on the response of the API, either throw a 403 Forbidden or continue with further execution (if everything is fine with the response).
the filter works as expected with multiple URI's, now how can i mock the response of the Rest API call in filter while writing integration tests.
i do have some external calls which i mock using WireMock (sample below)
wireMockServer = new WireMockServer(port);
wireMockServer.start();
WireMock.configureFor("localhost", port);
WireMock.stubFor(
WireMock.get(WireMock.urlPathMatching("/path/.*"))
.willReturn(
WireMock.aResponse()
.withStatus(200)
.withBody(new ObjectMapper().writeValueAsString(response))));
this does not help me while trying to mock the external call in the filter.
Any pointers would be helpful.
Thanks!
I'm using spring boot and I want to assert an asynchronous side effect by calling a secured endpoint with MockMvc.
I have been using Awaitility, but apparently the mocked security context is lost when executing in a different thread.
I couldn't find a way of passing the context, I tried with SecurityContextHolder.setContext() but it didn't work, I guess spring's MockMvc stores the context in a different way.
#Test
#WithMockUser(authorities = "admin", username = "user")
void shouldRunSideEffectAsync() throws Exception {
mockMvc.perform(post("/foo")).andExpect(status().isAccepted());
await()
.atMost(TIMEOUT)
.untilAsserted(() -> mockMvc.perform(get("/foo")).andExpect(status().isOk()));
}
The GET would return 404 for a while and then 200 when the async task is completed. However this will always return 403 as the MockUser info is lost.
How can I solve this?
You almost got it. Security for MockMvc is implemented by TestSecurityContextHolderPostProcessor, which uses the TestSecurityContextHolder to set/get the security context. That is just a wrapper around the SecurityContextHolder.
So you can use TestSecurityContextHolder.setContext() in the awaitility thread and it should work.
I have an application exporting web services, with a configured Spring Security SecurityFilterChain (with SecurityContextPersistenceFilter among others, which is required for the rest).
My application also uses Spring Security to secure method invocations.
I have following error when method security is triggered:
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
The 2nd part requires an Authentication in SecurityContextHolder as showed in org.springframework.security.access.intercept.AbstractSecurityInterceptor (line 195):
SecurityContextHolder.getContext().getAuthentication();
But, SecurityContextPersistenceFilter removes it before method invocation is triggered, as shown in
org.springframework.security.web.context.SecurityContextPersistenceFilter (line 84)
SecurityContextHolder.clearContext();
What can I do to have this object in SecurityContextHolder when method invocation is triggered?
Thank you in advance.
I'm using Spring Security 3.0.8-RELEASE
SecurityContextHolder.clearContext() will be called only after request processing completion. So normally all your application logic code will be executed before this line, and there is no problem at all. But the problem may be present if you execute some new thread in your code (by default security context will be not propogated). If this is your case then you can try to force context propogation to child thread. If you use only one thread then make sure that all your code is covered by spring security filter chain (may be you have some custom filter that executed around spring security filter chain?).
OK, my application is placed over Apache CXF DOSGi 1.4 to generate REST endpoints. Apache CXF interceptors cause an unexpected behaviour and SecurityContextHolder.clearContext() is called before finishing the request processing.
More information about this bug can be found here.
I've got spring web application with jersey rest services. However rest is secured via spring security and login process is very hard to perform from unit test code. I'd like to test rest services with whole spring security disabled. Is it even possible?
One of the advantages of annotation based web services is that you can unit-test them easily.
class WebServiceEndpoint {
#Path("/foo/{fooId}")
#POST
#Produces({ MediaType.APPLICATION_XML })
public Response doFoo(#PathParam("fooId") Integer fooId) {
/// ... web service endpoint implementation
}
}
If you're using Spring's servlet filter for security, then there shouldn't be any security-related code in the doFoo method, so you can just create a new WebServiceEndpoint class and call the method. So that's one way of 'disabling' security.
When you say the login process is 'hard', what do you mean? If you've succeeded in logging in once, then you can just reuse the same code in your other unit tests (e.g. in a #Before method).
Just test it as a pojo. Pass in whatever, return whatever, don't load an app context at all - that would be an integration test.
The ability to easily test functionality without the framework loaded is one of the key advantages of spring.
You don't say what's "hard," so I'm assuming that you've got something in your REST service, i.e. in the java method that you want to test, which requires authentication results. Spring has utilities for mocking the authentication results. For example, you can do the following in a #Before setup method:
Object principal = null; // fix this
Object credentials = null; // fix this
Authentication auth = new org.springframework.security.authentication.TestingAuthenticationToken(principal, credentials);
SecurityContextHolder.getContext().setAuthentication(auth);
But again, you haven't said what problem you're actually trying to solve...
Can someone tell whether is there a way to get HttpServletRequest and HttpServletResponse in Spring JMS listener class? My JMS listener is defined in springContext.xml file.
First of all you don't have access to HTTP servlet request and response within JMS listeners. These are completely independent modules that can even reside on different physical servers.
You can use MockHttpServletRequest and MockHttpServletResponse from spring-test.jar - but they are meant to be used within unit/integration tests, not in production code.
I would really like to see your code that requires MockHttpServletRequest and response. My guess is that it can be refactored or redesigned to use only relevant fields from the above, like request URL or user name.
I ended up using JAXDispatcher to invoke my service, from my JMS listener.
jaxbDispatcher.doGET(null, url, null, "application/xml", true);