package org.gcube.common.authorization.client.helper; import static org.gcube.common.authorization.client.Constants.authorizationService; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject; import org.gcube.common.authorization.client.exceptions.UnauthorizedAccessException; import org.gcube.common.authorization.library.AuthorizationEntry; import org.gcube.common.authorization.library.PolicyUtils; import org.gcube.common.authorization.library.annotations.AuthorizationControl; import org.gcube.common.authorization.library.policies.Action; import org.gcube.common.authorization.library.policies.Policy; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.ServiceIdentifier; /** * enables authorization control on classes using proxies * * when a user in not allowed to call a method annotated with {@link AuthorizationControl} * an {@link UnauthorizedAccessException} is thrown * * @author lucio lelii * */ public class Authorization { private static Map, Class> proxyClassMap = new HashMap, Class>(); private static ProxyFactory proxyfactory = new ProxyFactory(); private static Class getProxied(Class proxyClass){ if (proxyClassMap.containsKey(proxyClass)) return proxyClassMap.get(proxyClass); proxyfactory.setSuperclass(proxyClass); Class proxied=proxyfactory.createClass(); proxyClassMap.put(proxyClass, proxied); return proxied; } public static T getAuthorizedInstance(Class proxyClass){ Class proxied = getProxied(proxyClass); Object obj; try { obj = proxied.newInstance(); MethodHandler handler = new MethodHandler() { public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { if (thisMethod.isAnnotationPresent(AuthorizationControl.class) && !thisMethod.getName().equals("getServiceName") && !thisMethod.getName().equals("getServiceClass")){ if (SecurityTokenProvider.instance.get()==null) throw new RuntimeException("the Security token is not set"); Authorizable obj = (Authorizable) self; Action[] modes = null; if (thisMethod.isAnnotationPresent(AuthorizationControl.class)) modes = thisMethod.getAnnotation(AuthorizationControl.class).check(); checkAuthorization(obj.getServiceClass(), obj.getServiceName(), modes); } return proceed.invoke(self, args); } }; ((ProxyObject)obj).setHandler(handler); return proxyClass.cast(obj); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } public static void checkAuthorization(String serviceClass, String serviceName, Action ... modes) throws Exception{ if (modes==null || modes.length==0) return; if (SecurityTokenProvider.instance.get()==null) throw new UnauthorizedAccessException("the Security token is not set"); List modesList = Arrays.asList(modes); AuthorizationEntry entry = authorizationService().get(SecurityTokenProvider.instance.get()); if (entry.getPolicies()!=null){ //DO we need a library identifier ?? ServiceIdentifier serviceIdentifier = new ServiceIdentifier(serviceClass, serviceName, "*"); for (Policy policy: entry.getPolicies()) if (PolicyUtils.isPolicyValidForClient(policy.getServiceAccess(), serviceIdentifier)) if (modesList.contains(policy.getMode()) || policy.getMode()==Action.ALL) throw new UnauthorizedAccessException("the invoked method is protected by the Authorization system, cannot be invoked by "+entry.getClientInfo().getId()); } } }