mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
New security implementation.
This commit is contained in:
parent
6909994c7b
commit
988587183a
@ -1,6 +1,7 @@
|
||||
apiClasses=\
|
||||
src/org/mozilla/javascript/ClassDefinitionException.java,\
|
||||
src/org/mozilla/javascript/ClassOutput.java,\
|
||||
src/org/mozilla/javascript/ClassShutter.java,\
|
||||
src/org/mozilla/javascript/Context.java,\
|
||||
src/org/mozilla/javascript/ContextListener.java,\
|
||||
src/org/mozilla/javascript/EcmaError.java,\
|
||||
@ -15,6 +16,7 @@ apiClasses=\
|
||||
src/org/mozilla/javascript/Scriptable.java,\
|
||||
src/org/mozilla/javascript/ScriptableObject.java,\
|
||||
src/org/mozilla/javascript/SecuritySupport.java,\
|
||||
src/org/mozilla/javascript/SecurityController.java,\
|
||||
src/org/mozilla/javascript/WrapFactory.java,\
|
||||
src/org/mozilla/javascript/WrapHandler.java,\
|
||||
src/org/mozilla/javascript/Wrapper.java,\
|
||||
|
@ -38,10 +38,15 @@ This interface can be implemented to control the actions the JavaScript
|
||||
engine takes when it encounters errors.</li>
|
||||
|
||||
<li>
|
||||
<a href="org/mozilla/javascript/SecuritySupport.html">SecuritySupport</a>
|
||||
<a href="org/mozilla/javascript/SecurityController.html">SecurityController</a>
|
||||
- Optional support routines that must be provided by embeddings implementing
|
||||
security controls on scripts.</li>
|
||||
|
||||
<li>
|
||||
<a href="org/mozilla/javascript/ClassShutter.html">ClassShutter</a>
|
||||
- Embeddings that wish to filter Java classes that are visible to scripts
|
||||
through the LiveConnect, should implement this interface.</li>
|
||||
|
||||
<li>
|
||||
<a href="org/mozilla/javascript/Wrapper.html">Wrapper</a> - Interface implemented
|
||||
by objects wrapping other objects. Provides a method for recovering the
|
||||
|
@ -350,7 +350,6 @@ public class BaseFunction extends IdScriptable implements Function {
|
||||
}
|
||||
String sourceName = filename+'#'+linep[0]+"(Function)";
|
||||
|
||||
Object securityDomain = cx.getSecurityDomainForStackDepth(4);
|
||||
Scriptable global = ScriptableObject.getTopLevelScope(scope);
|
||||
|
||||
// Compile the function with opt level of -1 to force interpreter
|
||||
@ -361,7 +360,7 @@ public class BaseFunction extends IdScriptable implements Function {
|
||||
try {
|
||||
fn = (NativeFunction) cx.compileFunction(global, source,
|
||||
sourceName, 1,
|
||||
securityDomain);
|
||||
null);
|
||||
}
|
||||
finally { cx.setOptimizationLevel(oldOptLevel); }
|
||||
|
||||
|
86
js/rhino/src/org/mozilla/javascript/ClassShutter.java
Normal file
86
js/rhino/src/org/mozilla/javascript/ClassShutter.java
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Norris Boyd
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
Embeddings that wish to filter Java classes that are visible to scripts
|
||||
through the LiveConnect, should implement this interface.
|
||||
|
||||
@see Context#setClassShutter(ClassShutter)
|
||||
@since 1.5 Release 4
|
||||
@author Norris Boyd
|
||||
*/
|
||||
|
||||
public interface ClassShutter {
|
||||
|
||||
/**
|
||||
* Return true iff the Java class with the given name should be exposed
|
||||
* to scripts.
|
||||
* <p>
|
||||
* An embedding may filter which Java classes are exposed through
|
||||
* LiveConnect to JavaScript scripts.
|
||||
* <p>
|
||||
* Due to the fact that there is no package reflection in Java,
|
||||
* this method will also be called with package names. There
|
||||
* is no way for Rhino to tell if "Packages.a.b" is a package name
|
||||
* or a class that doesn't exist. What Rhino does is attempt
|
||||
* to load each segment of "Packages.a.b.c": It first attempts to
|
||||
* load class "a", then attempts to load class "a.b", then
|
||||
* finally attempts to load class "a.b.c". On a Rhino installation
|
||||
* without any ClassShutter set, and without any of the
|
||||
* above classes, the expression "Packages.a.b.c" will result in
|
||||
* a [JavaPackage a.b.c] and not an error.
|
||||
* <p>
|
||||
* With ClassShutter supplied, Rhino will first call
|
||||
* visibleToScripts before attempting to look up the class name. If
|
||||
* visibleToScripts returns false, the class name lookup is not
|
||||
* performed and subsequent Rhino execution assumes the class is
|
||||
* not present. So for "java.lang.System.out.println" the lookup
|
||||
* of "java.lang.System" is skipped and thus Rhino assumes that
|
||||
* "java.lang.System" doesn't exist. So then for "java.lang.System.out",
|
||||
* Rhino attempts to load the class "java.lang.System.out" because
|
||||
* it assumes that "java.lang.System" is a package name.
|
||||
* <p>
|
||||
* @param fullClassName the full name of the class (including the package
|
||||
* name, with '.' as a delimiter). For example the
|
||||
* standard string class is "java.lang.String"
|
||||
* @return whether or not to reveal this class to scripts
|
||||
*/
|
||||
public boolean visibleToScripts(String fullClassName);
|
||||
}
|
@ -96,22 +96,6 @@ public class Context {
|
||||
* @see org.mozilla.javascript.Context#enter
|
||||
*/
|
||||
public Context() {
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new context with the associated security support.
|
||||
*
|
||||
* @param securitySupport an encapsulation of the functionality
|
||||
* needed to support security for scripts.
|
||||
* @see org.mozilla.javascript.SecuritySupport
|
||||
*/
|
||||
public Context(SecuritySupport securitySupport) {
|
||||
this.securitySupport = securitySupport;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setLanguageVersion(VERSION_DEFAULT);
|
||||
optimizationLevel = codegenClass != null ? 0 : -1;
|
||||
Object[] array = contextListeners;
|
||||
@ -122,6 +106,14 @@ public class Context {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@deprecated The {@link SecuritySupport} class is deprecated. See its documentation for the upgrade path.
|
||||
*/
|
||||
public Context(SecuritySupport x) {
|
||||
this();
|
||||
setClassShutter(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a context associated with the current thread, creating
|
||||
* one if need be.
|
||||
@ -1473,54 +1465,48 @@ public class Context {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security support for this context.
|
||||
* <p> SecuritySupport may only be set if it is currently null.
|
||||
* Set the security controller for this context.
|
||||
* <p> SecurityController may only be set if it is currently null.
|
||||
* Otherwise a SecurityException is thrown.
|
||||
* @param supportObj a SecuritySupport object
|
||||
* @throws SecurityException if there is already a SecuritySupport
|
||||
* @param controller a SecurityController object
|
||||
* @throws SecurityException if there is already a SecurityController
|
||||
* object for this Context
|
||||
*/
|
||||
public synchronized void setSecuritySupport(SecuritySupport supportObj) {
|
||||
if (securitySupport != null) {
|
||||
public void setSecurityController(SecurityController controller) {
|
||||
if (controller == null) throw new IllegalArgumentException();
|
||||
if (securityController != null) {
|
||||
throw new SecurityException("Cannot overwrite existing " +
|
||||
"SecuritySupport object");
|
||||
"SecurityController object");
|
||||
}
|
||||
securitySupport = supportObj;
|
||||
securityController = controller;
|
||||
}
|
||||
|
||||
/**
|
||||
@deprecated The {@link SecuritySupport} class is deprecated. See its documentation for the upgrade path.
|
||||
*/
|
||||
public void setSecuritySupport(SecuritySupport x) {
|
||||
setClassShutter(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a security domain is required on calls to
|
||||
* compile and evaluate scripts.
|
||||
*
|
||||
* @since 1.4 Release 2
|
||||
* Set the LiveConnect access filter for this context.
|
||||
* <p> {@link ClassShutter} may only be set if it is currently null.
|
||||
* Otherwise a SecurityException is thrown.
|
||||
* @param shutter a ClassShutter object
|
||||
* @throws SecurityException if there is already a ClassShutter
|
||||
* object for this Context
|
||||
*/
|
||||
public static boolean isSecurityDomainRequired() {
|
||||
return requireSecurityDomain;
|
||||
public void setClassShutter(ClassShutter shutter) {
|
||||
if (shutter == null) throw new IllegalArgumentException();
|
||||
if (classShutter != null) {
|
||||
throw new SecurityException("Cannot overwrite existing " +
|
||||
"ClassShutter object");
|
||||
}
|
||||
classShutter = shutter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the security context associated with the innermost
|
||||
* script or function being executed by the interpreter.
|
||||
* @since 1.4 release 2
|
||||
*/
|
||||
public Object getInterpreterSecurityDomain() {
|
||||
return interpreterSecurityDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the class parameter is a class in the
|
||||
* interpreter. Typically used by embeddings that get a class
|
||||
* context to check security. These embeddings must know
|
||||
* whether to get the security context associated with the
|
||||
* interpreter or not.
|
||||
*
|
||||
* @param cl a class to test whether or not it is an interpreter
|
||||
* class
|
||||
* @return true if cl is an interpreter class
|
||||
* @since 1.4 release 2
|
||||
*/
|
||||
public boolean isInterpreterClass(Class cl) {
|
||||
return cl == Interpreter.class;
|
||||
ClassShutter getClassShutter() {
|
||||
return classShutter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1943,11 +1929,17 @@ public class Context {
|
||||
boolean returnFunction)
|
||||
throws IOException
|
||||
{
|
||||
Object dynamicDoamin = null;
|
||||
if (securityController != null) {
|
||||
dynamicDoamin = securityController.
|
||||
getDynamicSecurityDomain(securityDomain);
|
||||
}
|
||||
|
||||
if (debugger != null && in != null) {
|
||||
in = new DebugReader(in);
|
||||
}
|
||||
TokenStream ts = new TokenStream(in, scope, sourceName, lineno);
|
||||
return compile(scope, ts, securityDomain, in, returnFunction);
|
||||
return compile(scope, ts, dynamicDoamin, in, returnFunction);
|
||||
}
|
||||
|
||||
private static Class codegenClass;
|
||||
@ -2001,7 +1993,7 @@ public class Context {
|
||||
}
|
||||
|
||||
private Object compile(Scriptable scope, TokenStream ts,
|
||||
Object securityDomain, Reader in,
|
||||
Object dynamicSecurityDomain, Reader in,
|
||||
boolean returnFunction)
|
||||
throws IOException
|
||||
{
|
||||
@ -2038,8 +2030,10 @@ public class Context {
|
||||
tree.putProp(Node.DEBUGSOURCE_PROP, dr.getSaved());
|
||||
}
|
||||
|
||||
Object result = compiler.compile(this, scope, tree, securityDomain,
|
||||
securitySupport, nameHelper);
|
||||
Object result = compiler.compile(this, scope, tree,
|
||||
dynamicSecurityDomain,
|
||||
securityController,
|
||||
nameHelper);
|
||||
|
||||
return errorCount == 0 ? result : null;
|
||||
}
|
||||
@ -2120,81 +2114,15 @@ public class Context {
|
||||
return version == VERSION_DEFAULT || version >= VERSION_1_3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security context from the given class.
|
||||
* <p>
|
||||
* When some form of security check needs to be done, the class context
|
||||
* must retrieved from the security manager to determine what class is
|
||||
* requesting some form of privileged access.
|
||||
* @since 1.4 release 2
|
||||
*/
|
||||
Object getSecurityDomainFromClass(Class cl) {
|
||||
if (cl == Interpreter.class)
|
||||
return interpreterSecurityDomain;
|
||||
return securitySupport.getSecurityDomain(cl);
|
||||
}
|
||||
|
||||
SecuritySupport getSecuritySupport() {
|
||||
return securitySupport;
|
||||
}
|
||||
|
||||
Object getSecurityDomainForStackDepth(int depth) {
|
||||
Object result = null;
|
||||
if (securitySupport != null) {
|
||||
Class[] classes = securitySupport.getClassContext();
|
||||
if (classes != null) {
|
||||
if (depth != -1) {
|
||||
int depth1 = depth + 1;
|
||||
result = getSecurityDomainFromClass(classes[depth1]);
|
||||
} else {
|
||||
for (int i=1; i < classes.length; i++) {
|
||||
result = getSecurityDomainFromClass(classes[i]);
|
||||
if (result != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != null)
|
||||
return result;
|
||||
if (requireSecurityDomain)
|
||||
checkSecurityDomainRequired();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean requireSecurityDomain = true;
|
||||
private static boolean resourceMissing = false;
|
||||
final static String securityResourceName =
|
||||
"org.mozilla.javascript.resources.Security";
|
||||
static {
|
||||
try {
|
||||
ResourceBundle rb = ResourceBundle.getBundle(securityResourceName);
|
||||
String s = rb.getString("security.requireSecurityDomain");
|
||||
requireSecurityDomain = s.equals("true");
|
||||
} catch (java.util.MissingResourceException mre) {
|
||||
requireSecurityDomain = true;
|
||||
resourceMissing = true;
|
||||
} catch (SecurityException se) {
|
||||
requireSecurityDomain = true;
|
||||
}
|
||||
}
|
||||
|
||||
final public static void checkSecurityDomainRequired() {
|
||||
if (requireSecurityDomain) {
|
||||
String msg = "Required security context not found";
|
||||
if (resourceMissing) {
|
||||
msg += ". Didn't find properties file at " +
|
||||
securityResourceName;
|
||||
}
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
// Should not be public
|
||||
SecurityController getSecurityController() {
|
||||
return securityController;
|
||||
}
|
||||
|
||||
public boolean isGeneratingDebugChanged() {
|
||||
return generatingDebugChanged;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a name to the list of names forcing the creation of real
|
||||
* activation objects for functions.
|
||||
@ -2259,7 +2187,8 @@ public class Context {
|
||||
int version;
|
||||
int errorCount;
|
||||
|
||||
private SecuritySupport securitySupport;
|
||||
private SecurityController securityController;
|
||||
private ClassShutter classShutter;
|
||||
private ErrorReporter errorReporter;
|
||||
private Thread currentThread;
|
||||
private RegExpProxy regExpProxy;
|
||||
|
@ -72,9 +72,8 @@ public class Interpreter {
|
||||
|
||||
public Object compile(Context cx, Scriptable scope, Node tree,
|
||||
Object securityDomain,
|
||||
SecuritySupport securitySupport,
|
||||
SecurityController securityController,
|
||||
ClassNameHelper nameHelper)
|
||||
throws IOException
|
||||
{
|
||||
version = cx.getLanguageVersion();
|
||||
itsData = new InterpreterData(cx, securityDomain);
|
||||
@ -1528,15 +1527,8 @@ public class Interpreter {
|
||||
throws JavaScriptException
|
||||
{
|
||||
if (cx.interpreterSecurityDomain != idata.securityDomain) {
|
||||
// If securityDomain is different, update domain in Cotext
|
||||
// and call self under new domain
|
||||
Object savedDomain = cx.interpreterSecurityDomain;
|
||||
cx.interpreterSecurityDomain = idata.securityDomain;
|
||||
try {
|
||||
return interpret(cx, scope, thisObj, args, fnOrScript, idata);
|
||||
} finally {
|
||||
cx.interpreterSecurityDomain = savedDomain;
|
||||
}
|
||||
return execWithNewDomain(cx, scope, thisObj, args, fnOrScript,
|
||||
idata);
|
||||
}
|
||||
|
||||
final Object DBL_MRK = Interpreter.DBL_MRK;
|
||||
@ -2787,6 +2779,35 @@ public class Interpreter {
|
||||
activation.put(name, activation, value);
|
||||
}
|
||||
|
||||
private static Object execWithNewDomain(Context cx, Scriptable scope,
|
||||
final Scriptable thisObj,
|
||||
final Object[] args,
|
||||
final NativeFunction fnOrScript,
|
||||
final InterpreterData idata)
|
||||
throws JavaScriptException
|
||||
{
|
||||
if (cx.interpreterSecurityDomain == idata.securityDomain)
|
||||
Context.codeBug();
|
||||
|
||||
Script code = new Script() {
|
||||
public Object exec(Context cx, Scriptable scope)
|
||||
throws JavaScriptException
|
||||
{
|
||||
return interpret(cx, scope, thisObj, args, fnOrScript, idata);
|
||||
}
|
||||
};
|
||||
|
||||
Object savedDomain = cx.interpreterSecurityDomain;
|
||||
cx.interpreterSecurityDomain = idata.securityDomain;
|
||||
try {
|
||||
return cx.getSecurityController().
|
||||
execWithDomain(cx, scope, code, idata.securityDomain);
|
||||
}finally {
|
||||
cx.interpreterSecurityDomain = savedDomain;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean itsInFunctionFlag;
|
||||
|
||||
private InterpreterData itsData;
|
||||
|
@ -53,8 +53,6 @@ class InterpreterData implements Serializable {
|
||||
itsStringTable = new String[INITIAL_STRINGTABLE_SIZE];
|
||||
|
||||
itsUseDynamicScope = cx.hasCompileFunctionsWithDynamicScope();
|
||||
if (securityDomain == null)
|
||||
Context.checkSecurityDomainRequired();
|
||||
this.securityDomain = securityDomain;
|
||||
}
|
||||
|
||||
|
@ -334,10 +334,10 @@ public class JavaAdapter extends ScriptableObject {
|
||||
}
|
||||
}
|
||||
|
||||
SecuritySupport ss = cx.getSecuritySupport();
|
||||
if (ss != null) {
|
||||
Object securityDomain = cx.getSecurityDomainForStackDepth(-1);
|
||||
Class result = ss.defineClass(adapterName, bytes, securityDomain);
|
||||
SecurityController sc = cx.getSecurityController();
|
||||
if (sc != null) {
|
||||
Object securityDomain = sc.getDynamicSecurityDomain(null);
|
||||
Class result = sc.defineClass(adapterName, bytes, securityDomain);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
|
@ -495,14 +495,13 @@ public class NativeGlobal implements IdFunctionMaster {
|
||||
|
||||
try {
|
||||
StringReader in = new StringReader((String) x);
|
||||
Object securityDomain = cx.getSecurityDomainForStackDepth(3);
|
||||
|
||||
// Compile the reader with opt level of -1 to force interpreter
|
||||
// mode.
|
||||
int oldOptLevel = cx.getOptimizationLevel();
|
||||
cx.setOptimizationLevel(-1);
|
||||
Script script = cx.compileReader(scope, in, sourceName, 1,
|
||||
securityDomain);
|
||||
null);
|
||||
cx.setOptimizationLevel(oldOptLevel);
|
||||
|
||||
// if the compile fails, an error has been reported by the
|
||||
|
@ -68,7 +68,7 @@ public class NativeJavaPackage extends ScriptableObject {
|
||||
"java.applet",
|
||||
};
|
||||
|
||||
public static class TopLevelPackage extends NativeJavaPackage
|
||||
public static class TopLevelPackage extends NativeJavaPackage
|
||||
implements Function
|
||||
{
|
||||
public TopLevelPackage() {
|
||||
@ -209,10 +209,10 @@ public class NativeJavaPackage extends ScriptableObject {
|
||||
? name
|
||||
: packageName + "." + name;
|
||||
Context cx = Context.getContext();
|
||||
SecuritySupport ss = cx.getSecuritySupport();
|
||||
ClassShutter shutter = cx.getClassShutter();
|
||||
Scriptable newValue;
|
||||
try {
|
||||
if (ss != null && !ss.visibleToScripts(newPackage))
|
||||
if (shutter != null && !shutter.visibleToScripts(newPackage))
|
||||
throw new ClassNotFoundException();
|
||||
Class newClass = classLoader != null
|
||||
? classLoader.loadClass(newPackage)
|
||||
|
@ -159,10 +159,7 @@ public class NativeScript extends NativeFunction implements Script {
|
||||
filename = "<Script object>";
|
||||
linep[0] = 1;
|
||||
}
|
||||
Object securityDomain =
|
||||
cx.getSecurityDomainForStackDepth(5);
|
||||
return cx.compileReader(scope, reader, filename, linep[0],
|
||||
securityDomain);
|
||||
return cx.compileReader(scope, reader, filename, linep[0], null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Unexpected IOException");
|
||||
|
107
js/rhino/src/org/mozilla/javascript/SecurityController.java
Normal file
107
js/rhino/src/org/mozilla/javascript/SecurityController.java
Normal file
@ -0,0 +1,107 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Norris Boyd
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* This class describes the support needed to implement security.
|
||||
* <p>
|
||||
* Three main pieces of functionality are required to implement
|
||||
* security for JavaScript. First, it must be possible to define
|
||||
* classes with an associated security domain. (This security
|
||||
* domain may be any object incorporating notion of access
|
||||
* restrictions that has meaning to an embedding; for a client-side
|
||||
* JavaScript embedding this would typically be
|
||||
* java.security.ProtectionDomain or similar object depending on an
|
||||
* origin URL and/or a digital certificate.)
|
||||
* Next it must be possible to get a security domain object that
|
||||
* allows a particular action only if all security domains
|
||||
* associated with code on the current Java stack allows it. And
|
||||
* finally, it must be possible to execute script code with
|
||||
* associated security domain injected into Java stack.
|
||||
* <p>
|
||||
* These three pieces of functionality are encapsulated in the
|
||||
* SecurityController class.
|
||||
*
|
||||
* @see org.mozilla.javascript.Context#setSecurityController(SecurityController)
|
||||
* @see java.lang.ClassLoader
|
||||
* @since 1.5 Release 4
|
||||
*/
|
||||
public abstract class SecurityController {
|
||||
|
||||
/**
|
||||
* Define and load a Java class.
|
||||
* <p>
|
||||
* In embeddings that care about security, the securityDomain
|
||||
* must be associated with the defined class such that a call to
|
||||
* <code>getSecurityDomain</code> with that class will return this security
|
||||
* context.
|
||||
* <p>
|
||||
* @param name the name of the class
|
||||
* @param data the bytecode of the class
|
||||
* @param securityDomain some object specifying the security
|
||||
* context of the code that is defining this class.
|
||||
* Embeddings that don't care about security may allow
|
||||
* null here. This value propagated from the values passed
|
||||
* into methods of Context that evaluate scripts.
|
||||
*/
|
||||
public abstract Class defineClass(String name, byte[] data,
|
||||
Object securityDomain);
|
||||
|
||||
/**
|
||||
* Get dynamic security domain that allows an action only if it is allowed
|
||||
* by the current Java stack and <i>securityDomain</i>. If
|
||||
* <i>securityDomain</i> is null, return domain representing permissions
|
||||
* allowed by the current stack.
|
||||
*/
|
||||
public abstract Object getDynamicSecurityDomain(Object securityDomain);
|
||||
|
||||
/**
|
||||
* Call {@link Script#exec(Context cx, Scriptable scope)} of
|
||||
* <i>script</i> under restricted security domain where an action is
|
||||
* allowed only if it allowed according to the Java stack on the
|
||||
* moment of the <i>execWithDomain</i> call and <i>securityDomain</i>.
|
||||
* Any call to {@link #getDynamicSecurityDomain(Object)} during
|
||||
* execution of {@link Script#exec(Context cx, Scriptable scope)}
|
||||
* should return a domain incorporate restrictions imposed by
|
||||
* <i>securityDomain</i>.
|
||||
*/
|
||||
public abstract Object execWithDomain(Context cx, Scriptable scope,
|
||||
Script script, Object securityDomain)
|
||||
throws JavaScriptException;
|
||||
}
|
@ -33,116 +33,16 @@
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* This class describes the support needed to implement security.
|
||||
* <p>
|
||||
* Three main pieces of functionality are required to implement
|
||||
* security for JavaScript. First, it must be possible to define
|
||||
* classes with an associated security context. (This security
|
||||
* context may be any object that has meaning to an embedding;
|
||||
* for a client-side JavaScript embedding this would typically
|
||||
* be an origin URL and/or a digital certificate.) Next it
|
||||
* must be possible to get the current class context so that
|
||||
* the implementation can determine securely which class is
|
||||
* requesting a privileged action. And finally, it must be
|
||||
* possible to map a class back into a security context so that
|
||||
* additional classes may be defined with that security context.
|
||||
* <p>
|
||||
* These three pieces of functionality are encapsulated in the
|
||||
* SecuritySupport class.
|
||||
* <p>
|
||||
* Additionally, an embedding may provide filtering on the
|
||||
* Java classes that are visible to scripts through the
|
||||
* <code>visibleToScripts</code> method.
|
||||
*
|
||||
* @see org.mozilla.javascript.Context
|
||||
* @see java.lang.ClassLoader
|
||||
* @since 1.4 Release 2
|
||||
* @author Norris Boyd
|
||||
*/
|
||||
public interface SecuritySupport {
|
||||
@deprecated Since Rhino 1.5 R4 this interface is split into {@link ClassShutter} interface with the single {@link ClassShutter#visibleToScripts(String fullClassName)} method and the abstract {@link SecurityController} class to implement domain-based security restrictions.
|
||||
<p>
|
||||
For binary compatibility with older code implementing SecuritySupport only to restrict class access via the visibleToScripts method, this interface extends {@link ClassShutter}, so to upgrade you code in this case simply replace SecuritySupport by ClassShutter and remove empty implementation of the defineClass, getClassContext and getSecurityDomain methods. Then call {@link Context#setClassShutter(ClassShutter)} in place of{@link Context#setSecuritySupport(SecuritySupport)}.
|
||||
<p>
|
||||
The new {@link SecurityController} is incompatible with the old security implementation, so if you previously had non-trivial implementation of the defineClass, getClassContext and getSecurityDomain methods, you need to upgrade you code to use the new {@link SecurityController}.
|
||||
*/
|
||||
public interface SecuritySupport extends ClassShutter {
|
||||
|
||||
/**
|
||||
* Define and load a Java class.
|
||||
* <p>
|
||||
* In embeddings that care about security, the securityDomain
|
||||
* must be associated with the defined class such that a call to
|
||||
* <code>getSecurityDomain</code> with that class will return this security
|
||||
* context.
|
||||
* <p>
|
||||
* @param name the name of the class
|
||||
* @param data the bytecode of the class
|
||||
* @param securityDomain some object specifying the security
|
||||
* context of the code that is defining this class.
|
||||
* Embeddings that don't care about security may allow
|
||||
* null here. This value propagated from the values passed
|
||||
* into methods of Context that evaluate scripts.
|
||||
*/
|
||||
public Class defineClass(String name, byte[] data,
|
||||
Object securityDomain);
|
||||
|
||||
/**
|
||||
* Get the current class Context.
|
||||
* <p>
|
||||
* This functionality is supplied by SecurityManager.getClassContext,
|
||||
* but only one SecurityManager may be instantiated in a single JVM
|
||||
* at any one time. So implementations that care about security must
|
||||
* provide access to this functionality through this interface.
|
||||
* <p>
|
||||
* Note that the 0th entry of the returned array should be the class
|
||||
* of the caller of this method. So if this method is implemented by
|
||||
* calling SecurityManager.getClassContext, this method must allocate
|
||||
* a new, shorter array to return.
|
||||
*/
|
||||
public Class[] getClassContext();
|
||||
|
||||
/**
|
||||
* Return the security context associated with the given class.
|
||||
* <p>
|
||||
* If <code>cl</code> is a class defined through a call to
|
||||
* SecuritySupport.defineClass, then return the security
|
||||
* context from that call. Otherwise return null.
|
||||
* @param cl a class potentially defined by defineClass
|
||||
* @return a security context object previously passed to defineClass
|
||||
*/
|
||||
public Object getSecurityDomain(Class cl);
|
||||
|
||||
/**
|
||||
* Return true iff the Java class with the given name should be exposed
|
||||
* to scripts.
|
||||
* <p>
|
||||
* An embedding may filter which Java classes are exposed through
|
||||
* LiveConnect to JavaScript scripts.
|
||||
* <p>
|
||||
* Due to the fact that there is no package reflection in Java,
|
||||
* this method will also be called with package names. There
|
||||
* is no way for Rhino to tell if "Packages.a.b" is a package name
|
||||
* or a class that doesn't exist. What Rhino does is attempt
|
||||
* to load each segment of "Packages.a.b.c": It first attempts to
|
||||
* load class "a", then attempts to load class "a.b", then
|
||||
* finally attempts to load class "a.b.c". On a Rhino installation
|
||||
* without any SecuritySupport set, and without any of the
|
||||
* above classes, the expression "Packages.a.b.c" will result in
|
||||
* a [JavaPackage a.b.c] and not an error.
|
||||
* <p>
|
||||
* With SecuritySupport supplied, Rhino will first call
|
||||
* visibleToScripts before attempting to look up the class name. If
|
||||
* visibleToScripts returns false, the class name lookup is not
|
||||
* performed and subsequent Rhino execution assumes the class is
|
||||
* not present. So for "java.lang.System.out.println" the lookup
|
||||
* of "java.lang.System" is skipped and thus Rhino assumes that
|
||||
* "java.lang.System" doesn't exist. So then for "java.lang.System.out",
|
||||
* Rhino attempts to load the class "java.lang.System.out" because
|
||||
* it assumes that "java.lang.System" is a package name.
|
||||
* <p>
|
||||
* @param fullClassName the full name of the class (including the package
|
||||
* name, with '.' as a delimiter). For example the
|
||||
* standard string class is "java.lang.String"
|
||||
* @return whether or not to reveal this class to scripts
|
||||
*/
|
||||
public boolean visibleToScripts(String fullClassName);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class Codegen extends Interpreter {
|
||||
|
||||
public Object compile(Context cx, Scriptable scope, Node tree,
|
||||
Object securityDomain,
|
||||
SecuritySupport securitySupport,
|
||||
SecurityController securityController,
|
||||
ClassNameHelper nameHelper)
|
||||
{
|
||||
ObjArray classFiles = new ObjArray();
|
||||
@ -78,7 +78,10 @@ public class Codegen extends Interpreter {
|
||||
|
||||
Exception e = null;
|
||||
Class result = null;
|
||||
DefiningClassLoader classLoader = new DefiningClassLoader();
|
||||
DefiningClassLoader classLoader = null;
|
||||
if (securityController == null) {
|
||||
classLoader = new DefiningClassLoader();
|
||||
}
|
||||
nameHelper.reset();
|
||||
|
||||
try {
|
||||
@ -97,12 +100,15 @@ public class Codegen extends Interpreter {
|
||||
try {
|
||||
if (repository.storeClass(name, classFile, isTopLevel)) {
|
||||
Class clazz = null;
|
||||
if (securitySupport != null) {
|
||||
clazz = securitySupport.defineClass(name, classFile,
|
||||
securityDomain);
|
||||
}
|
||||
if (clazz == null) {
|
||||
Context.checkSecurityDomainRequired();
|
||||
if (securityController != null) {
|
||||
clazz = securityController.
|
||||
defineClass(name, classFile, securityDomain);
|
||||
if (clazz == null) {
|
||||
throw new NullPointerException
|
||||
("SecurityController.defineClass"
|
||||
+" may not return null");
|
||||
}
|
||||
} else {
|
||||
clazz = classLoader.defineClass(name, classFile);
|
||||
ClassLoader loader = clazz.getClassLoader();
|
||||
clazz = loader.loadClass(name);
|
||||
|
@ -1,36 +0,0 @@
|
||||
#
|
||||
# Default JavaScript security properties file.
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Rhino code, released
|
||||
# May 6, 1998.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Norris Boyd
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU Public License (the "GPL"), in which case the
|
||||
# provisions of the GPL are applicable instead of those above.
|
||||
# If you wish to allow use of your version of this file only
|
||||
# under the terms of the GPL and not to allow others to use your
|
||||
# version of this file under the NPL, indicate your decision by
|
||||
# deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this
|
||||
# file under either the NPL or the GPL.
|
||||
|
||||
security.requireSecurityDomain = false
|
@ -397,7 +397,7 @@ class Runner implements Runnable {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Context cx = Context.enter();
|
||||
Context cx = Main.enterContext();
|
||||
|
||||
try {
|
||||
if (f != null)
|
||||
|
@ -0,0 +1,222 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package org.mozilla.javascript.tools.shell;
|
||||
|
||||
import java.security.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.mozilla.javascript.*;
|
||||
import org.mozilla.classfile.*;
|
||||
|
||||
public class JavaPolicySecurity extends SecurityProxy
|
||||
{
|
||||
|
||||
private static class Loader extends ClassLoader
|
||||
{
|
||||
Class defineClass(String name, byte[] data, ProtectionDomain domain) {
|
||||
return super.defineClass(name, data, 0, data.length, domain);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ContextPermissions extends PermissionCollection
|
||||
{
|
||||
// Construct PermissionCollection that permits an action only
|
||||
// if it is permitted by staticDomain and by security context of Java stack on
|
||||
// the moment of constructor invocation
|
||||
ContextPermissions(ProtectionDomain staticDomain) {
|
||||
_context = AccessController.getContext();
|
||||
if (staticDomain != null) {
|
||||
_statisPermissions = staticDomain.getPermissions();
|
||||
}
|
||||
setReadOnly();
|
||||
}
|
||||
|
||||
public void add(Permission permission) {
|
||||
throw new RuntimeException("NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
public boolean implies(Permission permission) {
|
||||
if (_statisPermissions != null) {
|
||||
if (!_statisPermissions.implies(permission)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
_context.checkPermission(permission);
|
||||
return true;
|
||||
}catch (AccessControlException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Enumeration elements()
|
||||
{
|
||||
return new Enumeration() {
|
||||
public boolean hasMoreElements() { return false; }
|
||||
public Object nextElement() { return null; }
|
||||
};
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getName());
|
||||
sb.append('@');
|
||||
sb.append(Integer.toHexString(System.identityHashCode(this)));
|
||||
sb.append(" (context=");
|
||||
sb.append(_context);
|
||||
sb.append(", static_permitions=");
|
||||
sb.append(_statisPermissions);
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
AccessControlContext _context;
|
||||
PermissionCollection _statisPermissions;
|
||||
}
|
||||
|
||||
public JavaPolicySecurity() {
|
||||
// To trigger error on jdk-1.1 with lazy load
|
||||
new CodeSource(null, null);
|
||||
}
|
||||
|
||||
protected void callProcessFileSecure(final Context cx,
|
||||
final Scriptable scope,
|
||||
final String filename)
|
||||
{
|
||||
AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
URL url = getUrlObj(filename);
|
||||
ProtectionDomain staticDomain = getUrlDomain(url);
|
||||
Main.processFileSecure(cx, scope, url.toExternalForm(),
|
||||
staticDomain);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private URL getUrlObj(String url) {
|
||||
URL urlObj;
|
||||
try {
|
||||
urlObj = new URL(url);
|
||||
}catch (MalformedURLException ex) {
|
||||
// Assume as Main.processFileSecure it is file, need to build its
|
||||
// URL
|
||||
String curDir = System.getProperty("user.dir");
|
||||
curDir = curDir.replace('\\', '/');
|
||||
if (!curDir.endsWith("/")) {
|
||||
curDir = curDir+'/';
|
||||
}
|
||||
try {
|
||||
URL curDirURL = new URL("file:"+curDir);
|
||||
urlObj = new URL(curDirURL, url);
|
||||
}catch (MalformedURLException ex2) {
|
||||
throw new RuntimeException
|
||||
("Can not construct file URL for '"+url+"':"
|
||||
+ex2.getMessage());
|
||||
}
|
||||
}
|
||||
return urlObj;
|
||||
}
|
||||
|
||||
private ProtectionDomain getUrlDomain(URL url) {
|
||||
CodeSource cs = new CodeSource(url, null);
|
||||
PermissionCollection pc = Policy.getPolicy().getPermissions(cs);
|
||||
return new ProtectionDomain(cs, pc);
|
||||
}
|
||||
|
||||
void doPrivileged(final Runnable code) {
|
||||
}
|
||||
|
||||
public Class defineClass(String name, byte[] data,
|
||||
Object securityDomain)
|
||||
{
|
||||
ProtectionDomain domain = (ProtectionDomain)securityDomain;
|
||||
Loader loader = new Loader();
|
||||
return loader.defineClass(name, data, domain);
|
||||
}
|
||||
|
||||
public Object getDynamicSecurityDomain(Object securityDomain)
|
||||
{
|
||||
ProtectionDomain staticDomain = (ProtectionDomain)securityDomain;
|
||||
return getDynamicDomain(staticDomain);
|
||||
}
|
||||
|
||||
private ProtectionDomain getDynamicDomain(ProtectionDomain staticDomain) {
|
||||
ContextPermissions p = new ContextPermissions(staticDomain);
|
||||
ProtectionDomain contextDomain = new ProtectionDomain(null, p);
|
||||
return contextDomain;
|
||||
}
|
||||
|
||||
public Object execWithDomain(final Context cx, final Scriptable scope,
|
||||
final Script script, Object securityDomain)
|
||||
throws JavaScriptException
|
||||
{
|
||||
ProtectionDomain staticDomain = (ProtectionDomain)securityDomain;
|
||||
// There is no direct way in Java to intersect permitions according
|
||||
// stack context with additional domain.
|
||||
// The following implementation first constructs ProtectionDomain
|
||||
// that allows actions only allowed by both staticDomain and current
|
||||
// stack context, and then constructs AccessController for this dynamic
|
||||
// domain.
|
||||
// If this is too slow, alternative solution would be to generate
|
||||
// class per domain with a proxy method to call to infect
|
||||
// java stack.
|
||||
// Another optimization in case of scripts coming from "world" domain,
|
||||
// that is having minimal default privileges is to construct
|
||||
// one AccessControlContext based on ProtectionDomain
|
||||
// with least possible privileges and simply call
|
||||
// AccessController.doPrivileged with this untrusted context
|
||||
|
||||
ProtectionDomain dynamicDomain = getDynamicDomain(staticDomain);
|
||||
ProtectionDomain[] tmp = { dynamicDomain };
|
||||
AccessControlContext restricted = new AccessControlContext(tmp);
|
||||
|
||||
PrivilegedExceptionAction action = new PrivilegedExceptionAction() {
|
||||
public Object run() throws JavaScriptException {
|
||||
return script.exec(cx, scope);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return AccessController.doPrivileged(action, restricted);
|
||||
}catch (PrivilegedActionException ex) {
|
||||
throw (JavaScriptException)(ex.getException());
|
||||
}
|
||||
}
|
||||
}
|
@ -65,6 +65,14 @@ public class Main {
|
||||
* execute scripts.
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
try {
|
||||
if (Boolean.getBoolean("rhino.use_java_policy_security")) {
|
||||
initJavaPolicySecuritySupport();
|
||||
}
|
||||
}catch (SecurityException ex) {
|
||||
ex.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
int result = exec(args);
|
||||
if (result != 0)
|
||||
System.exit(result);
|
||||
@ -74,7 +82,7 @@ public class Main {
|
||||
* Execute the given arguments, but don't System.exit at the end.
|
||||
*/
|
||||
public static int exec(String args[]) {
|
||||
Context cx = Context.enter();
|
||||
Context cx = enterContext();
|
||||
// Create the top-level scope object.
|
||||
global = getGlobal();
|
||||
errorReporter = new ToolErrorReporter(false, global.getErr());
|
||||
@ -102,7 +110,7 @@ public class Main {
|
||||
public static Global getGlobal() {
|
||||
if (global == null) {
|
||||
try {
|
||||
global = new Global(Context.enter());
|
||||
global = new Global(enterContext());
|
||||
}
|
||||
finally {
|
||||
Context.exit();
|
||||
@ -111,6 +119,14 @@ public class Main {
|
||||
return global;
|
||||
}
|
||||
|
||||
static Context enterContext() {
|
||||
Context cx = new Context();
|
||||
if (securityImpl != null) {
|
||||
cx.setSecurityController(securityImpl);
|
||||
}
|
||||
return Context.enter(cx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse arguments.
|
||||
*/
|
||||
@ -147,7 +163,7 @@ public class Main {
|
||||
if (++i == args.length)
|
||||
usage(arg);
|
||||
Reader reader = new StringReader(args[i]);
|
||||
evaluateReader(cx, global, reader, "<command>", 1);
|
||||
evaluateReader(cx, global, reader, "<command>", 1, null);
|
||||
continue;
|
||||
}
|
||||
if (arg.equals("-w")) {
|
||||
@ -174,6 +190,25 @@ public class Main {
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static void initJavaPolicySecuritySupport() {
|
||||
Throwable exObj;
|
||||
try {
|
||||
Class cl = Class.forName
|
||||
("org.mozilla.javascript.tools.shell.JavaPolicySecurity");
|
||||
securityImpl = (SecurityProxy)cl.newInstance();
|
||||
return;
|
||||
}catch (ClassNotFoundException ex) {
|
||||
exObj = ex;
|
||||
}catch (IllegalAccessException ex) {
|
||||
exObj = ex;
|
||||
}catch (InstantiationException ex) {
|
||||
exObj = ex;
|
||||
}catch (LinkageError ex) {
|
||||
exObj = ex;
|
||||
}
|
||||
throw new RuntimeException("Can not load security support: "+exObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate JavaScript source.
|
||||
*
|
||||
@ -223,7 +258,7 @@ public class Main {
|
||||
}
|
||||
Reader reader = new StringReader(source);
|
||||
Object result = evaluateReader(cx, global, reader,
|
||||
"<stdin>", startline);
|
||||
"<stdin>", startline, null);
|
||||
if (result != cx.getUndefinedValue()) {
|
||||
try {
|
||||
global.getErr().println(cx.toString(result));
|
||||
@ -251,6 +286,16 @@ public class Main {
|
||||
|
||||
public static void processFile(Context cx, Scriptable scope,
|
||||
String filename)
|
||||
{
|
||||
if (securityImpl == null) {
|
||||
processFileSecure(cx, scope, filename, null);
|
||||
}else {
|
||||
securityImpl.callProcessFileSecure(cx, scope, filename);
|
||||
}
|
||||
}
|
||||
|
||||
static void processFileSecure(Context cx, Scriptable scope,
|
||||
String filename, Object securityDomain)
|
||||
{
|
||||
Reader in = null;
|
||||
// Try filename first as URL
|
||||
@ -306,16 +351,17 @@ public class Main {
|
||||
// Here we evalute the entire contents of the file as
|
||||
// a script. Text is printed only if the print() function
|
||||
// is called.
|
||||
evaluateReader(cx, scope, in, filename, 1);
|
||||
evaluateReader(cx, scope, in, filename, 1, securityDomain);
|
||||
}
|
||||
|
||||
public static Object evaluateReader(Context cx, Scriptable scope,
|
||||
Reader in, String sourceName,
|
||||
int lineno)
|
||||
int lineno, Object securityDomain)
|
||||
{
|
||||
Object result = cx.getUndefinedValue();
|
||||
try {
|
||||
result = cx.evaluateReader(scope, in, sourceName, lineno, null);
|
||||
result = cx.evaluateReader(scope, in, sourceName, lineno,
|
||||
securityDomain);
|
||||
}
|
||||
catch (WrappedException we) {
|
||||
global.getErr().println(we.getWrappedException().toString());
|
||||
@ -402,4 +448,5 @@ public class Main {
|
||||
//static private DebugShell debugShell;
|
||||
static boolean processStdin = true;
|
||||
static Vector fileList = new Vector(5);
|
||||
private static SecurityProxy securityImpl;
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package org.mozilla.javascript.tools.shell;
|
||||
|
||||
import org.mozilla.javascript.*;
|
||||
|
||||
public abstract class SecurityProxy extends SecurityController
|
||||
{
|
||||
protected abstract void callProcessFileSecure(Context cx, Scriptable scope,
|
||||
String filename);
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user