Reputation: 2999
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
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
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
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