Index: src/org/mozilla/javascript/JavaAdapter.java
===================================================================
RCS file: /cvsroot/mozilla/js/rhino/src/org/mozilla/javascript/JavaAdapter.java,v
retrieving revision 1.117
diff -u -r1.117 JavaAdapter.java
--- src/org/mozilla/javascript/JavaAdapter.java 14 Nov 2008 13:52:29 -0000 1.117
+++ src/org/mozilla/javascript/JavaAdapter.java 25 Jun 2009 08:53:10 -0000
@@ -131,6 +131,10 @@
public static Object convertResult(Object result, Class<?> c)
{
+ return convertResult(result, c, true);
+ }
+
+ public static Object convertResult(Object result, Class<?> c, boolean unwrap) {
if (result == Undefined.instance &&
(c != ScriptRuntime.ObjectClass &&
c != ScriptRuntime.StringClass))
@@ -138,7 +142,14 @@
// Avoid an error for an undefined value; return null instead.
return null;
}
- return Context.jsToJava(result, c);
+ if (!unwrap) {
+ // Scriptable.NOT_FOUND requires special handling
+ if (result instanceof Wrapper &&
+ ((Wrapper)result).unwrap() == Scriptable.NOT_FOUND) {
+ return Scriptable.NOT_FOUND;
+ }
+ }
+ return unwrap ? Context.jsToJava(result, c) : result;
}
public static Scriptable createAdapterWrapper(Scriptable obj,
@@ -353,9 +364,13 @@
(short) (ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
int interfacesCount = interfaces == null ? 0 : interfaces.length;
+ boolean isScriptable = Scriptable.class.isAssignableFrom(superClass);
for (int i=0; i < interfacesCount; i++) {
- if (interfaces[i] != null)
+ if (interfaces[i] != null) {
cfw.addInterface(interfaces[i].getName());
+ isScriptable = isScriptable
+ || Scriptable.class.isAssignableFrom(interfaces[i]);
+ }
}
String superName = superClass.getName().replace('.', '/');
@@ -395,7 +410,7 @@
String methodKey = methodName + methodSignature;
if (! generatedOverrides.has(methodKey)) {
generateMethod(cfw, adapterName, methodName,
- argTypes, method.getReturnType());
+ argTypes, method.getReturnType(), !isScriptable);
generatedOverrides.put(methodKey, 0);
generatedMethods.put(methodName, 0);
}
@@ -423,7 +438,7 @@
String methodKey = methodName + methodSignature;
if (! generatedOverrides.has(methodKey)) {
generateMethod(cfw, adapterName, methodName,
- argTypes, method.getReturnType());
+ argTypes, method.getReturnType(), !isScriptable);
generatedOverrides.put(methodKey, 0);
generatedMethods.put(methodName, 0);
@@ -450,7 +465,7 @@
for (int k=0; k < length; k++)
parms[k] = ScriptRuntime.ObjectClass;
generateMethod(cfw, adapterName, functionName, parms,
- ScriptRuntime.ObjectClass);
+ ScriptRuntime.ObjectClass, !isScriptable);
}
return cfw.toByteArray();
}
@@ -817,7 +832,7 @@
* Generates the appropriate RETURN bytecode.
*/
static void generateReturnResult(ClassFileWriter cfw, Class<?> retType,
- boolean callConvertResult)
+ boolean convertResult)
{
// wrap boolean values with java.lang.Boolean, convert all other
// primitive values to java.lang.Double.
@@ -874,20 +889,19 @@
} else {
String retTypeStr = retType.getName();
- if (callConvertResult) {
- cfw.addLoadConstant(retTypeStr);
- cfw.addInvoke(ByteCode.INVOKESTATIC,
- "java/lang/Class",
- "forName",
- "(Ljava/lang/String;)Ljava/lang/Class;");
-
- cfw.addInvoke(ByteCode.INVOKESTATIC,
- "org/mozilla/javascript/JavaAdapter",
- "convertResult",
- "(Ljava/lang/Object;"
- +"Ljava/lang/Class;"
- +")Ljava/lang/Object;");
- }
+ cfw.addLoadConstant(retTypeStr);
+ cfw.addInvoke(ByteCode.INVOKESTATIC,
+ "java/lang/Class",
+ "forName",
+ "(Ljava/lang/String;)Ljava/lang/Class;");
+ cfw.addLoadConstant(convertResult ? 1 : 0);
+ cfw.addInvoke(ByteCode.INVOKESTATIC,
+ "org/mozilla/javascript/JavaAdapter",
+ "convertResult",
+ "(Ljava/lang/Object;"
+ +"Ljava/lang/Class;"
+ +"Z"
+ +")Ljava/lang/Object;");
// Now cast to return type
cfw.add(ByteCode.CHECKCAST, retTypeStr);
cfw.add(ByteCode.ARETURN);
@@ -896,7 +910,7 @@
private static void generateMethod(ClassFileWriter cfw, String genName,
String methodName, Class<?>[] parms,
- Class<?> returnType)
+ Class<?> returnType, boolean convertResult)
{
StringBuffer sb = new StringBuffer();
int paramsEnd = appendMethodSignature(parms, returnType, sb);
@@ -959,7 +973,7 @@
+"J"
+")Ljava/lang/Object;");
- generateReturnResult(cfw, returnType, true);
+ generateReturnResult(cfw, returnType, convertResult);
cfw.stopMethod((short)paramsEnd);
}
Index: src/org/mozilla/javascript/JavaMembers.java
===================================================================
RCS file: /cvsroot/mozilla/js/rhino/src/org/mozilla/javascript/JavaMembers.java,v
retrieving revision 1.80
diff -u -r1.80 JavaMembers.java
--- src/org/mozilla/javascript/JavaMembers.java 6 Jun 2009 14:11:24 -0000 1.80
+++ src/org/mozilla/javascript/JavaMembers.java 25 Jun 2009 08:53:10 -0000
@@ -54,6 +54,8 @@
*/
class JavaMembers
{
+ static RuntimePermission permission = new RuntimePermission("accessDeclaredMembers");
+
JavaMembers(Scriptable scope, Class<?> cl)
{
this(scope, cl, false);
@@ -92,6 +94,10 @@
Object get(Scriptable scope, String name, Object javaObject,
boolean isStatic)
{
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(permission);
+ }
Map<String,Object> ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (!isStatic && member == null) {
@@ -133,6 +139,10 @@
void put(Scriptable scope, String name, Object javaObject,
Object value, boolean isStatic)
{
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(permission);
+ }
Map<String,Object> ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (!isStatic && member == null) {
@@ -197,6 +207,10 @@
Object[] getIds(boolean isStatic)
{
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(permission);
+ }
Map<String,Object> map = isStatic ? staticMembers : members;
return map.keySet().toArray(new Object[map.size()]);
}
Index: src/org/mozilla/javascript/PolicySecurityController.java
===================================================================
RCS file: /cvsroot/mozilla/js/rhino/src/org/mozilla/javascript/PolicySecurityController.java,v
retrieving revision 1.10
diff -u -r1.10 PolicySecurityController.java
--- src/org/mozilla/javascript/PolicySecurityController.java 25 Mar 2008 14:32:26 -0000 1.10
+++ src/org/mozilla/javascript/PolicySecurityController.java 25 Jun 2009 08:53:10 -0000
@@ -42,6 +42,7 @@
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
import java.security.SecureClassLoader;
import java.util.Map;
import java.util.WeakHashMap;
@@ -116,9 +117,10 @@
@Override
public Object getDynamicSecurityDomain(Object securityDomain)
{
- // No separate notion of dynamic security domain - just return what was
- // passed in.
- return securityDomain;
+ // if RhinoSecurityManager is installed, try to get the protection domain
+ // of the topmost script in the current stack.
+ ProtectionDomain dynamicDomain = SecurityUtilities.getDynamicScriptProtectionDomain();
+ return dynamicDomain == null ? securityDomain : dynamicDomain.getCodeSource();
}
@Override
Index: src/org/mozilla/javascript/RhinoSecurityManager.java
===================================================================
RCS file: src/org/mozilla/javascript/RhinoSecurityManager.java
diff -N src/org/mozilla/javascript/RhinoSecurityManager.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/mozilla/javascript/RhinoSecurityManager.java 25 Jun 2009 08:53:10 -0000
@@ -0,0 +1,27 @@
+package org.mozilla.javascript;
+
+import java.security.ProtectionDomain;
+
+/**
+ * A java.lang.SecurityManager subclass that provides access to the security domain
+ * of the top-most script in the currently executing stack. This is useful to
+ * provide the same protection domain to scripts created by other scripts
+ * (e.g. JavaAdapters).
+ */
+public class RhinoSecurityManager extends SecurityManager {
+
+ /**
+ * Find the top-most stack element representing a script and return its protection domain.
+ * @return The protection of the top-most script in the current stack
+ */
+ protected ProtectionDomain getScriptProtectionDomain() {
+ Class[] context = getClassContext();
+ for (Class c : context) {
+ if (c != InterpretedFunction.class && NativeFunction.class.isAssignableFrom(c) ||
+ PolicySecurityController.SecureCaller.class.isAssignableFrom(c)) {
+ return c.getProtectionDomain();
+ }
+ }
+ return null;
+ }
+}
Index: src/org/mozilla/javascript/SecurityUtilities.java
===================================================================
RCS file: /cvsroot/mozilla/js/rhino/src/org/mozilla/javascript/SecurityUtilities.java,v
retrieving revision 1.6
diff -u -r1.6 SecurityUtilities.java
--- src/org/mozilla/javascript/SecurityUtilities.java 18 Mar 2008 15:10:18 -0000 1.6
+++ src/org/mozilla/javascript/SecurityUtilities.java 25 Jun 2009 08:53:10 -0000
@@ -65,7 +65,7 @@
}
});
}
-
+
public static ProtectionDomain getProtectionDomain(final Class<?> clazz)
{
return (ProtectionDomain)AccessController.doPrivileged(
@@ -77,4 +77,25 @@
}
});
}
+
+ /**
+ * Look up the top-most element in the current stack representing a
+ * script and return its protection domain. This relies on the system-wide
+ * SecurityManager being an instance of {@link RhinoSecurityManager},
+ * otherwise it returns <code>null</code>.
+ * @return The protection of the top-most script in the current stack, or null
+ */
+ public static ProtectionDomain getDynamicScriptProtectionDomain() {
+ return AccessController.doPrivileged(
+ new PrivilegedAction<ProtectionDomain>() {
+ public ProtectionDomain run() {
+ SecurityManager securityManager = System.getSecurityManager();
+ if (securityManager instanceof RhinoSecurityManager) {
+ return ((RhinoSecurityManager) securityManager)
+ .getScriptProtectionDomain();
+ }
+ return null;
+ }
+ });
+ }
}