1 /*
2  * JasperReports - Free Java Reporting Library.
3  * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
4  * http://www.jaspersoft.com
5  *
6  * Unless you have purchased a commercial license agreement from Jaspersoft,
7  * the following license terms apply:
8  *
9  * This program is part of JasperReports.
10  *
11  * JasperReports is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * JasperReports is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
23  */

24 package net.sf.jasperreports.compilers;
25
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.ConcurrentHashMap;
30
31 import net.sf.jasperreports.annotations.properties.Property;
32 import net.sf.jasperreports.annotations.properties.PropertyScope;
33 import net.sf.jasperreports.engine.JRPropertiesUtil;
34 import net.sf.jasperreports.engine.JRPropertiesUtil.PropertySuffix;
35 import net.sf.jasperreports.engine.JRRuntimeException;
36 import net.sf.jasperreports.engine.JasperReportsContext;
37 import net.sf.jasperreports.engine.util.ClassLoaderFilter;
38 import net.sf.jasperreports.functions.FunctionsBundle;
39 import net.sf.jasperreports.functions.FunctionsUtil;
40 import net.sf.jasperreports.properties.PropertyConstants;
41
42 /**
43  * @author Lucian Chirita (lucianc@users.sourceforge.net)
44  */

45 public class ReportClassFilter implements ClassLoaderFilter
46 {
47     
48     @Property(
49             category = PropertyConstants.CATEGORY_FILL,
50             defaultValue = "false",
51             scopes = {PropertyScope.CONTEXT},
52             sinceVersion = PropertyConstants.VERSION_6_13_0,
53             valueType = Boolean.class
54             )
55     public static final String PROPERTY_PREFIX_CLASS_FILTER_ENABLED = 
56             JRPropertiesUtil.PROPERTY_PREFIX + "report.class.filter.enabled";
57     
58     @Property(
59             category = PropertyConstants.CATEGORY_FILL,
60             scopes = {PropertyScope.CONTEXT},
61             sinceVersion = PropertyConstants.VERSION_6_13_0,
62             name = "net.sf.jasperreports.report.class.whitelist.{arbitrary_name}"
63             )
64     public static final String PROPERTY_PREFIX_CLASS_WHITELIST = 
65             JRPropertiesUtil.PROPERTY_PREFIX + "report.class.whitelist.";
66     
67     public static final String EXCEPTION_MESSAGE_KEY_CLASS_NOT_VISIBLE = "compilers.class.not.visible";
68
69     private static void addHardcodedWhitelist(StandardReportClassWhitelist whitelist)
70     {
71         whitelist.addClass("java.lang.Boolean");
72         whitelist.addClass("java.lang.String");
73         whitelist.addClass("java.lang.StringBuffer");
74         whitelist.addClass("java.lang.StringBuilder");
75         whitelist.addClass("java.lang.Character");
76         whitelist.addClass("java.lang.Byte");
77         whitelist.addClass("java.lang.Short");
78         whitelist.addClass("java.lang.Integer");
79         whitelist.addClass("java.lang.Long");
80         whitelist.addClass("java.lang.Float");
81         whitelist.addClass("java.lang.Double");
82         whitelist.addClass("java.lang.Math");
83     }
84     
85     private boolean filterEnabled;
86     private List<ReportClassWhitelist> whitelists;
87     
88     private Map<String, Boolean> visibilityCache = new ConcurrentHashMap<String, Boolean>();
89
90     public ReportClassFilter(JasperReportsContext jasperReportsContext)
91     {
92         JRPropertiesUtil properties = JRPropertiesUtil.getInstance(jasperReportsContext);
93         filterEnabled = properties.getBooleanProperty(PROPERTY_PREFIX_CLASS_FILTER_ENABLED);
94         if (filterEnabled)
95         {
96             whitelists = new ArrayList<>();
97             
98             StandardReportClassWhitelist whitelist = new StandardReportClassWhitelist();
99             addHardcodedWhitelist(whitelist);
100             loadPropertiesWhitelist(properties, whitelist);
101             loadFunctionsWhitelist(jasperReportsContext, whitelist);
102             whitelists.add(whitelist);
103             
104             List<ReportClassWhitelist> extensionWhitelists = jasperReportsContext.getExtensions(
105                     ReportClassWhitelist.class);
106             whitelists.addAll(extensionWhitelists);            
107         }        
108     }
109
110     private static void loadPropertiesWhitelist(JRPropertiesUtil propertiesUtil, 
111             StandardReportClassWhitelist whitelist)
112     {
113         List<PropertySuffix> properties = propertiesUtil.getProperties(PROPERTY_PREFIX_CLASS_WHITELIST);
114         for (PropertySuffix propertySuffix : properties)
115         {
116             String whitelistString = propertySuffix.getValue();
117             whitelist.addWhitelist(whitelistString);
118         }
119     }
120
121     private static void loadFunctionsWhitelist(JasperReportsContext jasperReportsContext, 
122             StandardReportClassWhitelist whitelist)
123     {
124         FunctionsUtil functionsUtil = FunctionsUtil.getInstance(jasperReportsContext);
125         List<FunctionsBundle> functionBundles = functionsUtil.getAllFunctionBundles();
126         for (FunctionsBundle functionsBundle : functionBundles)
127         {
128             List<Class<?>> functionClasses = functionsBundle.getFunctionClasses();
129             for (Class<?> functionClass : functionClasses)
130             {
131                 whitelist.addClass(functionClass.getName());
132             }
133         }
134     }
135
136     public boolean isFilteringEnabled()
137     {
138         return filterEnabled;
139     }
140     
141     @Override
142     public void checkClassVisibility(String className) throws JRRuntimeException
143     {
144         boolean visible = isClassVisible(className);
145         if (!visible)
146         {
147             throw new JRRuntimeException(EXCEPTION_MESSAGE_KEY_CLASS_NOT_VISIBLE, new Object[] {className});
148         }
149     }
150     
151     public boolean isClassVisible(String className)
152     {
153         Boolean visible = visibilityCache.get(className);
154         if (visible == null)
155         {
156             visible = visible(className);
157             visibilityCache.put(className, visible);
158         }
159         return visible;
160     }
161
162     protected boolean visible(String className)
163     {
164         boolean visible;
165         if (filterEnabled)
166         {
167             visible = false;
168             for (ReportClassWhitelist whitelist : whitelists)
169             {
170                 if (whitelist.includesClass(className))
171                 {
172                     visible = true;
173                     break;
174                 }
175             }
176         }
177         else
178         {
179             visible = true;
180         }
181         return visible;
182     }
183     
184 }
185