Search code examples
springjerseyjax-rsjax-wsservlet-filters

Resource not invoked after Jersery Request Filter


I have a two SpringServlets defined, one of which directs to a custom filter

@WebServlet(urlPatterns = { "/" }, initParams = {
    @WebInitParam(name = "com.sun.jersey.config.property.packages", value = "com.x.y.resource"),
    @WebInitParam(name = "com.sun.jersey.api.json.POJOMappingFeature", value = "true") })
public class JerseyServlet extends SpringServlet
{
}

@WebServlet(name = "secure", urlPatterns = "/secure/*", initParams = {
    @WebInitParam(name = "com.sun.jersey.config.property.packages", value = "com.x.y.resource"),
    @WebInitParam(name = "com.sun.jersey.spi.container.ContainerRequestFilters", value = "com.x.y.resource.OAuthFilter"),
    @WebInitParam(name = "com.sun.jersey.api.json.POJOMappingFeature", value = "true") })
public class JerseySecureServlet extends SpringServlet
{
}

The idea being that any URLs that contain "/secure/" are directed to the OAuthFilter to validate the request by the OAuth headers. All other URLs are just handled normally.

For any request sent to a URL not containing "/secure/", the appropriate JAX-RS resource class is invoked correctly. However, for URLs containing "/secure/" the OAuthFilter is invoked correctly, but the JAX-RS annotated Resource class is never invoked afterwards.

Here is an example secure resource

@Component
@Scope("request")
@Path("/secure/example")
public class SecureResource
{
    @GET
    ...
}

and here is the OAuthFilter

@Provider
@Component
public class OAuthFilter implements ContainerRequestFilter
{
    public static final String AUTHORIZED_USER = "authorized_user";

    @Autowired
    AccessTokenService accessTokenService;

    @Autowired
    UserService userService;

    @Context
    HttpServletRequest httpRequest;

    @Override
    public ContainerRequest filter(ContainerRequest containerRequest)
    {
        OAuthServerRequest request = new OAuthServerRequest(containerRequest);
        OAuthParameters params = new OAuthParameters();
        params.readRequest(request);

        String accessToken = params.getToken();

        if (accessToken == null)
        {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }

        String userId = accessTokenService.getUserIdForToken(accessToken);

        if (userId == null)
        {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }

        User user = userService.get(userId);

        if (user == null)
        {
            throw new WebApplicationException(Status.NOT_FOUND);
        }

        httpRequest.setAttribute(AUTHORIZED_USER, user);

        return containerRequest;
    }
}

It looks like once the JerseySecureServlet with the "/secure/*" mapping is selected and the OAuthFilter is invoked the baseURI is "http:/ip:port/context/secure" and the path is simply "/example", and no Resource corresponds to this path, so nothing is invoked. What should I be doing instead to only apply this filter to URLs that contain "/secure/"?


Solution

  • I have solved the problem, but I am not 100% sure if my solution is the correct way to do it. I have changed the annotation on the filtered serlvet to be @WebFilter, giving me

    @WebServlet(urlPatterns = { "/*" }, initParams = {
        @WebInitParam(name = "com.sun.jersey.config.property.packages", value = "com.x.y.resource"),
        @WebInitParam(name = "com.sun.jersey.api.json.POJOMappingFeature", value = "true") })
    public class JerseyServlet extends SpringServlet
    {
    }
    
    @WebFilter(urlPatterns = "/secure/*", initParams = {
        @WebInitParam(name = "com.sun.jersey.config.property.packages", value = "com.x.y.resource"),
        @WebInitParam(name = "com.sun.jersey.spi.container.ContainerRequestFilters", value = "com.x.y.resource.OAuthFilter"),
        @WebInitParam(name = "com.sun.jersey.api.json.POJOMappingFeature", value = "true") })
    public class JerseySecureFilter extends SpringServlet
    {
    }
    

    and this works. A better solution will be accepted over this one.