View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe;
12  
13  import java.io.IOException;
14  import java.io.InputStream;
15  import java.util.ArrayList;
16  import java.util.Collections;
17  import java.util.HashSet;
18  import java.util.List;
19  import java.util.Set;
20  
21  import javax.servlet.ServletContext;
22  
23  import org.apache.catalina.Context;
24  import org.apache.catalina.Valve;
25  import org.apache.catalina.WebResource;
26  import org.apache.catalina.deploy.NamingResourcesImpl;
27  import org.apache.jasper.JspCompilationContext;
28  import org.apache.jasper.Options;
29  import org.apache.jasper.compiler.JspRuntimeContext;
30  import org.apache.naming.ContextAccessController;
31  import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
32  import org.apache.tomcat.util.descriptor.web.ContextResource;
33  import org.apache.tomcat.util.descriptor.web.ContextResourceLink;
34  import org.apache.tomcat.util.descriptor.web.FilterDef;
35  import org.apache.tomcat.util.descriptor.web.FilterMap;
36  
37  import psiprobe.model.ApplicationParam;
38  import psiprobe.model.ApplicationResource;
39  import psiprobe.model.FilterInfo;
40  import psiprobe.model.FilterMapping;
41  
42  /**
43   * The Class Tomcat90ContainerAdapter.
44   */
45  public class Tomcat90ContainerAdapter extends AbstractTomcatContainer {
46  
47    @Override
48    protected Valve createValve() {
49      return new Tomcat90AgentValve();
50    }
51  
52    @Override
53    public boolean canBoundTo(String binding) {
54      if (binding == null) {
55        return false;
56      }
57      return binding.startsWith("Apache Tomcat/9.0")
58          || binding.startsWith("Apache Tomcat (TomEE)/9.0") || binding.startsWith("Pivotal tc")
59          || binding.startsWith("Vmware tc") && binding.contains("/9.0");
60    }
61  
62    /**
63     * Gets the filter mappings.
64     *
65     * @param fmap the fmap
66     * @param dm the dm
67     * @param filterClass the filter class
68     *
69     * @return the filter mappings
70     */
71    protected List<FilterMapping> getFilterMappings(FilterMap fmap, String dm, String filterClass) {
72      String[] urls = fmap.getURLPatterns();
73      String[] servlets = fmap.getServletNames();
74      List<FilterMapping> results = new ArrayList<>(urls.length + servlets.length);
75      addFilterMapping(fmap.getFilterName(), dm, filterClass, urls, results, FilterMapType.URL);
76      addFilterMapping(fmap.getFilterName(), dm, filterClass, servlets, results,
77          FilterMapType.SERVLET_NAME);
78      return results;
79    }
80  
81    @Override
82    protected JspCompilationContext createJspCompilationContext(String name, Options opt,
83        ServletContext sctx, JspRuntimeContext jrctx, ClassLoader classLoader) {
84  
85      JspCompilationContext jcctx = new JspCompilationContext(name, opt, sctx, null, jrctx);
86      jcctx.setClassLoader(classLoader);
87      return jcctx;
88    }
89  
90    @Override
91    public void addContextResourceLink(Context context, List<ApplicationResource> resourceList) {
92  
93      NamingResourcesImpl namingResources = context.getNamingResources();
94      for (ContextResourceLink link : namingResources.findResourceLinks()) {
95        ApplicationResource resource = new ApplicationResource();
96  
97        logger.debug("reading resourceLink: {}", link.getName());
98        resource.setApplicationName(context.getName());
99        resource.setName(link.getName());
100       resource.setType(link.getType());
101       resource.setLinkTo(link.getGlobal());
102 
103       registerGlobalResourceAccess(link);
104 
105       resourceList.add(resource);
106     }
107   }
108 
109   @Override
110   public void addContextResource(Context context, List<ApplicationResource> resourceList) {
111     NamingResourcesImpl namingResources = context.getNamingResources();
112     for (ContextResource contextResource : namingResources.findResources()) {
113       ApplicationResource resource = new ApplicationResource();
114 
115       logger.info("reading resource: {}", contextResource.getName());
116       resource.setApplicationName(context.getName());
117       resource.setName(contextResource.getName());
118       resource.setType(contextResource.getType());
119       resource.setScope(contextResource.getScope());
120       resource.setAuth(contextResource.getAuth());
121       resource.setDescription(contextResource.getDescription());
122 
123       resourceList.add(resource);
124     }
125   }
126 
127   @Override
128   public List<FilterMapping> getApplicationFilterMaps(Context context) {
129     FilterMap[] fms = context.findFilterMaps();
130     List<FilterMapping> filterMaps = new ArrayList<>(fms.length);
131     for (FilterMap filterMap : fms) {
132       if (filterMap != null) {
133         String dm;
134         switch (filterMap.getDispatcherMapping()) {
135           case FilterMap.ASYNC:
136             dm = "ASYNC";
137             break;
138           case FilterMap.ERROR:
139             dm = "ERROR";
140             break;
141           case FilterMap.FORWARD:
142             dm = "FORWARD";
143             break;
144           case FilterMap.INCLUDE:
145             dm = "INCLUDE";
146             break;
147           case FilterMap.REQUEST:
148             dm = "REQUEST";
149             break;
150           default:
151             dm = "";
152         }
153 
154         String filterClass = "";
155         FilterDef fd = context.findFilterDef(filterMap.getFilterName());
156         if (fd != null) {
157           filterClass = fd.getFilterClass();
158         }
159 
160         List<FilterMapping> filterMappings = getFilterMappings(filterMap, dm, filterClass);
161         filterMaps.addAll(filterMappings);
162       }
163     }
164     return filterMaps;
165   }
166 
167   @Override
168   public List<FilterInfo> getApplicationFilters(Context context) {
169     FilterDef[] fds = context.findFilterDefs();
170     List<FilterInfo> filterDefs = new ArrayList<>(fds.length);
171     for (FilterDef filterDef : fds) {
172       if (filterDef != null) {
173         FilterInfo fi = getFilterInfo(filterDef);
174         filterDefs.add(fi);
175       }
176     }
177     return filterDefs;
178   }
179 
180   /**
181    * Gets the filter info.
182    *
183    * @param fd the fd
184    *
185    * @return the filter info
186    */
187   private static FilterInfo getFilterInfo(FilterDef fd) {
188     FilterInfo fi = new FilterInfo();
189     fi.setFilterName(fd.getFilterName());
190     fi.setFilterClass(fd.getFilterClass());
191     fi.setFilterDesc(fd.getDescription());
192     return fi;
193   }
194 
195   @Override
196   public List<ApplicationParam> getApplicationInitParams(Context context) {
197     /*
198      * We'll try to determine if a parameter value comes from a deployment descriptor or a context
199      * descriptor.
200      *
201      * Assumption: context.findParameter() returns only values of parameters that are declared in a
202      * deployment descriptor.
203      *
204      * If a parameter is declared in a context descriptor with override=false and redeclared in a
205      * deployment descriptor, context.findParameter() still returns its value, even though the value
206      * is taken from a context descriptor.
207      *
208      * context.findApplicationParameters() returns all parameters that are declared in a context
209      * descriptor regardless of whether they are overridden in a deployment descriptor or not or
210      * not.
211      */
212     /*
213      * creating a set of parameter names that are declared in a context descriptor and can not be
214      * overridden in a deployment descriptor.
215      */
216     Set<String> nonOverridableParams = new HashSet<>();
217     for (ApplicationParameter appParam : context.findApplicationParameters()) {
218       if (appParam != null && !appParam.getOverride()) {
219         nonOverridableParams.add(appParam.getName());
220       }
221     }
222     List<ApplicationParam> initParams = new ArrayList<>(20);
223     ServletContext servletCtx = context.getServletContext();
224     for (String paramName : Collections.list(servletCtx.getInitParameterNames())) {
225       ApplicationParam param = new ApplicationParam();
226       param.setName(paramName);
227       param.setValue(servletCtx.getInitParameter(paramName));
228       /*
229        * if the parameter is declared in a deployment descriptor and it is not declared in a context
230        * descriptor with override=false, the value comes from the deployment descriptor
231        */
232       param.setFromDeplDescr(
233           context.findParameter(paramName) != null && !nonOverridableParams.contains(paramName));
234       initParams.add(param);
235     }
236     return initParams;
237   }
238 
239   @Override
240   public boolean resourceExists(String name, Context context) {
241     return context.getResources().getResource(name) != null;
242   }
243 
244   @Override
245   public InputStream getResourceStream(String name, Context context) throws IOException {
246     WebResource resource = context.getResources().getResource(name);
247     return resource.getInputStream();
248   }
249 
250   @Override
251   public Long[] getResourceAttributes(String name, Context context) {
252     Long[] result = new Long[2];
253     WebResource resource = context.getResources().getResource(name);
254     result[0] = resource.getContentLength();
255     result[1] = resource.getLastModified();
256     return result;
257   }
258 
259   /**
260    * Returns the security token required to bind to a naming context.
261    *
262    * @param context the catalina context
263    *
264    * @return the security token for use with <code>ContextBindings</code>
265    */
266   @Override
267   protected Object getNamingToken(Context context) {
268     // Used by NamingContextListener when setting up JNDI context
269     Object token = context.getNamingToken();
270     if (!ContextAccessController.checkSecurityToken(context, token)) {
271       logger.error("Couldn't get a valid security token. ClassLoader binding will fail.");
272     }
273     return token;
274   }
275 
276 }