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 import org.apache.velocity.runtime.log.Log;
24
25 /**
26 * <p>Prevent "dangerous" classloader/reflection related calls. Use this
27 * introspector for situations in which template writers are numerous
28 * or untrusted. Specifically, this introspector prevents creation of
29 * arbitrary objects and prevents reflection on objects.
30 *
31 * <p>See documentation of checkObjectExecutePermission() for
32 * more information on specific classes and methods blocked.
33 *
34 * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
35 * @version $Id: SecureIntrospectorImpl.java 705375 2008-10-16 22:06:30Z nbubna $
36 * @since 1.5
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)
62 throws IllegalArgumentException
63 {
64 if (!checkObjectExecutePermission(clazz, methodName))
65 {
66 log.warn("Cannot retrieve method " + methodName +
67 " from object of class " + clazz.getName() +
68 " due to security restrictions.");
69 return null;
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 * check for wait and notify
92 */
93 if (methodName != null &&
94 (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 (Number.class.isAssignableFrom(clazz))
103 {
104 return true;
105 }
106 else if (Boolean.class.isAssignableFrom(clazz))
107 {
108 return true;
109 }
110 else if (String.class.isAssignableFrom(clazz))
111 {
112 return true;
113 }
114
115 /**
116 * Always allow Class.getName()
117 */
118 else if (Class.class.isAssignableFrom(clazz) &&
119 (methodName != null) && methodName.equals("getName"))
120 {
121 return true;
122 }
123
124 /**
125 * check the classname (minus any array info)
126 * whether it matches disallowed classes or packages
127 */
128 String className = clazz.getName();
129 if (className.startsWith("[L") && className.endsWith(";"))
130 {
131 className = className.substring(2, className.length() - 1);
132 }
133
134 int dotPos = className.lastIndexOf('.');
135 String packageName = (dotPos == -1) ? "" : className.substring(0, dotPos);
136
137 for (int i = 0, size = badPackages.length; i < size; i++)
138 {
139 if (packageName.equals(badPackages[i]))
140 {
141 return false;
142 }
143 }
144
145 for (int i = 0, size = badClasses.length; i < size; i++)
146 {
147 if (className.equals(badClasses[i]))
148 {
149 return false;
150 }
151 }
152
153 return true;
154 }
155 }