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 Tomcat10ContainerAdapter.
44   */
45  public class Tomcat10ContainerAdapter extends AbstractTomcatContainer {
46  
47    @Override
48    protected Valve createValve() {
49      return new Tomcat10AgentValve();
50    }
51  
52    @Override
53    public boolean canBoundTo(String binding) {
54      if (binding == null) {
55        return false;
56      }
57      return binding.startsWith("Apache Tomcat/10.1")
58          || binding.startsWith("Apache Tomcat (TomEE)/10.0")
59          || binding.startsWith("NonStop(tm) Servlets For JavaServer Pages(tm) v10.1")
60          || binding.startsWith("Vmware tc") && binding.contains("/10.1");
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             throw new IllegalArgumentException(
153                 "Unknown dispatcher mapping: " + filterMap.getDispatcherMapping());
154         }
155 
156         String filterClass = "";
157         FilterDef fd = context.findFilterDef(filterMap.getFilterName());
158         if (fd != null) {
159           filterClass = fd.getFilterClass();
160         }
161 
162         List<FilterMapping> filterMappings = getFilterMappings(filterMap, dm, filterClass);
163         filterMaps.addAll(filterMappings);
164       }
165     }
166     return filterMaps;
167   }
168 
169   @Override
170   public List<FilterInfo> getApplicationFilters(Context context) {
171     FilterDef[] fds = context.findFilterDefs();
172     List<FilterInfo> filterDefs = new ArrayList<>(fds.length);
173     for (FilterDef filterDef : fds) {
174       if (filterDef != null) {
175         FilterInfo fi = getFilterInfo(filterDef);
176         filterDefs.add(fi);
177       }
178     }
179     return filterDefs;
180   }
181 
182   /**
183    * Gets the filter info.
184    *
185    * @param fd the fd
186    *
187    * @return the filter info
188    */
189   private static FilterInfo getFilterInfo(FilterDef fd) {
190     FilterInfo fi = new FilterInfo();
191     fi.setFilterName(fd.getFilterName());
192     fi.setFilterClass(fd.getFilterClass());
193     fi.setFilterDesc(fd.getDescription());
194     return fi;
195   }
196 
197   @Override
198   public List<ApplicationParam> getApplicationInitParams(Context context) {
199     /*
200      * We'll try to determine if a parameter value comes from a deployment descriptor or a context
201      * descriptor.
202      *
203      * Assumption: context.findParameter() returns only values of parameters that are declared in a
204      * deployment descriptor.
205      *
206      * If a parameter is declared in a context descriptor with override=false and redeclared in a
207      * deployment descriptor, context.findParameter() still returns its value, even though the value
208      * is taken from a context descriptor.
209      *
210      * context.findApplicationParameters() returns all parameters that are declared in a context
211      * descriptor regardless of whether they are overridden in a deployment descriptor or not or
212      * not.
213      */
214     /*
215      * creating a set of parameter names that are declared in a context descriptor and can not be
216      * overridden in a deployment descriptor.
217      */
218     Set<String> nonOverridableParams = new HashSet<>();
219     for (ApplicationParameter appParam : context.findApplicationParameters()) {
220       if (appParam != null && !appParam.getOverride()) {
221         nonOverridableParams.add(appParam.getName());
222       }
223     }
224     List<ApplicationParam> initParams = new ArrayList<>(20);
225     ServletContext servletCtx = context.getServletContext();
226     for (String paramName : Collections.list(servletCtx.getInitParameterNames())) {
227       ApplicationParam param = new ApplicationParam();
228       param.setName(paramName);
229       param.setValue(servletCtx.getInitParameter(paramName));
230       /*
231        * if the parameter is declared in a deployment descriptor and it is not declared in a context
232        * descriptor with override=false, the value comes from the deployment descriptor
233        */
234       param.setFromDeplDescr(
235           context.findParameter(paramName) != null && !nonOverridableParams.contains(paramName));
236       initParams.add(param);
237     }
238     return initParams;
239   }
240 
241   @Override
242   public boolean resourceExists(String name, Context context) {
243     return context.getResources().getResource(name) != null;
244   }
245 
246   @Override
247   public InputStream getResourceStream(String name, Context context) throws IOException {
248     WebResource resource = context.getResources().getResource(name);
249     return resource.getInputStream();
250   }
251 
252   @Override
253   public Long[] getResourceAttributes(String name, Context context) {
254     Long[] result = new Long[2];
255     WebResource resource = context.getResources().getResource(name);
256     result[0] = resource.getContentLength();
257     result[1] = resource.getLastModified();
258     return result;
259   }
260 
261   /**
262    * Returns the security token required to bind to a naming context.
263    *
264    * @param context the catalina context
265    *
266    * @return the security token for use with <code>ContextBindings</code>
267    */
268   @Override
269   protected Object getNamingToken(Context context) {
270     // Used by NamingContextListener when setting up JNDI context
271     Object token = context.getNamingToken();
272     if (!ContextAccessController.checkSecurityToken(context, token)) {
273       logger.error("Couldn't get a valid security token. ClassLoader binding will fail.");
274     }
275     return token;
276   }
277 
278 }