OPTIONS request handler should be called before API handler - java

I have a working #RestController component that yields API web endpoints.
This is one of those endpoints
#CrossOrigin
#GetMapping(API_VERSION + PLAYER + METHOD_FETCH + "/{uid:^[0-9]*$}")
public Player fetchPlayer(#PathVariable("uid") String uid) {
return mongoTemplate.findById(uid, Player.class);
}
Now when using my Vue.js App I call this endpoint. The problem is the axios http client library turns a get request that has authentication headers into a options request to probe the server for actual access.
Now I need to consume this options request and have it be enabled for CORS. I did the following therefore:
#RestController
#Log
#RequestMapping("/**")
public class AuthenticationEndpoint {
#CrossOrigin
#RequestMapping(method = RequestMethod.OPTIONS)
public void handleOptionRequest(){
log.info("option request handled");
}
}
I map it to every url so it "should" intercept every OPTIONS request. But it does not. When having a
GET http://{{host}}:80/api/v0.1/player/fetch/4607255831
Authorization: Basic MTIzNTM2NDMyNDphYmMxMjM=
The more specific API web endpoint is handled before the OPTIONS handler.
How can I actually put the OPTIONS handler before the others in Spring MVC?
I want it to act like an interceptor
OR
What is the best practise way to achieve the wanted behaviour? I kinda feel I am hacking around a better solution.

How can I actually put the OPTIONS handler before the others in Spring MVC? I want it to act like an interceptor.
Your can create a component a class that implements Filter interface and give it a High order :
#Component
#Order(1)
public class RequestInterceptor implements Filter {
#Override
public void doFilter
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String httpMethod = req.getMethod();
if(HttpMethod.OPTIONS.name().equals(httpMethod)){
//do something here before reaching the method handler
}
chain.doFilter(request, response);
}
// other methods
}
Or you can extends OncePerRequestFilter.java and make the same check as above in the doFilterInternal method.
EDIT
If you want to control whether to proceed handling a giving request or not you can use HandlerInterceptor :
A HandlerInterceptor gets called before the appropriate HandlerAdapter
triggers the execution of the handler itself. This mechanism can be
used for a large field of preprocessing aspects, e.g. for
authorization checks, or common handler behavior like locale or theme
changes. Its main purpose is to allow for factoring out repetitive
handler code.
HandlerInterceptor is basically similar to a Servlet
Filter, but in contrast to the latter it just allows custom
pre-processing with the option of prohibiting the execution of the
handler itself, and custom post-processing. Filters are more powerful,
for example they allow for exchanging the request and response objects
that are handed down the chain. Note that a filter gets configured in
web.xml, a HandlerInterceptor in the application context.
#Comonent
public class LoggerInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception{
// do checks and decide wether to complete or to stop here
// true if the execution chain should proceed with the next interceptor or the handler itself.
// Else, DispatcherServlet assumes that this interceptor has already dealt with the response itself.
return true;
}
// other methods
}

Related

How to get HttpServletRequest and HttpServletResponse in SOAP interceptor in spring

I have a spring boot application with SOAP endpoints and an interceptor class which implements EndpointInterceptor.The problem is, there is no overridden methods available in this interface which have access to HttpServletRequest and HttpServletResponse.
My question is :
How can I get HttpServletRequest and HttpServletResponse objects whenever an API request comes using a SOAP interceptor (I saw many examples which is using WebMvcConfigurerAdapter and HandlerInterceptor but it is working only for Rest #Controller. In my case it is SOAP with #Endpoint and it is not calling the overridden methods).
If that is not possible , how can i get make this object from MessageContext since the handleRequest overridden method is having that parameter as show below
#Override
public boolean handleRequest(MessageContext messageContext,
Object endpoint) throws Exception {
LOG.info("Endpoint Request Handling");
return true;
}
Spring-ws has TransportContext class for storing the current underlying connection. You can access it via TransportContextHolder class statically in the code.
If you are sure that the underlying connection is a HttpServletConnection then you could do something like this inside the interceptor methods:
TransportContext ctx = TransportContextHolder.getTransportContext();
HttpServletRequest req = ((HttpServletConnection) ctx.getConnection()).getHttpServletRequest();
If you want to manipulate (Override) the HttpServletRequest and HttpServletResponse
before/after reaching the endpoints using Interceptors would be a bad idea as the requests reached at that level would be preprocessed and would not give you the option of modification.
You could use Filters instead of Interceptors to achieve what your trying to do.

Simple REST endpoints authentication

I am learning how secure my endpoints, but everything i searched for contains pretty complicated examples, that didn't really answerd my question, and for now, just for the sake of this example project, i was looking for something simple.
My current solution is to make endpoints return like this:
return authenticate(request.headers) ? cityService.getCity() : utils.unauthenticatedResponse();
Where authenticate(request.headers) checks for token in header.
The thing i want to improve is to have that authenticate method run before every request to my endpoints (aside from login and register), so i can just return cityService.getCity(), and i won't have to make that check every time.
Will appreciate every answers, but please make it easy yo understand, since i am just a beginner.
Since you need to run the authenticate method before every request, you need to implement a Filter. It's pretty straightforward and you can get the steps and template to implement a filter here.
Every request to an endpoint will first pass through the filter (this is configurable), where you can have the authenticate method and then allow it further accordingly.
For starters, you can implement a filter like below:
#Component
public class AuthFilter implements Filter {
#Override
public void doFilter
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if(authenticate(req.getHeaders)){
chain.doFilter(request, response);
} else {
//else logic, ie throw some exception in case authenticate returns false
}
}
}
The advantages that this provides are :
You can implement multiple filters
You can provide Order/priority to filters
You can configure which endpoints need to pass through the filter and which ones do not.
You can use ContainerRequestFilter (if you are using Spring/Tomcat)
Every request coming to the server will go through this filter, so you can implement your code in it.

