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