Anatoly
Anatoly

Reputation: 5241

Can I add a custom annotation to JAX-RS method to validate access?

For example I've the following method:

@GET
    @Path("/get/current")
    public Response getCurrentInfo(@HeaderParam("Authorization") String token){

        Gson gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS")
        .setPrettyPrinting().create();          

        String email = SecurityProvider.decryptTokenAndGetEmail(token);

        if(DB.isAccessPermitted(email)){
            Info info = DB.getCurrentInfo();
            String json = gson.toJson(info);
            return Response.ok(json).build();
        }else{
           return Response.status(401).build();
        }

    }

So instead to write in every method:

          if(DB.isAccessPermitted(email)){
                Info info = DB.getCurrentInfo();
                String json = gson.toJson(info);
                return Response.ok(json).build();
            }else{
               return Response.status(401).build();
            }

I will create for example @SecurityCheck annotation, annotate every method which has limited access and perform check only in a single place. Is it possible to achieve with annotations and can MVCE be provided? Thank you.

Upvotes: 9

Views: 6711

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 209132

If you are using JAX-RS 2.0, you can inject ResourceInfo into a ContainerRequestFilter, then get the java.lang.reflect.Method from the. From the Method, you can get the annotation. For example

@Provider
@Priority(Priorities.AUTHENTICATION)
public class SecurityFilter implements ContainerRequestFilter {

    @Context
    private ResourceInfo resourceInfo;

    // You can get the header from the `requestContext`
    @Override
    public void filter(ContainerRequestContext requestContext) {
        Method resourceMethod = resourceInfo.getResourceMethod();
        SecurityCheck annotation = resourceMethod.getAnnotation(SecurityCheck.class);
        // get some value from annotation

        if (notAllowedAccess) {
            throw new WebApplicationException(403);
        }
    }
}

This (the ResourceInfo) is only necessary though if you need to get some value from the annotation, like @SecurityCheck("SomeRoleAllowed").

If you don't need the value, and all you want is for any method annotated to be filtered, then you can either create a DynamicFeature, where you bind each method to a filter. For example

@Provider
public class SecurityCheckDynamicFeature implements DynamicFeature {
    @Override
    public void configure(ResourceInfo info, FeatureContext context) {
        Method method = info.getResourceMethod();
        SecurityCheck annotation = method.getAnnotation(SecurityCheck.class);
        if (annotation != null) {
            context.register(SecurityFilter.class);
        }
    }
}

Or another way is to just use @NameBinding on the custom annotation

@NameBinding
@Target(...)
@Retention
public @interface SecurityCheck {}

Then you need to annotate the SecurityFilter class with the annotation also. Any method or class annotated will go through the filter.

Other Resources:

Upvotes: 19

Related Questions