How do we listen to any URL/end point which is not marked with #RestController annotation in Spring?

Is there a way that I can listen to any particular request without that request being present in any of the request mappings in Spring ? I am trying to build a gateway functionality where i need to redirect a request to a downstream API by inspecting the request URI. I would need to see if I have the downstream/internal api for that particular request and forward to the downstream API if i have that mapping.
I currently have all the downstream mapping in the database.
For example:
Client facing uri: http://external_host/api/xyz/
downstream uri: http://downstream_host/api/abc
I store this mapping of client facing uri and downstream uri in the database. So I just to want to listen to all the requests that are hitting my service and then examine on my own if I can forward the request or not based on the mapping I have stored.
All I could think was to have a controller that would accept any request but I do not like this approach as this seems pretty naive.
#RestController
#RequestMapping(value = "*")
public class TestController {
#RequestMapping(value = "/*", method = RequestMethod.GET)
public void GetRequestUri() {
System.out.println("test");
}
}
I hope my question was elaborate enough.
You could use Netflix Zuul which is a proxy that is doing routing and filtering, but with a different way.
If you want to build your own proxy - discovery service you need to use only one endpoint, so your implementation has nothing wrong!
Approach - Creating a filter
Reference: How to register a servlet filter in Spring MVC
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class RootFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
// Evaluate the request path
chain.doFilter(request, response);
} catch (Exception ex) {
//handle Exceptions.
}
}
}
web.xml
<filter>
<filter-name>RootFilter</filter-name>
<filter-class>com.....RootFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RootFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new RootFilter()};
}
}
Approach - Creating Interceptor
Reference: Spring 3 MVC Interceptor tutorial
Spring MVC provides a powerful mechanism to intercept an http request. Similar to Servlet Filter concept, Spring MVC provides a way to define special classes called Interceptors that gets called before and after a request is served.
Each interceptor you define must implement org.springframework.web.servlet.HandlerInterceptor interface. There are three methods that need to be implemented.
preHandle(..) is called before the actual handler is executed;
The preHandle(..) method returns a boolean value. You can use this method to break or continue the processing of the execution chain. When this method returns true, the handler execution chain will continue; when it returns false, the DispatcherServlet assumes the interceptor itself has taken care of requests (and, for example, rendered an appropriate view) and does not continue executing the other interceptors and the actual handler in the execution chain.
postHandle(..) is called after the handler is executed;
afterCompletion(..) is called after the complete request has finished.
These three methods should provide enough flexibility to do all kinds of preprocessing and postprocessing.

How can I lookup the method being called on a Handler from a Spring HandlerInterceptor?

