Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 243
Anatoly Avatar asked Aug 26 '15 13:08

Anatoly


People also ask

What is the use of @produce annotation of JAX-RS?

The @Produces Annotation If applied at the method level, the annotation overrides any @Produces annotations applied at the class level. If no methods in a resource are able to produce the MIME type in a client request, the JAX-RS runtime sends back an HTTP “406 Not Acceptable” error.

How will you enable validation on the resource in the following bean class?

To validate these entity classes, use the @Valid annotation on the method parameter. For example, the following class is a user-defined class containing both standard and user-defined validation constraints.


1 Answers

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:

  • Filters and Interceptors
like image 59
Paul Samsotha Avatar answered Oct 06 '22 03:10

Paul Samsotha