I followed the Jersey tutorials to implement a completely custom SecurityContext
for my application. I created a custom ContainerRequestFilter
to set the SecurityContext
as follows:
package com.my.security;
@Provider
@Priority(Priorities.AUTHORIZATION)
public class SecurityRequestFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) {
requestContext.setSecurityContext(new MySecurityContext(requestContext));
}
public static final class MySecurityContext implements SecurityContext {
private String token;
public MySecurityContext(ContainerRequestContext requestContext) {
token = requestContext.getHeaderString("token");
}
@Override
public boolean isUserInRole(String role) {
return role.equals("admin") && token.equals("token-for-admin");
}
// other methods omitted
}
}
The logic in the isUserInRole
method is irrelevant, it's just a mock to make the point.
My endpoint looks something like:
package com.my.rest;
@PermitAll
@Path("/people")
public class PeopleRestService {
@RolesAllowed({"admin"})
@Path("/{email}")
@DELETE
public Response deletePerson(@PathParam("email") final String email) {
peopleService.removePerson(email);
return Response.ok().build();
}
}
Now I created a test (using JerseyTest
) configured with the packages where the two classes are:
@Override
protected Application configure() {
return new ResourceConfig().packages("com.my.rest", "com.my.security");
}
If I execute the following in my test:
Response response = target("people/[email protected]")
.request().header("token", "token-for-admin").delete();
Assert.assertEquals(200, response.getStatus());
everything works fine.
However, if I execute the following:
Response response = target("people/[email protected]").request().delete();
Assert.assertEquals(403, response.getStatus());
I would expect a 403 error code because I didn't set the authentication token. However, I get a 500 error code and a Grizzly (the container used for the test) HTML response with the string "Request failed.".
If I comment out the @Provider
annotation on the SecurityRequestFilter
class or remove the package com.my.security
from the test configuration, Jersey uses the container provided SecurityContext
and correctly returns a 403 instead.
Why is this happening? Shouldn't Jersey return a 403 with a custom SecurityContext
too? What am I missing?
I apologize for my dumbness. the logic in the isUserInRole
method is completely relevant! I had a NPE in there that I didn't see and was causing the 500.