I have a Spring HandlerInterceptor intercepting the frontend URL's in my application (/app/*). I want to determine which action method in the Handler is about to be invoked from within the HandlerInterceptor. Is there a way to look that up, do I need to inject something into the interceptor that can look that up based on the requested path?
The Interceptor is like this:
public class PageCacheInterceptor implements HandlerInterceptor {...}
It is mapped like this:
<mvc:interceptors>
<bean class="com.example.web.interceptors.PageCacheInterceptor" />
</mvc:interceptors>
Background (because I know you'll ask!). I am adding simple page caching to my app and want to use an annotation like #Cacheable on each suitable method in the controller. The interceptor can then determine whether to cache a response based on the action that created it.
For example:
#RequestMapping(value = "", method = RequestMethod.GET)
#Cacheable(events={Events.NEW_ORDER,Events.NEW_STAT})
public String home(Model model) {...}
The events are the ones that cause the cache to be invalidated. For example /widget/list action would have it's cached response invalidated by a new widget being saved.
Edit: I've upgraded to the latest Spring 3.1 M2, as this blog post hinted at features I need, but it's not clear whether injecting these new classes or sub-classing them will be required. Has any one used them to retrieve the HandlerMethod in an interceptor?
Ok so the solution was actually really easy:
1) Upgrade to Spring 3.1
2) RTFM (properly)
For example a HandlerInterceptor can cast the handler from Object to HandlerMethod and get access to the target controller method, its annotations, etc
3) Cast the handler object to HandlerMethod in the Interceptor.
Then you can do this sort of thing:
HandlerMethod method = (HandlerMethod) handler;
Cacheable methodAnnotation = method.getMethodAnnotation(Cacheable.class);
if (methodAnnotation != null) {
System.out.println("cacheable request");
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre-handle");
HandlerMethod hm=(HandlerMethod)handler;
Method method=hm.getMethod(); if(method.getDeclaringClass().isAnnotationPresent(Controller.class)){
if(method.isAnnotationPresent(ApplicationAudit.class))
{
System.out.println(method.getAnnotation(ApplicationAudit.class).value());
request.setAttribute("STARTTIME",System.currentTimemillis());
}
}
return true;
}
This post has more details,hope this helps http://www.myjavarecipes.com/spring-profilingaudit-using-mvc-filters/

Obtaining actual parameter values in a Jersey ResourceFilterFactory

I want to implement custom authorisation in my REST services using Jersey. This custom authorisation inspects annotations on methods as well as the actual parameters that a
method receives.
My jax-rs annotated method looks like:
#GET
#Path("customers")
#Requires(Role.CustomerManager)
public Customer getCustomer(#ParseFromQueryString #CheckPermission final Customer customer) {
// ...
}
The #ParseFromQueryString is an annotation that indicates Jersey (through an Injectable provider) to unmarshall a Customer from a query string. The code for that looks like:
public class QueryStringCustomerInjectable implements Injectable<Customer> {
public Customer getValue() {
final Customer customer = new Customer();
// ... a UriInfo was injected using the #Context annotation
// ... extract parameters from QueryString and use setters
return customer;
}
}
The #CheckPermission annotation indicates my custom authoriser that permissions are to be checked on a customer. Some users have access to information on some customers. Similarly, the #Requires annotation takes a role that the invoker should have. These are not java's security roles (Strings), rather, they are enum values.
Using Jersey's ResourceDebuggingFilter as a starting point, I have been able to get to the point of knowing which method will be invoked. However, I still haven't figured out how to determine which parameters will actually be used to invoke the method.
At the top of my head, I can think of two work arounds:
A Method interceptor using Guice + Jersey.
Code this logic in the QueryStringCustomerInjectable, but this seems a bit sloppy. It would be a class doing too much.
Yet, I would really like to do this using only Jersey / JAX-RS. I feel that I am so close!
Ideas? Pointers?
Thanks!
You should use Filters or Interceptors to handle all the information about method.
see Jersey Filter and Interceptors
For the Customer deserialization you could implement the javax.ws.rs.ext.ParamConverterProvider and register it into Jersey. Then you can inject it into your methods with #QueryParam("customer"). It's a bit more flexible since you can use it also with #BeanParam or #PathParam annotations.
Then you can use the ContainerRequestFilter. See as a reference how jersey does the Oauth1 for example OAuth1ServerFilter.
The next thing you can do is to create maybe a feature which will register the newly created filter (see Oauth1ServerFeature for a reference - I couldn't find the source code right now).
Good luck!
Why not using your own Servlet filter e.g.
public class YourFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// ..... httpReq.getUserPrincipal();
// then set what you need using ThreadLocal and use it inside your resource class
// do not forget to call
filterChain.doFilter(request, response); // at the end of this method
}
The last step is to register your servlet filter. This is done using web app's web.xml
It will intercept your HTTP requests before the actual code inside jersey resource is called.

Categories

Resources