Author: henrib
Date: Mon Nov 20 14:58:39 2017
New Revision: 1815813

URL: http://svn.apache.org/viewvc?rev=1815813&view=rev
Log:
JEXL:
Made permissions an explicit instance in preparation for future / further 
sandboxing capabilities

Modified:
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ClassMap.java
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java

Modified: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ClassMap.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ClassMap.java?rev=1815813&r1=1815812&r2=1815813&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ClassMap.java
 (original)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ClassMap.java
 Mon Nov 20 14:58:39 2017
@@ -63,8 +63,8 @@ final class ClassMap {
      * This is the cache to store and look up the method information.
      * <p>
      * It stores the association between:
-     *  - a key made of a method name and an array of argument types.
-     *  - a method.
+     * - a key made of a method name and an array of argument types.
+     * - a method.
      * </p>
      * <p>
      * Since the invocation of the associated method is dynamic, there is no 
need (nor way) to differentiate between
@@ -87,18 +87,19 @@ final class ClassMap {
      * Standard constructor.
      *
      * @param aClass the class to deconstruct.
-     * @param log the logger.
+     * @param permissions the permissions to apply during introspection
+     * @param log    the logger.
      */
     @SuppressWarnings("LeakingThisInConstructor")
-    ClassMap(Class<?> aClass, Log log) {
+    ClassMap(Class<?> aClass, Permissions permissions, Log log) {
         // eagerly cache methods
-        create(this, aClass, log);
+        create(this, permissions, aClass, log);
         // eagerly cache public fields
         Field[] fields = aClass.getFields();
         if (fields.length > 0) {
             Map<String, Field> cache = new HashMap<String, Field>();
             for (Field field : fields) {
-                if (Modifier.isPublic(field.getModifiers()) && 
Permissions.allow(field)) {
+                if (permissions.allow(field)) {
                     cache.put(field.getName(), field);
                 }
             }
@@ -149,16 +150,16 @@ final class ClassMap {
 
     /**
      * Find a Method using the method name and parameter objects.
-     *<p>
-     * Look in the methodMap for an entry.  If found,
+     * <p>
+     * Look in the methodMap for an entry. If found,
      * it'll either be a CACHE_MISS, in which case we
      * simply give up, or it'll be a Method, in which
      * case, we return it.
-     *</p>
+     * </p>
      * <p>
      * If nothing is found, then we must actually go
      * and introspect the method from the MethodMap.
-     *</p>
+     * </p>
      * @param methodKey the method key
      * @return A Method object representing the method to invoke or null.
      * @throws MethodKey.AmbiguousException When more than one method is a 
match for the parameters.
@@ -195,11 +196,12 @@ final class ClassMap {
     /**
      * Populate the Map of direct hits. These are taken from all the public 
methods
      * that our class, its parents and their implemented interfaces provide.
-     * @param cache the ClassMap instance we create
+     * @param cache          the ClassMap instance we create
+     * @param permissions    the permissions to apply during introspection
      * @param classToReflect the class to cache
-     * @param log the Log
+     * @param log            the Log
      */
-    private static void create(ClassMap cache, Class<?> classToReflect, Log 
log) {
+    private static void create(ClassMap cache, Permissions permissions, 
Class<?> classToReflect, Log log) {
         //
         // Build a list of all elements in the class hierarchy. This one is 
bottom-first (i.e. we start
         // with the actual declaring class and its interfaces and then move up 
(superclass etc.) until we
@@ -210,11 +212,11 @@ final class ClassMap {
         //
         for (; classToReflect != null; classToReflect = 
classToReflect.getSuperclass()) {
             if (Modifier.isPublic(classToReflect.getModifiers())) {
-                populateWithClass(cache, classToReflect, log);
+                populateWithClass(cache, permissions, classToReflect, log);
             }
             Class<?>[] interfaces = classToReflect.getInterfaces();
             for (int i = 0; i < interfaces.length; i++) {
-                populateWithInterface(cache, interfaces[i], log);
+                populateWithInterface(cache, permissions, interfaces[i], log);
             }
         }
         // now that we've got all methods keyed in, lets organize them by name
@@ -253,31 +255,33 @@ final class ClassMap {
     /**
      * Recurses up interface hierarchy to get all super interfaces.
      * @param cache the cache to fill
+     * @param permissions the permissions to apply during introspection
      * @param iface the interface to populate the cache from
-     * @param log the Log
+     * @param log   the Log
      */
-    private static void populateWithInterface(ClassMap cache, Class<?> iface, 
Log log) {
+    private static void populateWithInterface(ClassMap cache, Permissions 
permissions, Class<?> iface, Log log) {
         if (Modifier.isPublic(iface.getModifiers())) {
-            populateWithClass(cache, iface, log);
-        }
-        Class<?>[] supers = iface.getInterfaces();
-        for (int i = 0; i < supers.length; i++) {
-            populateWithInterface(cache, supers[i], log);
+            populateWithClass(cache, permissions, iface, log);
+            Class<?>[] supers = iface.getInterfaces();
+            for (int i = 0; i < supers.length; i++) {
+                populateWithInterface(cache, permissions, supers[i], log);
+            }
         }
     }
 
     /**
      * Recurses up class hierarchy to get all super classes.
      * @param cache the cache to fill
+     * @param permissions the permissions to apply during introspection
      * @param clazz the class to populate the cache from
-     * @param log the Log
+     * @param log   the Log
      */
-    private static void populateWithClass(ClassMap cache, Class<?> clazz, Log 
log) {
+    private static void populateWithClass(ClassMap cache, Permissions 
permissions, Class<?> clazz, Log log) {
         try {
             Method[] methods = clazz.getDeclaredMethods();
             for (int i = 0; i < methods.length; i++) {
                 Method mi = methods[i];
-                if (Modifier.isPublic(mi.getModifiers()) && 
Permissions.allow(mi)) {
+                if (permissions.allow(mi)) {
                     // add method to byKey cache; do not override
                     cache.byKey.putIfAbsent(new MethodKey(mi), mi);
                 }

Modified: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java?rev=1815813&r1=1815812&r2=1815813&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
 (original)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
 Mon Nov 20 14:58:39 2017
@@ -21,7 +21,6 @@ import org.apache.commons.logging.Log;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -68,6 +67,10 @@ public final class Introspector {
      */
     private ClassLoader loader;
     /**
+     * The permissions.
+     */
+    private final Permissions permissions;
+    /**
      * The read/write lock.
      */
     private final ReadWriteLock lock = new ReentrantReadWriteLock();
@@ -90,8 +93,19 @@ public final class Introspector {
      * @param cloader the class loader
      */
     public Introspector(Log log, ClassLoader cloader) {
+        this(log, cloader, null);
+    }
+
+    /**
+     * Create the introspector.
+     * @param log     the logger to use
+     * @param cloader the class loader
+     * @param perms the permissions
+     */
+    public Introspector(Log log, ClassLoader cloader, Permissions perms) {
         this.rlog = log;
-        loader = cloader;
+        this.loader = cloader;
+        this.permissions = perms != null? perms : Permissions.DEFAULT;
     }
 
     /**
@@ -247,7 +261,7 @@ public final class Introspector {
                 }
                 List<Constructor<?>> l = new ArrayList<Constructor<?>>();
                 for (Constructor<?> ictor : clazz.getConstructors()) {
-                    if (Modifier.isPublic(ictor.getModifiers()) && 
Permissions.allow(ictor)) {
+                    if (permissions.allow(ictor)) {
                         l.add(ictor);
                     }
                 }
@@ -298,7 +312,7 @@ public final class Introspector {
                 // try again
                 classMap = classMethodMaps.get(c);
                 if (classMap == null) {
-                    classMap = new ClassMap(c, rlog);
+                    classMap = new ClassMap(c, permissions, rlog);
                     classMethodMaps.put(c, classMap);
                 }
             } finally {

Modified: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java?rev=1815813&r1=1815812&r2=1815813&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java
 (original)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java
 Mon Nov 20 14:58:39 2017
@@ -20,25 +20,42 @@ package org.apache.commons.jexl3.interna
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import org.apache.commons.jexl3.annotations.NoJexl;
 
 /**
- * Checks whether an element (ctor, field or method) is visible by JEXL 
introspection
- * by checking if has been annotated with NoJexl.
+ * Checks whether an element (ctor, field or method) is visible by JEXL 
introspection.
+ * Default implementation does this by checking if element has been annotated 
with NoJexl.
  */
 public class Permissions {
     /** Make non instantiable. */
     private Permissions() {
     }
+    /**
+     * The default singleton.
+     */
+    public static final Permissions DEFAULT = new Permissions();
 
     /**
-     * Checks whether a class or one of its superclasses or implemented 
interfaces
+     * Checks whether a package explicitly disallows JEXL introspection.
+     * @param pack the package
+     * @return true if JEXL is allowed to introspect, false otherwise
+     */
+    public boolean allow(Package pack) {
+        if (pack != null && pack.getAnnotation(NoJexl.class) != null) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Checks whether a class or one of its super-classes or implemented 
interfaces
      * explicitly disallows JEXL introspection.
      * @param clazz the class to check
      * @return true if JEXL is allowed to introspect, false otherwise
      */
-    public static boolean allow(Class<?> clazz) {
-        return allow(clazz, true);
+    public boolean allow(Class<?> clazz) {
+        return clazz != null && allow(clazz.getPackage()) && allow(clazz, 
true);
     }
 
     /**
@@ -46,10 +63,13 @@ public class Permissions {
      * @param ctor the constructor to check
      * @return true if JEXL is allowed to introspect, false otherwise
      */
-    public static boolean allow(Constructor<?> ctor) {
+    public boolean allow(Constructor<?> ctor) {
         if (ctor == null) {
             return false;
         }
+        if (!Modifier.isPublic(ctor.getModifiers())) {
+            return false;
+        }
         Class<?> clazz = ctor.getDeclaringClass();
         if (!allow(clazz, false)) {
             return false;
@@ -67,10 +87,13 @@ public class Permissions {
      * @param field the field to check
      * @return true if JEXL is allowed to introspect, false otherwise
      */
-    public static boolean allow(Field field) {
+    public boolean allow(Field field) {
         if (field == null) {
             return false;
         }
+        if (!Modifier.isPublic(field.getModifiers())) {
+            return false;
+        }
         Class<?> clazz = field.getDeclaringClass();
         if (!allow(clazz, false)) {
             return false;
@@ -85,15 +108,18 @@ public class Permissions {
 
     /**
      * Checks whether a method explicitly disallows JEXL introspection.
-     * <p>Since methods can be overriden, this also checks that no superclass 
or interface
+     * <p>Since methods can be overridden, this also checks that no superclass 
or interface
      * explictly disallows this methods.</p>
      * @param method the method to check
      * @return true if JEXL is allowed to introspect, false otherwise
      */
-    public static boolean allow(Method method) {
+    public boolean allow(Method method) {
         if (method == null) {
             return false;
         }
+        if (!Modifier.isPublic(method.getModifiers())) {
+            return false;
+        }
         // is method annotated with nojexl ?
         NoJexl nojexl = method.getAnnotation(NoJexl.class);
         if (nojexl != null) {
@@ -134,9 +160,7 @@ public class Permissions {
         if (clazz == null) {
             return false;
         }
-        // is package annotated with nojexl ?
-        Package pack = clazz.getPackage();
-        if (pack != null && pack.getAnnotation(NoJexl.class) != null) {
+        if (!Modifier.isPublic(clazz.getModifiers())) {
             return false;
         }
         // lets walk all interfaces


Reply via email to