munHunger
munHunger

Reputation: 2999

Adding an annotation to a method to note if it is allowed to run

I have implemented parts of my own security framework in java and I have run into a small-ish problem.

I want to be able to check if a user has access to a method or not. I can do this by simply adding a check inside of the method like the following:

@GET
public Response getResource() throws Exception
{
    if (AuthUtils.isAuthenticated(request, "ROLE1", "ROLE2"))
        return Response.ok("Hello World!").build();
    else
        return Response.status(HttpServletResponse.SC_UNAUTHORIZED).build();
}

Where you supply a list of roles that are authorized to use the function.

However in an ideal world, I would like to do something like the following

@Secure(roles = {"ROLE1", "ROLE"})
@GET
public Response getResource() throws Exception
{
    return Response.ok("Hello World!").build();
}

Where it by default returns an unathorized response on all methods annotated with @Secure where the user does not have the correct roles.

Is something like this possible with Java? and if so, how?

Upvotes: 3

Views: 1341

Answers (3)

wi2ard
wi2ard

Reputation: 1555

What you need to do is make an aspect, ie. a method that gets called every time before a specific "target method" is called. You can use Spring as mentioned before but you can also do this using just Java core and Reflection. To do this, you will need to have a proxy method that calls your actual "target method" only if the user has the right permissions. Alternatively the proxy would throw an exception. So what this means is that you also need to make your dependency injection dynamic.

For a very simple application you don't even need annotations. Say you want to secure the access to the method Service::getSecuredResource :

public interface Service {
    Object getSecuredResource();
}

public class ServiceImpl implements Service {
    public Object getSecuredResource() {
        System.out.println("in my secure method");
        return "something private";
    }
}

public class ClientController {
    private Service service;     //line 1

    public void doSomething(){
        service.getSecuredResource();
    }

    public void setService(Service service)...
}

public final class AuthenticationService {

    public static void authenticate()...

    public static boolean isAuthenticated()...//do permission checks here
}

A simple solution would be:

public class Main {
    public static void main(String[] args) {
        final ClientController clientController = new ClientController();

        injectDependencies(clientController);

        clientController.doSomething();
    }

    private static void injectDependencies(ClientController clientController) {       //line 2
        final Service serviceProxy = new Service() {
            private Service targetObject = new ServiceImpl();

            public Object getSecuredResource() {
                if (AuthenticationService.isAuthenticated()) {
                    return targetObject.getSecuredResource();
                }
                throw new SecurityException("you're not authorised");
            }
        };

        clientController.setService(serviceProxy);
    }
}

Of course, if you want something more dynamic, you will need to have annotations and use Reflection to create dynamic proxies and to inject the dependencies. I would annotate the service declaration (line 1) with my custom annotation, say MyInject. Then Main::injectDependencies method (line 2) would be replaced by something like this:

   private static void injectDependencies(ClientController clientController) {
       Arrays.stream(clientController.getClass().getFields())
               .filter(field -> field.getAnnotation(MyInject.class)!=null)
               .forEach(field -> injectField(field, clientController));
   }

   private static void injectField(Field field, ClientController clientController) {
       InvocationHandler handler = new InvocationHandler() {
           @Override
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               //verify here that the user has the right permissions for the called method
           }
       };
       Service serviceProxy = (Service) Proxy.newProxyInstance(
               Service.class.getClassLoader(),
               new Class[] { Service.class },
               handler);
       clientController.setService(serviceProxy);
   }

Upvotes: 1

Paul Samsotha
Paul Samsotha

Reputation: 209112

If you're using Jersey 2.x, just use the RolesAllowedDynamicFeature. You need to register it with your application. This will handle the authorization. You would use the annotation @RolesAllowed. It can go at the class level or method level

@RolesAllowed({"ROLE1", "ROLE"})
@GET
public Response getResource() throws Exception

If you are using Servlet Authentication, then the roles will be populated in the HttpServletRequest#getUserRoles. Here you will not need to do anything else. I assume servlet security is what you are using from the looks of this code

if (AuthUtils.isAuthenticated(request, "ROLE1", "ROLE2"))

I'm guessing the request is the HttpServletRequest.

If you're not using Servlet security, then to make this work, you need to use a Jersey filter to set the SecurityContext. Jersey will use the SecurityContext to check the roles. You can see an example in this post.

See also:

Upvotes: 1

Rakib Hasan
Rakib Hasan

Reputation: 315

yes, possible. We can use spring security plugin/library to do this. In Spring We can follow Spring security In Grails We can follow Spring Security Plugin

Upvotes: -1

Related Questions