| /* |
| * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.script.javascript; |
| |
| import java.lang.reflect.*; |
| import static sun.security.util.SecurityConstants.*; |
| import sun.org.mozilla.javascript.internal.*; |
| |
| /** |
| * This wrap factory is used for security reasons. JSR 223 script |
| * engine interface and JavaScript engine classes are run as bootstrap |
| * classes. For example, java.lang.Class.forName method (when called without |
| * class loader) uses caller's class loader. This may be exploited by script |
| * authors to access classes otherwise not accessible. For example, |
| * classes in sun.* namespace are normally not accessible to untrusted |
| * code and hence should not be accessible to JavaScript run from |
| * untrusted code. |
| * |
| * @author A. Sundararajan |
| * @since 1.6 |
| */ |
| final class RhinoWrapFactory extends WrapFactory { |
| private RhinoWrapFactory() {} |
| private static RhinoWrapFactory theInstance; |
| |
| static synchronized WrapFactory getInstance() { |
| if (theInstance == null) { |
| theInstance = new RhinoWrapFactory(); |
| } |
| return theInstance; |
| } |
| |
| // We use instance of this class to wrap security sensitive |
| // Java object. Please refer below. |
| private static class RhinoJavaObject extends NativeJavaObject { |
| RhinoJavaObject(Scriptable scope, Object obj, Class type) { |
| // we pass 'null' to object. NativeJavaObject uses |
| // passed 'type' to reflect fields and methods when |
| // object is null. |
| super(scope, null, type); |
| |
| // Now, we set actual object. 'javaObject' is protected |
| // field of NativeJavaObject. |
| javaObject = obj; |
| } |
| } |
| |
| public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, |
| Object javaObject, Class staticType) { |
| SecurityManager sm = System.getSecurityManager(); |
| ClassShutter classShutter = RhinoClassShutter.getInstance(); |
| if (javaObject instanceof ClassLoader) { |
| // Check with Security Manager whether we can expose a |
| // ClassLoader... |
| if (sm != null) { |
| sm.checkPermission(GET_CLASSLOADER_PERMISSION); |
| } |
| // if we fall through here, check permission succeeded. |
| return super.wrapAsJavaObject(cx, scope, javaObject, staticType); |
| } else { |
| String name = null; |
| if (javaObject instanceof Class) { |
| name = ((Class)javaObject).getName(); |
| } else if (javaObject instanceof Member) { |
| Member member = (Member) javaObject; |
| // Check member access. Don't allow reflective access to |
| // non-public members. Note that we can't call checkMemberAccess |
| // because that expects exact stack depth! |
| if (sm != null && !Modifier.isPublic(member.getModifiers())) { |
| return null; |
| } |
| name = member.getDeclaringClass().getName(); |
| } |
| // Now, make sure that no ClassShutter prevented Class or Member |
| // of it is accessed reflectively. Note that ClassShutter may |
| // prevent access to a class, even though SecurityManager permit. |
| if (name != null) { |
| if (!classShutter.visibleToScripts(name)) { |
| return null; |
| } else { |
| return super.wrapAsJavaObject(cx, scope, javaObject, staticType); |
| } |
| } |
| } |
| |
| // we have got some non-reflective object. |
| Class dynamicType = javaObject.getClass(); |
| String name = dynamicType.getName(); |
| if (!classShutter.visibleToScripts(name)) { |
| // Object of some sensitive class (such as sun.net.www.* |
| // objects returned from public method of java.net.URL class. |
| // We expose this object as though it is an object of some |
| // super class that is safe for access. |
| |
| Class type = null; |
| |
| // Whenever a Java Object is wrapped, we are passed with a |
| // staticType which is the type found from environment. For |
| // example, method return type known from signature. The dynamic |
| // type would be the actual Class of the actual returned object. |
| // If the staticType is an interface, we just use that type. |
| if (staticType != null && staticType.isInterface()) { |
| type = staticType; |
| } else { |
| // dynamicType is always a class type and never an interface. |
| // find an accessible super class of the dynamic type. |
| while (dynamicType != null) { |
| dynamicType = dynamicType.getSuperclass(); |
| name = dynamicType.getName(); |
| if (classShutter.visibleToScripts(name)) { |
| type = dynamicType; break; |
| } |
| } |
| // atleast java.lang.Object has to be accessible. So, when |
| // we reach here, type variable should not be null. |
| assert type != null: |
| "even java.lang.Object is not accessible?"; |
| } |
| // create custom wrapper with the 'safe' type. |
| return new RhinoJavaObject(scope, javaObject, type); |
| } else { |
| return super.wrapAsJavaObject(cx, scope, javaObject, staticType); |
| } |
| } |
| } |