1   package org.apache.velocity.test;
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.io.IOException;
23  import java.io.StringWriter;
24  import java.io.Writer;
25  import java.util.Collection;
26  import java.util.HashSet;
27  
28  import junit.framework.Test;
29  import junit.framework.TestSuite;
30  
31  import org.apache.velocity.VelocityContext;
32  import org.apache.velocity.app.VelocityEngine;
33  import org.apache.velocity.context.Context;
34  import org.apache.velocity.exception.MethodInvocationException;
35  import org.apache.velocity.exception.ParseErrorException;
36  import org.apache.velocity.exception.ResourceNotFoundException;
37  import org.apache.velocity.runtime.RuntimeConstants;
38  import org.apache.velocity.util.introspection.SecureUberspector;
39  
40  /**
41   * Checks that the secure introspector is working properly.
42   *
43   * @author <a href="Will Glass-Husain">wglass@forio.com</a>
44   * @version $Id: SecureIntrospectionTestCase.java 509906 2007-02-21 06:11:05Z wglass $
45   */
46  public class SecureIntrospectionTestCase extends BaseTestCase
47  {
48  
49      /**
50       * Default constructor.
51       * @param name
52       */
53      public SecureIntrospectionTestCase(String name)
54      {
55          super(name);
56      }
57  
58      public static Test suite()
59      {
60         return new TestSuite(SecureIntrospectionTestCase.class);
61      }
62  
63  
64      private String [] badTemplateStrings =
65      {
66          "$test.Class.Methods",
67          "$test.Class.ClassLoader",
68          "$test.Class.ClassLoader.loadClass('java.util.HashMap').newInstance().size()"
69      };
70  
71      private String [] goodTemplateStrings =
72      {
73          "#foreach($item in $test.collection)$item#end",
74          "$test.Class.Name",
75          "#set($test.Property = 'abc')$test.Property",
76          "$test.aTestMethod()"
77      };
78  
79      /**
80       *  Test to see that "dangerous" methods are forbidden
81       *  @exception Exception
82       */
83      public void testBadMethodCalls()
84          throws Exception
85      {
86          VelocityEngine ve = new VelocityEngine();
87          ve.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, SecureUberspector.class.getName());
88          ve.init();
89  
90          /*
91           * all of the following method calls should not work
92           */
93          doTestMethods(ve, badTemplateStrings, false);
94      }
95  
96      /**
97       *  Test to see that "dangerous" methods are forbidden
98       *  @exception Exception
99       */
100     public void testGoodMethodCalls()
101         throws Exception
102     {
103         VelocityEngine ve = new VelocityEngine();
104         ve.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, SecureUberspector.class.getName());
105         ve.init();
106 
107         /*
108          * all of the following method calls should not work
109          */
110         doTestMethods(ve, goodTemplateStrings, true);
111     }
112 
113     private void doTestMethods(VelocityEngine ve, String[] templateStrings, boolean shouldeval)
114     {
115         Context c = new VelocityContext();
116         c.put("test", this);
117 
118         try
119         {
120             for (int i=0; i < templateStrings.length; i++)
121             {
122                 if (shouldeval && !doesStringEvaluate(ve,c,templateStrings[i]))
123                 {
124                     fail ("Should have evaluated: " + templateStrings[i]);
125                 }
126 
127                 if (!shouldeval && doesStringEvaluate(ve,c,templateStrings[i]))
128                 {
129                     fail ("Should not have evaluated: " + templateStrings[i]);
130                 }
131             }
132 
133         }
134         catch (Exception e)
135         {
136             fail(e.toString());
137         }
138     }
139 
140     private boolean doesStringEvaluate(VelocityEngine ve, Context c, String inputString) throws ParseErrorException, MethodInvocationException, ResourceNotFoundException, IOException
141     {
142     	// assume that an evaluation is bad if the input and result are the same (e.g. a bad reference)
143     	// or the result is an empty string (e.g. bad #foreach)
144     	Writer w = new StringWriter();
145         ve.evaluate(c, w, "foo", inputString);
146         String result = w.toString();
147         return (result.length() > 0 ) &&  !result.equals(inputString);
148     }
149 
150     private String testProperty;
151     public String getProperty()
152     {
153         return testProperty;
154     }
155 
156     public int aTestMethod()
157     {
158         return 1;
159     }
160 
161     public void setProperty(String val)
162     {
163         testProperty = val;
164     }
165 
166 
167 	public Collection getCollection()
168 	{
169 		Collection c = new HashSet();
170 		c.add("aaa");
171 		c.add("bbb");
172 		c.add("ccc");
173 		return c;
174 	}
175 
176 }
177 
178