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