1 package org.apache.velocity.util.introspection;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.lang.reflect.Method;
23
24 import org.apache.velocity.runtime.log.Log;
25
26 /**
27 * <p>Prevent "dangerous" classloader/reflection related calls. Use this
28 * introspector for situations in which template writers are numerous
29 * or untrusted. Specifically, this introspector prevents creation of
30 * arbitrary objects and prevents reflection on objects.
31 *
32 * <p>See documentation of checkObjectExecutePermission() for
33 * more information on specific classes and methods blocked.
34 *
35 * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
36 * @version $Id: SecureIntrospectorImpl.java 509094 2007-02-19 05:17:09Z wglass $
37 */
38 public class SecureIntrospectorImpl extends Introspector implements SecureIntrospectorControl
39 {
40 private String[] badClasses;
41 private String[] badPackages;
42
43 public SecureIntrospectorImpl(String[] badClasses, String[] badPackages, Log log)
44 {
45 super(log);
46 this.badClasses = badClasses;
47 this.badPackages = badPackages;
48 }
49
50 /**
51 * Get the Method object corresponding to the given class, name and parameters.
52 * Will check for appropriate execute permissions and return null if the method
53 * is not allowed to be executed.
54 *
55 * @param clazz Class on which method will be called
56 * @param methodName Name of method to be called
57 * @param params array of parameters to method
58 * @return Method object retrieved by Introspector
59 * @throws IllegalArgumentException The parameter passed in were incorrect.
60 */
61 public Method getMethod(Class clazz, String methodName, Object[] params) throws IllegalArgumentException
62 {
63 if (!checkObjectExecutePermission(clazz,methodName))
64 {
65 log.warn ("Cannot retrieve method " + methodName +
66 " from object of class " + clazz.getName() +
67 " due to security restrictions.");
68 return null;
69
70 }
71 else
72 {
73 return super.getMethod(clazz, methodName, params);
74 }
75 }
76
77 /**
78 * Determine which methods and classes to prevent from executing. Always blocks
79 * methods wait() and notify(). Always allows methods on Number, Boolean, and String.
80 * Prohibits method calls on classes related to reflection and system operations.
81 * For the complete list, see the properties <code>introspector.restrict.classes</code>
82 * and <code>introspector.restrict.packages</code>.
83 *
84 * @param clazz Class on which method will be called
85 * @param methodName Name of method to be called
86 * @see org.apache.velocity.util.introspection.SecureIntrospectorControl#checkObjectExecutePermission(java.lang.Class, java.lang.String)
87 */
88 public boolean checkObjectExecutePermission(Class clazz, String methodName)
89 {
90
91 /**
92 * check for wait and notify
93 */
94 if ( (methodName != null) && (methodName.equals("wait") || methodName.equals("notify")) )
95 {
96 return false;
97 }
98
99 /**
100 * Always allow the most common classes - Number, Boolean and String
101 */
102 else if (java.lang.Number.class.isAssignableFrom(clazz))
103 {
104 return true;
105 }
106
107 else if (java.lang.Boolean.class.isAssignableFrom(clazz))
108 {
109 return true;
110 }
111
112 else if (java.lang.String.class.isAssignableFrom(clazz))
113 {
114 return true;
115 }
116
117
118 /**
119 * Always allow Class.getName()
120 */
121 else if (java.lang.Class.class.isAssignableFrom(clazz) && (methodName != null) && methodName.equals("getName"))
122 {
123 return true;
124 }
125
126 /**
127 * check the classname (minus any array info)
128 * whether it matches disallowed classes or packages
129 */
130 String className = clazz.getName();
131 if (className.startsWith("[L") && className.endsWith(";"))
132 {
133 className = className.substring(2,className.length() - 1);
134 }
135
136 String packageName;
137 int dotPos = className.lastIndexOf('.');
138 packageName = (dotPos == -1) ? "" : className.substring(0,dotPos);
139
140 int sz = badPackages.length;
141 for (int i = 0; i < sz; i++)
142 {
143 if (packageName.equals(badPackages[i]))
144 {
145 return false;
146 }
147 }
148
149 sz = badClasses.length;
150 for (int i = 0; i < sz; i++)
151 {
152 if (className.equals(badClasses[i]))
153 {
154 return false;
155 }
156 }
157
158 return true;
159 }
160 }