Spring Boot 2.2.5 - Request method 'MOVE' not supported - spring-boot

I am playing around with a simple Spring Boot webapp which gets called by some software which does basic file download/upload tasks.
The software sending the Requests to my app can not be changed/modified and I came across following request being sent to my webapp:
DEBUG Received [
MOVE /database/1.tmp HTTP/1.1
Destination: http://localhost:8080/database/1
Host: localhost:8080
]
which results in
WARN Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'MOVE' not supported]
As I found out MOVE is not an enum in RequestMethod so I can not simply annotate my controller with method = RequestMethod.MOVE.
How can I handle this request?

First, you have to override Spring Boot's default firewall to allow MOVE methods:
#Bean
public HttpFirewall defaultHttpFirewall() {
final StrictHttpFirewall firewall = new StrictHttpFirewall();
Set<String> allowedHttpMethods = new HashSet<>();
allowedHttpMethods.add(HttpMethod.DELETE.name());
allowedHttpMethods.add(HttpMethod.GET.name());
allowedHttpMethods.add(HttpMethod.POST.name());
allowedHttpMethods.add(HttpMethod.PUT.name());
allowedHttpMethods.add("MOVE");
firewall.setAllowedHttpMethods(allowedHttpMethods);
return firewall;
}
Now that MOVE requests are handed over to your application, your only way (as I found out there are no controller mappings for custom methods) is to manually handle the requests in a filter:
#Component
#Slf4j
public class NonRESTFulHttpMethodRequestFilter implements Filter {
#Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
if ("MOVE".equals(httpServletRequest.getMethod())) {
final HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
log.trace("Ignoring 'MOVE {}' request with 200 OK", httpServletRequest.getRequestURI());
httpServletResponse.setStatus(HttpStatus.OK.value());
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
}

Related

How to send custom request or response headers to APM from Keycloak Integration Spring Boot

I'm working on springboot project and we are using openId keycloak for authentication. I'm delaing with Multitenancy concept too. I want to sent custom header as request or either response and the same should be captured in APM as metadata. My current approach is as follows:
public class PreAuthFilter extends KeycloakPreAuthActionsFilter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
((HttpServletResponse) response).addHeader("X-Realm",realm);
super.doFilter(request, response, chain);
}
But with above code i'm getting multiple response metatdata in APM
http.response.headers.X-Realm.0
http.response.headers.X-Realm.1
http.response.headers.X-Realm.2
http.response.headers.X-Realm.3
My expectation was single realm in APM Metadata
http.response.headers.X-Realm = "value"
I think SimpleHttpFacade is getting intialized during resolving deployment multiple times hence adding the response.
Need Suggestion
Thanx.
It appears this could be that the issue is more likely related to your application context spring and filters.
Since it's spring could you try OncePerRequestFilter ?
import org.springframework.web.filter.OncePerRequestFilter;
#Named
public class ApmFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// do apm things
filterChain.doFilter(request, response);
}
#Override
public void destroy() {
}
}

Intercept websocket initial handshake in rsockets

