package org.apache.velocity.util.introspection; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.slf4j.Logger; import java.lang.reflect.Method; /** *
Prevent "dangerous" classloader/reflection related calls. Use this * introspector for situations in which template writers are numerous * or untrusted. Specifically, this introspector prevents creation of * arbitrary objects and prevents reflection on objects. * *
See documentation of checkObjectExecutePermission() for
* more information on specific classes and methods blocked.
*
* @author Will Glass-Husain
* @version $Id$
* @since 1.5
*/
public class SecureIntrospectorImpl extends Introspector implements SecureIntrospectorControl
{
private String[] badClasses;
private String[] badPackages;
public SecureIntrospectorImpl(String[] badClasses, String[] badPackages, Logger log)
{
super(log);
this.badClasses = badClasses;
this.badPackages = badPackages;
}
/**
* Get the Method object corresponding to the given class, name and parameters.
* Will check for appropriate execute permissions and return null if the method
* is not allowed to be executed.
*
* @param clazz Class on which method will be called
* @param methodName Name of method to be called
* @param params array of parameters to method
* @return Method object retrieved by Introspector
* @throws IllegalArgumentException The parameter passed in were incorrect.
*/
public Method getMethod(Class clazz, String methodName, Object[] params)
throws IllegalArgumentException
{
if (!checkObjectExecutePermission(clazz, methodName))
{
log.warn("Cannot retrieve method {} from object of class {} due to security restrictions."
, methodName, clazz.getName());
return null;
}
else
{
return super.getMethod(clazz, methodName, params);
}
}
/**
* Determine which methods and classes to prevent from executing. Always blocks
* methods wait() and notify(). Always allows methods on Number, Boolean, and String.
* Prohibits method calls on classes related to reflection and system operations.
* For the complete list, see the properties introspector.restrict.classes
* and introspector.restrict.packages
.
*
* @param clazz Class on which method will be called
* @param methodName Name of method to be called
* @see org.apache.velocity.util.introspection.SecureIntrospectorControl#checkObjectExecutePermission(java.lang.Class, java.lang.String)
*/
public boolean checkObjectExecutePermission(Class clazz, String methodName)
{
/**
* check for wait and notify
*/
if (methodName != null &&
(methodName.equals("wait") || methodName.equals("notify")) )
{
return false;
}
/**
* Always allow the most common classes - Number, Boolean and String
*/
else if (Number.class.isAssignableFrom(clazz))
{
return true;
}
else if (Boolean.class.isAssignableFrom(clazz))
{
return true;
}
else if (String.class.isAssignableFrom(clazz))
{
return true;
}
/**
* Always allow Class.getName()
*/
else if (Class.class.isAssignableFrom(clazz) &&
(methodName != null) && methodName.equals("getName"))
{
return true;
}
/**
* check the classname (minus any array info)
* whether it matches disallowed classes or packages
*/
String className = clazz.getName();
if (className.startsWith("[L") && className.endsWith(";"))
{
className = className.substring(2, className.length() - 1);
}
int dotPos = className.lastIndexOf('.');
String packageName = (dotPos == -1) ? "" : className.substring(0, dotPos);
for (String badPackage : badPackages)
{
if (packageName.equals(badPackage))
{
return false;
}
}
for (String badClass : badClasses)
{
if (className.equals(badClass))
{
return false;
}
}
return true;
}
}