You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2019/04/29 07:54:24 UTC
[commons-jexl] branch master updated: JEXL-253: first code drop,
testing waters
This is an automated email from the ASF dual-hosted git repository.
henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
The following commit(s) were added to refs/heads/master by this push:
new b508e51 JEXL-253: first code drop, testing waters
new 028f2c4 Merge origin/master
b508e51 is described below
commit b508e517f7134e43722b055b9cc60b5c7c1a3446
Author: Henri Biestro <hb...@gmail.com>
AuthorDate: Mon Apr 29 09:50:27 2019 +0200
JEXL-253: first code drop, testing waters
---
.../internal/introspection/SandboxUberspect.java | 22 ++--
.../commons/jexl3/introspection/JexlSandbox.java | 141 +++++++++++++++++----
2 files changed, 123 insertions(+), 40 deletions(-)
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
index 13778b0..5fe8582 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
@@ -57,7 +57,7 @@ public final class SandboxUberspect implements JexlUberspect {
public void setClassLoader(ClassLoader loader) {
uberspect.setClassLoader(loader);
}
-
+
@Override
public ClassLoader getClassLoader() {
return uberspect.getClassLoader();
@@ -72,24 +72,20 @@ public final class SandboxUberspect implements JexlUberspect {
public JexlMethod getConstructor(final Object ctorHandle, final Object... args) {
final String className;
if (ctorHandle instanceof Class<?>) {
- Class<?> clazz = (Class<?>) ctorHandle;
- className = clazz.getName();
+ className = sandbox.execute((Class<?>) ctorHandle, "");
} else if (ctorHandle != null) {
- className = ctorHandle.toString();
+ className = sandbox.execute(ctorHandle.toString(), "");
} else {
- return null;
- }
- if (sandbox.execute(className, "") != null) {
- return uberspect.getConstructor(className, args);
+ className = null;
}
- return null;
+ return className != null? uberspect.getConstructor(className, args) : null;
}
@Override
public JexlMethod getMethod(final Object obj, final String method, final Object... args) {
if (obj != null && method != null) {
- String objClassName = (obj instanceof Class) ? ((Class<?>)obj).getName() : obj.getClass().getName();
- String actual = sandbox.execute(objClassName, method);
+ Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
+ String actual = sandbox.execute(clazz, method);
if (actual != null) {
return uberspect.getMethod(obj, actual, args);
}
@@ -113,7 +109,7 @@ public final class SandboxUberspect implements JexlUberspect {
final Object identifier) {
if (obj != null && identifier != null) {
String property = identifier.toString();
- String actual = sandbox.read(obj.getClass().getName(), property);
+ String actual = sandbox.read(obj.getClass(), property);
if (actual != null) {
// no transformation, strict equality: use identifier before string conversion
Object pty = actual == property? identifier : actual;
@@ -135,7 +131,7 @@ public final class SandboxUberspect implements JexlUberspect {
final Object arg) {
if (obj != null && identifier != null) {
String property = identifier.toString();
- String actual = sandbox.write(obj.getClass().getName(), property);
+ String actual = sandbox.write(obj.getClass(), property);
if (actual != null) {
// no transformation, strict equality: use identifier before string conversion
Object pty = actual == property? identifier : actual;
diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlSandbox.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlSandbox.java
index 1b4e299..f71f776 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlSandbox.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlSandbox.java
@@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
/**
* A sandbox describes permissions on a class by explicitly allowing or forbidding access to methods and properties
@@ -61,6 +62,10 @@ public final class JexlSandbox {
*/
private final Map<String, Permissions> sandbox;
/**
+ * Whether permissions can be inherited (through implementation or extension).
+ */
+ private final boolean inherit;
+ /**
* Default behavior, black or white.
*/
private final boolean white;
@@ -101,7 +106,19 @@ public final class JexlSandbox {
* @since 3.1
*/
protected JexlSandbox(boolean wb, Map<String, Permissions> map) {
+ this(wb, false, map);
+ }
+
+ /**
+ * Creates a sandbox based on an existing permissions map.
+ * @param wb whether this sandbox is white (true) or black (false)
+ * @param inh whether permissions are inherited, default false
+ * @param map the permissions map
+ * @since 3.2
+ */
+ protected JexlSandbox(boolean wb, boolean inh, Map<String, Permissions> map) {
white = wb;
+ inherit = inh;
sandbox = map;
}
@@ -109,11 +126,25 @@ public final class JexlSandbox {
* @return a copy of this sandbox
*/
public JexlSandbox copy() {
- Map<String, Permissions> map = new HashMap<String, Permissions>();
+ // modified concurently at runtime so...
+ Map<String, Permissions> map = new ConcurrentHashMap<String, Permissions>();
for (Map.Entry<String, Permissions> entry : sandbox.entrySet()) {
map.put(entry.getKey(), entry.getValue().copy());
}
- return new JexlSandbox(white, map);
+ return new JexlSandbox(white, inherit, map);
+ }
+
+ /**
+ * Gets a class by name, crude mechanism for backwards (<3.2 ) compatibility.
+ * @param cname the class name
+ * @return the class
+ */
+ static Class<?> forName(String cname) {
+ try {
+ return Class.forName(cname);
+ } catch(Exception xany) {
+ return null;
+ }
}
/**
@@ -124,7 +155,7 @@ public final class JexlSandbox {
* @return null if not allowed, the name of the property to use otherwise
*/
public String read(Class<?> clazz, String name) {
- return read(clazz.getName(), name);
+ return get(clazz).read().get(name);
}
/**
@@ -134,13 +165,9 @@ public final class JexlSandbox {
* @param name the property name
* @return null if not allowed, the name of the property to use otherwise
*/
+ @Deprecated
public String read(String clazz, String name) {
- Permissions permissions = sandbox.get(clazz);
- if (permissions == null) {
- return white? name : null;
- } else {
- return permissions.read().get(name);
- }
+ return get(clazz).read().get(name);
}
/**
@@ -151,7 +178,7 @@ public final class JexlSandbox {
* @return null if not allowed, the name of the property to use otherwise
*/
public String write(Class<?> clazz, String name) {
- return write(clazz.getName(), name);
+ return get(clazz).write().get(name);
}
/**
@@ -161,13 +188,9 @@ public final class JexlSandbox {
* @param name the property name
* @return null if not allowed, the name of the property to use otherwise
*/
+ @Deprecated
public String write(String clazz, String name) {
- Permissions permissions = sandbox.get(clazz);
- if (permissions == null) {
- return white ? name : null;
- } else {
- return permissions.write().get(name);
- }
+ return get(clazz).write().get(name);
}
/**
@@ -178,7 +201,8 @@ public final class JexlSandbox {
* @return null if not allowed, the name of the method to use otherwise
*/
public String execute(Class<?> clazz, String name) {
- return execute(clazz.getName(), name);
+ String m = get(clazz).execute().get(name);
+ return "".equals(name) && m != null? clazz.getName() : m;
}
/**
@@ -188,13 +212,10 @@ public final class JexlSandbox {
* @param name the method name
* @return null if not allowed, the name of the method to use otherwise
*/
+ @Deprecated
public String execute(String clazz, String name) {
- Permissions permissions = sandbox.get(clazz);
- if (permissions == null) {
- return white ? name : null;
- } else {
- return permissions.execute().get(name);
- }
+ String m = get(clazz).execute().get(name);
+ return "".equals(name) && m != null? clazz : m;
}
/**
@@ -255,6 +276,26 @@ public final class JexlSandbox {
}
};
+ /*
+ * The block-all name set.
+ */
+ private static final Names BLACK_NAMES = new Names() {
+ @Override
+ public boolean add(String name) {
+ return false;
+ }
+
+ @Override
+ protected Names copy() {
+ return this;
+ }
+
+ @Override
+ public String get(String name) {
+ return null;
+ }
+ };
+
/**
* A white set of names.
*/
@@ -327,13 +368,12 @@ public final class JexlSandbox {
* Contains the white or black lists for properties and methods for a given class.
*/
public static final class Permissions {
-
+ /** Whether these permissions are inheritable, ie can be used by derived classes. */
+ private final boolean inheritable;
/** The controlled readable properties. */
private final Names read;
-
/** The controlled writable properties. */
private final Names write;
-
/** The controlled methods. */
private final Names execute;
@@ -361,6 +401,7 @@ public final class JexlSandbox {
this.read = nread != null ? nread : WHITE_NAMES;
this.write = nwrite != null ? nwrite : WHITE_NAMES;
this.execute = nexecute != null ? nexecute : WHITE_NAMES;
+ this.inheritable = false;
}
/**
@@ -371,6 +412,14 @@ public final class JexlSandbox {
}
/**
+ * Whether this permission applies to derived classes.
+ * @return true
+ */
+ public boolean isInheritable() {
+ return inheritable;
+ }
+
+ /**
* Adds a list of readable property names to these permissions.
*
* @param pnames the property names
@@ -437,10 +486,15 @@ public final class JexlSandbox {
return execute;
}
}
+
/**
* The pass-thru permissions.
*/
private static final Permissions ALL_WHITE = new Permissions(WHITE_NAMES, WHITE_NAMES, WHITE_NAMES);
+ /**
+ * The block-all permissions.
+ */
+ private static final Permissions ALL_BLACK = new Permissions(BLACK_NAMES, BLACK_NAMES, BLACK_NAMES);
/**
* Creates the set of permissions for a given class.
@@ -484,11 +538,44 @@ public final class JexlSandbox {
* @return the defined permissions or an all-white permission instance if none were defined
*/
public Permissions get(String clazz) {
+ if (inherit) {
+ return get(forName(clazz));
+ }
Permissions permissions = sandbox.get(clazz);
if (permissions == null) {
- return ALL_WHITE;
+ return white ? ALL_WHITE : ALL_BLACK;
} else {
return permissions;
}
}
+
+ /**
+ * Get the permissions associated to a class.
+ * @param clazz the class
+ * @return the permissions
+ */
+ public Permissions get(Class<?> clazz) {
+ Permissions permissions = clazz == null? ALL_BLACK : sandbox.get(clazz.getName());
+ if (permissions == null) {
+ if (inherit) {
+ // clazz can not be null since permissions would be not null and black;
+ // find first inheritable class that defined permissions
+ for (Class<?> ii : clazz.getClasses()) {
+ permissions = sandbox.get(ii.getName());
+ if (permissions != null && permissions.isInheritable()) {
+ break;
+ }
+ }
+ if (permissions == null) {
+ permissions = white ? ALL_WHITE : ALL_BLACK;
+ }
+ // store the info to avoid doing this costly look up
+ sandbox.put(clazz.getName(), permissions);
+ } else {
+ permissions = white ? ALL_WHITE : ALL_BLACK;
+ }
+ }
+ return permissions;
+ }
+
}