Skip to main content

JSR 315 Needs YOU: Response to Greg's blog

Posted by mode on May 14, 2008 at 4:38 PM PDT

In my previous post I described some of the pluggability mechanism being added to the servlet 3.0 specification. One of the issues that I didn't touch upon in detail was how the annotations and web-fragments are processed and how can one override / turn off the auto scanning of annotations and web-fragments.

Greg Wilkins from Webtide blogged
about the pluggability mechanism and raised an issue with the auto-scanning. Hopefully this blog will make the argument for the simple scanning of annotations and web-fragments and argue against the case of having a more flexible scheme in this release of the servlet specification.

I will start with the annotation case first and then talk about the web-fragments. When you use annotations to declare servlets and Filters then you must have a url-mapping / FilterMapping attribute on the corresponding servlet / Filter. In this way there is no convention by which a servlet is exposed without having an explicit mapping. Also , as with the rest of the Java EE platform, specifically technologies like EJB and Web Services, the deployment descriptor is used to override information that is specified via annotations. So if you have a servlet that is declared via annotations during development and now you need to change one attribute of the servlet when you go from development to production, you don't need to modify the code. Instead you override the configuration using the web.xml file. In the example below I show how this can be used -

@Servlet(url-mapping="/foo")
public class MyServlet {
    @GET
    public void handleGet(HttpServletRequest req, HttpServletResponse res) {
         ...
     }
}

At deployment time say you want to override the url-mapping for the servlet defined above. The way you would do that would be by defining the new mapping for the servlet in the web.xml as shown below -

<web-app>
  <servlet-mapping>
    <servlet-name>
      MyServlet
    </servlet-name>
    <url-pattern>
      /MyApp
    </url-pattern>
  </servlet-mapping>
</web-app>

If you didn't want any of the annotations to be processed at all by the container and wanted to specify all the configuration via the deployment descriptor, then, like with the rest of the Java EE 5 platform, we have the metadata-complete element in the descriptor. If the element is present and set to "true" then the container will not process any annotations and just use the configuration specified in the descriptor. This provides a way disable the auto-scanning for those that have concerns about performance, and security. This is consistent with what we have today in Java EE 5 platform and has worked well with EJBs and JAX-WS (Web Services APIs). We have not received any negative feedback about security and performance being an issue. Web Services are endpoints that are exposed on the web so the argument someone makes about there not being a security hole in EJB does not stand true for Web Services.

The second issue is about auto-scanning of web-fragments. The early draft of the specification says that the container needs to process web-fragments and make available the servlets, filters an listeners defined via the fragments. As discussed in my earlier post, this helps with use of frameworks. Currently the early draft of the specification says that the same flag - metadata-complete controls both the scanning of annotations and fragments. I still think that is sufficient for the developers. However during JavaOne we had an expert group face-to-face meeting and discussed the possibility of having another flag to control the scanning of web fragments and use the metadata-complete just to control scanning of annotations. Again similar to metadata-complete this flag would control whether to scan for web-fragments or not. If you choose not to scan the web-fragments then you would need to specify the entire metadata that you need in in the web.xml of the application, a-la metadata-complete :). For those that have major security concerns this would probably be the route to go because even if you do have the include mechanism there would be no way to specify just one servlet from the jar file. The container would still scan for all the servlets, filters and listeners from the framework available. The concept of "trusting" certain frameworks doesn't seem to solve the problem. Let's take Spring for example - if you choose Spring as the framework but didn't want one of the servlets defined in Spring to be available. The include mechanism would not work for you. You would have to fall back on defining everything in the web.xml of the application anyways. The benefit that the include proposal from Greg Wilkins is very little specially if the main concern is that servlets and filters are being exposed without the user intending to do so. I think that it is the problem of the framework developer and not the user of the framework to make sure that they don't expose certain types of components. By using a flag to control scanning you can effectively get what the include mechanism provides except you don't get partial scanning of only a certain set of jars. The include mechanism would probably only make the descriptor more verbose in having to list the jars you want scanned.

Another mechanism that came up during the face-to-face which hasn't been still talked about in the expert group is the concept of disabling servlets and filters in the application's web.xml. For example we could have in the application's web.xml the following -

  <servlet>
    <servlet-name>FrameworkServlet</servlet-name>
    <enabled>false</enabled>
  </servlet>

This way some of the servlets that aren't needed in production can be disabled via the main web.xml of the application and the security issue can be mitigated while keeping things simple.

Related Topics >>

Comments

vhi: Disabling scanning is enabled by "metadata-complete". All you need to do is put that in your app's descriptor.

whartung: Even if you specify which packages to scan that does not limit what servlets and filters get deployed. You are back to using metadata-complete and filling out the entire descriptor. I think that enabled=false is a better mechanism to control anything that you don't want deployed.

ss141213: We did talk about the mechanism like TLDs but the rest of the platform does not do anything like that. We thought it would be more consistent with EJB 3.0 and JAX-WS 2.x to use metadata-complete.

gregwilkins: I think we can start with what we have and test the waters. If people absolutely want fully selective and modular configuration we can add that in a future release.

My argument is not so much about security or trust. These are just some of the reasons that you may want to change the reasonable default configurations baked into your jars. As it appears that I have not made my case on this issue, I've made my last word in my blog, and will move onto other features. Jetty however will support both auto-discovered and fully selective and parameterized modular configuration via annotations, fragments and listeners.

I think the container should be secure by-default. Instead of allowing for any library to automatically contribute its servlets to the container, we should explicitly enable particular packages like "com.mycomp.publik*". So by default, the scanning should be disabled, and it should upto the developer to explicitly enable scanning for his/her servlets. The all-or-nothing approach would simply encourage the developers to allow scanning on all libraries, ending with a security issue.

Why don't we follow something similar to TLDs. Let web-fragments be named. Allow web fragments to be discovered and included in a web.xml. Allow two ways to include web fragments in web.xml, viz: a) explicitly mentioned in web.xml b) implicitly available in class-space of the web app.

Sahoo

Ok, so this mechanism is to allow framework authors to ship frameworks with reasonable defaults. We've trusted these people with the plumbing driving our websites, I suspect they'll make reasonable sane decisions about what should be turned on or off by default. Turning off all auto-config and writing the web.xml yourself nets you out at where you are today so I find it reasonable. The false would be fantastic and should be enough to keep this quick and easy.

I think a couple of things are necessary.

One, there needs to be a logging mechanism in place that shows all of the mappings the container is making. At a minimum I should be able to deploy my application and see all of the servlets et al that the container is going to use, that way I can scan that list for anything that looks untoward or out of place.

Two, I think there needs to be a more granular mechanism for disabling scanning and/or mapping than the metadata-complete catch all.

Basically, the metadata-complete flag requires me, as a developer, to manually configure the entire context, which means I can't leverage the annotations at all once the slightest conflict appears.

The metadata-complete is valuable in locking down the container and preventing new code from be accidently introduced, but combined with a verbose listing, that should be less of a problem.

The "enabled=false" technique may be enough to handle this, but I still think it would be nice to limit scanning period to only select package spaces (i.e. I can enable scanning only on com.mystuff.*), which lets me leverage both the annotations, yet still be reasonable secure against potential threats without having to adopt the burden of complete manual configuration.