001: package org.apache.velocity.util.introspection;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.lang.reflect.Method;
023:
024: import org.apache.velocity.runtime.log.Log;
025:
026: /**
027: * <p>Prevent "dangerous" classloader/reflection related calls. Use this
028: * introspector for situations in which template writers are numerous
029: * or untrusted. Specifically, this introspector prevents creation of
030: * arbitrary objects and prevents reflection on objects.
031: *
032: * <p>See documentation of checkObjectExecutePermission() for
033: * more information on specific classes and methods blocked.
034: *
035: * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
036: * @version $Id: SecureIntrospectorImpl.java 509906 2007-02-21 06:11:05Z wglass $
037: */
038: public class SecureIntrospectorImpl extends Introspector implements
039: SecureIntrospectorControl {
040: private String[] badClasses;
041: private String[] badPackages;
042:
043: public SecureIntrospectorImpl(String[] badClasses,
044: String[] badPackages, Log log) {
045: super (log);
046: this .badClasses = badClasses;
047: this .badPackages = badPackages;
048: }
049:
050: /**
051: * Get the Method object corresponding to the given class, name and parameters.
052: * Will check for appropriate execute permissions and return null if the method
053: * is not allowed to be executed.
054: *
055: * @param clazz Class on which method will be called
056: * @param methodName Name of method to be called
057: * @param params array of parameters to method
058: * @return Method object retrieved by Introspector
059: * @throws IllegalArgumentException The parameter passed in were incorrect.
060: */
061: public Method getMethod(Class clazz, String methodName,
062: Object[] params) throws IllegalArgumentException {
063: if (!checkObjectExecutePermission(clazz, methodName)) {
064: log.warn("Cannot retrieve method " + methodName
065: + " from object of class " + clazz.getName()
066: + " due to security restrictions.");
067: return null;
068:
069: } else {
070: return super .getMethod(clazz, methodName, params);
071: }
072: }
073:
074: /**
075: * Determine which methods and classes to prevent from executing. Always blocks
076: * methods wait() and notify(). Always allows methods on Number, Boolean, and String.
077: * Prohibits method calls on classes related to reflection and system operations.
078: * For the complete list, see the properties <code>introspector.restrict.classes</code>
079: * and <code>introspector.restrict.packages</code>.
080: *
081: * @param clazz Class on which method will be called
082: * @param methodName Name of method to be called
083: * @see org.apache.velocity.util.introspection.SecureIntrospectorControl#checkObjectExecutePermission(java.lang.Class, java.lang.String)
084: */
085: public boolean checkObjectExecutePermission(Class clazz,
086: String methodName) {
087:
088: /**
089: * check for wait and notify
090: */
091: if ((methodName != null)
092: && (methodName.equals("wait") || methodName
093: .equals("notify"))) {
094: return false;
095: }
096:
097: /**
098: * Always allow the most common classes - Number, Boolean and String
099: */
100: else if (java.lang.Number.class.isAssignableFrom(clazz)) {
101: return true;
102: }
103:
104: else if (java.lang.Boolean.class.isAssignableFrom(clazz)) {
105: return true;
106: }
107:
108: else if (java.lang.String.class.isAssignableFrom(clazz)) {
109: return true;
110: }
111:
112: /**
113: * Always allow Class.getName()
114: */
115: else if (java.lang.Class.class.isAssignableFrom(clazz)
116: && (methodName != null) && methodName.equals("getName")) {
117: return true;
118: }
119:
120: /**
121: * check the classname (minus any array info)
122: * whether it matches disallowed classes or packages
123: */
124: String className = clazz.getName();
125: if (className.startsWith("[L") && className.endsWith(";")) {
126: className = className.substring(2, className.length() - 1);
127: }
128:
129: String packageName;
130: int dotPos = className.lastIndexOf('.');
131: packageName = (dotPos == -1) ? "" : className.substring(0,
132: dotPos);
133:
134: int sz = badPackages.length;
135: for (int i = 0; i < sz; i++) {
136: if (packageName.equals(badPackages[i])) {
137: return false;
138: }
139: }
140:
141: sz = badClasses.length;
142: for (int i = 0; i < sz; i++) {
143: if (className.equals(badClasses[i])) {
144: return false;
145: }
146: }
147:
148: return true;
149: }
150: }
|