So, I have defined my custom filter and now I want to return in case something goes wrong:
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if(rulefail()){
//what now??
}
filterChain.doFilter(servletRequest, servletResponse);
}
I tried throwing a runtime exception but of course it isn't effective: the server returns the tomcat's default internal server error page.
From this answer, just return or don't do filterChain.dofiler. See if this answer suffice https://stackoverflow.com/a/8445927/905494
Related
This question already has answers here:
How to get request body params in spring filter?
(2 answers)
Closed 4 months ago.
I need to calculate a value for every request body (soap requests) for this i created a filter (extending OncePerRequestFilter):
#Component
#RequiredArgsConstructor
public class AddHashFilter extends OncePerRequestFilter {
private final RequestHash hash;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if(!(request instanceof ContentCachingRequestWrapper)){
requestToUse = new ContentCachingRequestWrapper(request);
}
hash.hash(IOUtils.toString(requestToUse.getInputStream(), StandardCharsets.UTF_8));
filterChain.doFilter(requestToUse, response);
}
}
The problem is that this somehow destroys the request - i get 400. What i tried:
using request.geReader -> get an exception that getReader was already called
omit using ContentCachingRequestWrapper -> no change
i also tried this variant to read the body (from examples i found)
#Component
#RequiredArgsConstructor
public class AddHashFilter extends OncePerRequestFilter {
private final RequestHash hash;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
hash.hash(new String(StreamUtils.copyToByteArray(request.getInputStream()), StandardCharsets.UTF_8));
filterChain.doFilter(request, response);
}
}
The problem is same: all request are quit with 400.
But if i remove the actual work/ use of this filter (only keeping filterChain.doFilter...) it is working.
So how can i read complete body and keep it usable for everything after?
Http request could be read only once, so if you read it in filter you can not use it again. Spring provides its own class that extends HttpServletRequest and allows reading its contents multiple times. And that resolves your problem. See this question and my answer to it: How to get request body params in spring filter?
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() {
}
}
I'm new in Spring Security and I'm sorry for my English.
I have a rememberme cookie and when the request comes to the filter RememberMeAuthenticationFilter - it makes authentication, breaks the next processing and immediately returns to user only 200 status with defaultUrl, something like
{"redirectTo":"/","success":true,"username":"userName","roles":[listOfRoles]}
in here
public RememberMeAuthenticationFilter(AuthenticationManager authenticationManager,
RememberMeServices rememberMeServices) {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
...
if (successHandler != null) { // <<<<<<<<<<<<<<<<<In here the request breaks.
successHandler.onAuthenticationSuccess(request, response,
rememberMeAuth);
return;
}
...
chain.doFilter(request, response);
}
}
Tell me please how to do next: the request goes down throw the filter after successful authentication with rememberme cookie to chain.doFilter(request, response);
And after all filters go to controller method which user asks.
I find the solution, if somebody interesting. The solution was not to inject authenticationSuccessHandler to RememberMeAuthenticationFilter. I redefined the bean RememberMeAuthenticationFilter (thats by default defined inside grails) and not inject authenticationSuccessHandler. And thats why this code not processing and go to chain.doFilter.
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);
}
}
}
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!