From b317b7e70de2621fb25806b611126bcaf8793beb Mon Sep 17 00:00:00 2001
From: Lin Gao <lgao@redhat.com>
Date: Thu, 2 Mar 2017 10:17:25 +0800
Subject: [PATCH] [ISPN-7535] Cache creation requires specific permissions when
 using security manager

Move Util.getClassLoaders() and ReflectionUtil.invokeAccessibly() to doPrivileged() when security manager is enabled
---
 .../commons/util/ReflectionUtil.java          | 13 +---
 .../commons/util/SecurityActions.java         | 63 +++++++++++++++++++
 .../org/infinispan/commons/util/Util.java     | 30 ++-------
 3 files changed, 68 insertions(+), 38 deletions(-)

diff --git a/commons/src/main/java/org/infinispan/commons/util/ReflectionUtil.java b/commons/src/main/java/org/infinispan/commons/util/ReflectionUtil.java
index df9526d83af0..9b70e1430c6f 100644
--- a/commons/src/main/java/org/infinispan/commons/util/ReflectionUtil.java
+++ b/commons/src/main/java/org/infinispan/commons/util/ReflectionUtil.java
@@ -6,7 +6,6 @@
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -163,17 +162,7 @@ private static Field findFieldRecursively(Class<?> c, String fieldName) {
     * @param parameters parameters
     */
    public static Object invokeAccessibly(Object instance, Method method, Object[] parameters) {
-      try {
-         method.setAccessible(true);
-         return method.invoke(instance, parameters);
-      } catch (InvocationTargetException e) {
-         Throwable cause = e.getCause() != null ? e.getCause() : e;
-         throw new CacheException("Unable to invoke method " + method + " on object of type " + (instance == null ? "null" : instance.getClass().getSimpleName()) +
-                                        (parameters != null ? " with parameters " + Arrays.asList(parameters) : ""), cause);
-      } catch (Exception e) {
-         throw new CacheException("Unable to invoke method " + method + " on object of type " + (instance == null ? "null" : instance.getClass().getSimpleName()) +
-               (parameters != null ? " with parameters " + Arrays.asList(parameters) : ""), e);
-      }
+      return SecurityActions.invokeAccessibly(instance, method, parameters);
    }
 
    public static Method findGetterForField(Class<?> c, String fieldName) {
diff --git a/commons/src/main/java/org/infinispan/commons/util/SecurityActions.java b/commons/src/main/java/org/infinispan/commons/util/SecurityActions.java
index 91e58fbecd21..72d721349181 100644
--- a/commons/src/main/java/org/infinispan/commons/util/SecurityActions.java
+++ b/commons/src/main/java/org/infinispan/commons/util/SecurityActions.java
@@ -1,7 +1,12 @@
 package org.infinispan.commons.util;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Arrays;
+
+import org.infinispan.commons.CacheException;
 
 /**
  * Privileged actions for the package
@@ -70,4 +75,62 @@ static String getProperty(String name) {
 
       return SysProps.PRIVILEGED.getProperty(name);
    }
+
+   private static <T> T doPrivileged(PrivilegedAction<T> action) {
+      if (System.getSecurityManager() != null) {
+         return AccessController.doPrivileged(action);
+      } else {
+         return action.run();
+      }
+   }
+
+   static Object invokeAccessibly(Object instance, Method method, Object[] parameters) {
+       return doPrivileged((PrivilegedAction<Object>) () -> {
+          try {
+             method.setAccessible(true);
+             return method.invoke(instance, parameters);
+          } catch (InvocationTargetException e) {
+             Throwable cause = e.getCause() != null ? e.getCause() : e;
+             throw new CacheException("Unable to invoke method " + method + " on object of type " + (instance == null ? "null" : instance.getClass().getSimpleName()) +
+                                            (parameters != null ? " with parameters " + Arrays.asList(parameters) : ""), cause);
+          } catch (Exception e) {
+             throw new CacheException("Unable to invoke method " + method + " on object of type " + (instance == null ? "null" : instance.getClass().getSimpleName()) +
+                   (parameters != null ? " with parameters " + Arrays.asList(parameters) : ""), e);
+          }
+       });
+   }
+
+   static ClassLoader[] getClassLoaders(ClassLoader appClassLoader) {
+      return doPrivileged((PrivilegedAction<ClassLoader[]>) () -> {
+         return new ClassLoader[] { appClassLoader,   // User defined classes
+               Util.class.getClassLoader(),           // Infinispan classes (not always on TCCL [modular env])
+               ClassLoader.getSystemClassLoader(),    // Used when load time instrumentation is in effect
+               Thread.currentThread().getContextClassLoader() //Used by jboss-as stuff
+         };
+      });
+   }
+
+   private static ClassLoader getOSGiClassLoader() {
+       // Make loading class optional
+       try {
+           Class<?> osgiClassLoader = Class.forName("org.infinispan.commons.util.OsgiClassLoader");
+           return (ClassLoader) osgiClassLoader.getMethod("getInstance", null).invoke(null);
+       } catch (ClassNotFoundException e) {
+           // fall back option - it can't hurt if we scan ctx class loader 2 times.
+           return Thread.currentThread().getContextClassLoader();
+       } catch (Exception e) {
+           throw new RuntimeException("Unable to call getInstance on OsgiClassLoader", e);
+       }
+   }
+
+   static ClassLoader[] getOSGIContextClassLoaders(ClassLoader appClassLoader) {
+      return doPrivileged((PrivilegedAction<ClassLoader[]>) () -> {
+         return new ClassLoader[] { appClassLoader,   // User defined classes
+               getOSGiClassLoader(), // OSGi bundle context needs to be on top of TCCL, system CL, etc.
+               Util.class.getClassLoader(),           // Infinispan classes (not always on TCCL [modular env])
+               ClassLoader.getSystemClassLoader(),    // Used when load time instrumentation is in effect
+               Thread.currentThread().getContextClassLoader() //Used by jboss-as stuff
+         };
+      });
+   }
 }
diff --git a/commons/src/main/java/org/infinispan/commons/util/Util.java b/commons/src/main/java/org/infinispan/commons/util/Util.java
index 97078494be4b..3febe48e4fd5 100644
--- a/commons/src/main/java/org/infinispan/commons/util/Util.java
+++ b/commons/src/main/java/org/infinispan/commons/util/Util.java
@@ -115,33 +115,11 @@ public static boolean isOSGiContext() {
 
    public static ClassLoader[] getClassLoaders(ClassLoader appClassLoader) {
       if (isOSGiContext()) {
-         return new ClassLoader[] { appClassLoader,   // User defined classes
-               getOSGiClassLoader(), // OSGi bundle context needs to be on top of TCCL, system CL, etc.
-               Util.class.getClassLoader(),           // Infinispan classes (not always on TCCL [modular env])
-               ClassLoader.getSystemClassLoader(),    // Used when load time instrumentation is in effect
-               Thread.currentThread().getContextClassLoader() //Used by jboss-as stuff
-         };
+         return SecurityActions.getOSGIContextClassLoaders(appClassLoader);
       } else {
-         return new ClassLoader[] { appClassLoader,   // User defined classes
-               Util.class.getClassLoader(),           // Infinispan classes (not always on TCCL [modular env])
-               ClassLoader.getSystemClassLoader(),    // Used when load time instrumentation is in effect
-               Thread.currentThread().getContextClassLoader() //Used by jboss-as stuff
-         };
-      }
-   }
-
-    private static ClassLoader getOSGiClassLoader() {
-        // Make loading class optional
-        try {
-            Class<?> osgiClassLoader = Class.forName("org.infinispan.commons.util.OsgiClassLoader");
-            return (ClassLoader) osgiClassLoader.getMethod("getInstance", null).invoke(null);
-        } catch (ClassNotFoundException e) {
-            // fall back option - it can't hurt if we scan ctx class loader 2 times.
-            return Thread.currentThread().getContextClassLoader();
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to call getInstance on OsgiClassLoader", e);
-        }
-    }
+         return SecurityActions.getClassLoaders(appClassLoader);
+      }
+   }
 
    /**
     * <p>