I want to be able to intercept the first request a client makes to my endpoint so to be able to answer with 101 (websocket estabilished) or deny it.
Is there any interceptor I can use? I tried registering a filter bean but it seems it is just skipped, I think because I'm in a webflux application...
#Bean
public FilterRegistrationBean<ContextFilter> initialFilter() {
FilterRegistrationBean<ContextFilter> registrationBean
= new FilterRegistrationBean<>();
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
and
public class MyFilter extends OncePerRequestFilter{
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
log.info("You know, for filtering");
filterChain.doFilter(request, response);
}
To establish the RSocket connection client must send a first frame called SETUP frame. You can catch it with the Spring #ConnectMapping annotation.
#ConnectMapping
fun onConnect(rSocketRequester: RSocketRequester, clientId: String) {
if (clientId == "wrong_client") rSocketRequester.rsocket().dispose() //to reject connection
}
To reject the connection use the rSocketRequester.rsocket().dispose() as shown above.
Note that with the SETUP frame you can pass the payload and metadata from the client as usual.

Passin Parameters from Filter to Business Service in SpringBoot

I have 3 REST services which are reading some common header parameters on the request. I need to use that parameters on my business services. instead of reading that common header parameters on each web service controller (#RestController), Is it possible to read that headers on request filter and make it available on the business services ? If yes, are there any examples to do this ?
You can get request object
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
and access the headers in business services using request object.
Like #Nitin suggest you can pass the request object from your controllers to your services and read the header there. There is no problem with that.
If you still want to read it in a filter and have it available in any #Service you can do as follows:
#Component
#Order(1)
public class HeaderReaderFilter implements Filter {
#Autowired
private HeaderDataHolder headerDataHolder;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
headerDataHolder.setHeaderContent(httpRequest.getHeader("header_field"));
chain.doFilter(request, response);
}
}
#RequestScope
#Component
public class HeaderDataHolder {
private String headerContent;
public String getHeaderContent() {
return headerContent;
}
public void setHeaderContent(String headerContent) {
this.headerContent = headerContent;
}
}
And then have the HeaderDataHolder #Autowired in your service classes. Notice the necessary #RequestScope so you have a different bean for each request.

Custom Authentication Filter for Mule Http Listener

I would like to implement a Security Filter in Mule 3 extending OncePerRequestFilter from Spring Security. But I am unable to make it work because the code for authentication hadn't been reach.
Here is the code for registering the filter on mule xml.
<spring:bean id="requestContextFilter" class="com.sample.authentication.BeforeBasicAuthFilter"/>
<ss:http entry-point-ref="restAuthenticationEntryPoint">
<ss:custom-filter ref="requestContextFilter" before="FIRST"/>
</ss:http>
public class BeforeBasicAuthFilter extends OncePerRequestFilter {
private HttpServletRequest request;
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
this.request = request;
System.out.println("XXXX ");
filterChain.doFilter(request, response);
}
}
I believe that that filter is not registered to be used by the http listener or authentication manager. Was there a way in Mule to register a filter to be used on a http Listener? My goal is that I should be able to intercept the raw http request before the authentication will take place.
Use before BASIC_AUTH_FILTER in the custom-filter.
<ss:http entry-point-ref="restAuthenticationEntryPoint">
<ss:custom-filter ref="requestContextFilter" before="BASIC_AUTH_FILTER"/>
</ss:http>

Spring HttpServletRequest unaccessible in HystrixCommand

Inside a Javanica annotated #HystrixCommand we are checking if the request was in an actual HTTP servlet request by checking:
RequestContextHolder.getRequestAttributes() != null;
However invoked from a #HystrixCommand this condition is always false, even if the request came from a Spring MVC request.
If I remove the #HystrixCommand annotation everything works fine.
We also tried to use the HttpServletRequest directly, this works fine (without #HystrixCommand):
LOGGER.info(request.getHeader("X-Client"));
With annotated #HystrixCommand we are facing exception indicating I am not in an valid HttpServletRequest. I know it is due to Hystrix running commands in separate Threads from its own ThreadPool and tried to do this, but doesn't work either:
public class RequestServletFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// No Impl
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
chain.doFilter(request, response);
} finally {
context.shutdown();
}
}
#Override
public void destroy() {
// No Impl
}
Does someone have a clue how to delegate the Spring HttpServletRequest into HystrixCommands?
Any help is appreciated.
When using the RequestContextHolder by default it parameters are not shared (for good reasons!).
Assuming that you are using a DispatcherServlet to handle your request you can set its [threadContextInheritable] to true to have the RequestContext and LocaleContext shared between requests.
The same applies for the RequestContextFilter, it isn't possible with the RequestContextListener.
Note: I would consider sharing the HttpServletRequest between threads as something you shouldn't be doing and should be done with great care!

Resources