What is the proper replacement of the Resteasy 3.X PreProcessInterceptor?

20,751

Solution 1

RESTEasy 3.x.x conforms to the JAX-RS 2.0 specification.

What you are trying to do could be accomplished (maybe better) with:

@Provider
public class SecurityInterceptor 
      implements javax.ws.rs.container.ContainerRequestFilter {
     @Override
     public void filter(ContainerRequestContext requestContext){
       if (not_authenticated){ requestContext.abortWith(response)};
     }
}

since the ReaderInterceptor is invoked only if the underlying MessageBodyReader.readFrom is called by the standard JAX-RS pipeline, not fromthe application code.

The reason why your interceptor is not called, though, could be the @ServerInterceptor annotation, which is a RESTEasy extension.

The spec states at §6.5.2 that a interceptor is globally registered, unless the @Provider is annotated with a @NameBinding annotation, but I don't know if RESTEasy can handle a @ServerInterceptor if it's not explicitly registered as shown in RestEASY Interceptor Not Being Called

Solution 2

If you need to get access to the underlying java.lang.reflect.Method (like you used to be able to get by implementing AcceptedByMethod), you can do the following:

ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) 
            requestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker");
Method method = methodInvoker.getMethod();

Solution 3

I also wanted to get access to the underlying java.lang.reflect.Method and tried mtpettyp's answer with Resteasy 3.0.8, but that was returning null on the getProperty call. I am also using Spring and resteasy-spring although I don't believe that should impact this at all.

If you run into my situation and are implementing a Post Matching ContainerRequestFilter (you kind of have to if you were expecting to get the matched resource method anyway) then you can actually cast the ContainerRequestContext to the implementation Resteasy has for the Post Match scenario. The PostMatchContainerRequestContext has a reference to the ResourceMethodInvoker.

public void filter(ContainerRequestContext context) throws IOException {
    PostMatchContainerRequestContext pmContext = (PostMatchContainerRequestContext) context;

    Method method = pmContext.getResourceMethod().getMethod();

    /* rest of code here */
}
Share:
20,751
Gilberto Torrezan
Author by

Gilberto Torrezan

Glad to help #SOreadytohelp

Updated on March 03, 2020

Comments

  • Gilberto Torrezan
    Gilberto Torrezan about 4 years

    I'm building rest service using an authentication/authorization mechanism as described in this tutorial: http://howtodoinjava.com/2013/06/26/jax-rs-resteasy-basic-authentication-and-authorization-tutorial/

    Basically it uses the PreProcessInterceptor interface to scan the target method for annotations (from javax.annotation.security package) which describe the required roles to access that method. As the the authenticator here is an interceptor, it can cancel the target method invocation, returning a 401 (unauthorized) if needed.

    The problem here is that the interface org.jboss.resteasy.spi.interception.PreProcessInterceptor is deprecated in the current RestEasy version (3.0.1), and I'm having problems trying to implement the same behaviour with the standard JAX-RS interfaces.

    I'm using the javax.ws.rs.ext.ReaderInterceptor interface to intercept the call. But somehow the server never calls it: the interceptor is just ignored.

    I'm registering the interceptors/resources the same way as I did with the former PreProcessInterceptor, and using the same @Provider and @ServerInterceptor annotations:

    ServerApplication:

    public class ServerApplication extends javax.ws.rs.core.Application {
    
         private final HashSet<Object> singletons = new LinkedHashSet<Object>();
    
         public ServerApplication() {
             singletons.add(new SecurityInterceptor());
             singletons.add( ... ); //add each of my rest resources
         }
    
        @Override
        public Set<Class<?>> getClasses() {
            HashSet<Class<?>> set = new HashSet<Class<?>>();
            return set;
        }
    
        @Override
        public Set<Object> getSingletons() {
            return singletons;
        }
    }
    

    SecurityInterceptor:

    @Provider
    @ServerInterceptor
    public class SecurityInterceptor implements javax.ws.rs.ext.ReaderInterceptor {
         @Override
         public Object aroundReadFrom(ReaderInterceptorContext context){
                //code that is never called... so lonely here...
         }
    }
    

    Any insights about how can I solve this problem?

    Thank you.

  • Gilberto Torrezan
    Gilberto Torrezan almost 11 years
    Using the ContainerRequestFilter, how can I get the annotations of the target method? The filter / interceptor needs to know that to properly allow or deny the invocation, based on the user roles.
  • Carlo Pellegrini
    Carlo Pellegrini almost 11 years
    ContainerRequestFilter.getUriInfo().getMatchedResources() returns the list of the matched resource objects. There you can parse the annotations matching the actual called methods
  • Gilberto Torrezan
    Gilberto Torrezan almost 11 years
    I think you meant requestContext.getUriInfo().getMatchedResources(). Anyway, this method is not quite as easy to use like in the former PreProcessInterceptor, since I don't have direct access to the target java.lang.reflect.Method. But I'll mark the answer as accepted, since it solves the problem.
  • Carlo Pellegrini
    Carlo Pellegrini almost 11 years
    It's what I meant. Sorry for the typo.. Have you investigated instead using requestContext.setSecurityContext() to inject your authentication and then delegate to a @RolesAllowed annotation?
  • arun_kk
    arun_kk over 9 years
    How about getting a httpRequest from the requestContext. I have a requirement to read the InputStream from the httpRequest. how to do that ?Or is a way there i can get InputStream from the containerrequestcontext?
  • Vinh.TV
    Vinh.TV about 8 years
    I getting null reference from methodInvoker, don't know why.
  • MathieuB
    MathieuB almost 7 years
    Injecting ResourceInfo using @Context annotation will give you access to the target Method. See related: stackoverflow.com/a/29201811/3323963