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/"?
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.