Showing posts for tag "servlets"

Block Web Access to Code/Java Source Files

Thu Feb 19 10:49:45 EST 2026

Last year, while developing Jakarta Modules, I realized that there's a path to accessing Java source files by path in normal NSF apps. This ended up being tracked as a Defect Article, but has unfortunately since been deferred to an unspecified future time. I think it's worth fixing before such a time, though, so I set about doing that.

TL;DR

If you have a file in Code/Java in Designer named "com.mycompany.MyClass", the source is accessible via "foo.nsf/xsp/com/mycompany/MyClass.java". There are a couple ways to patch this:

  • Set up a web substitution rule for /*.nsf/xsp/*.java to /doesnotexist.html or the like. That won't cover non-Java files (like translation.properties, etc.), but it'd at least prevent your source code from being visible. It'd also be good to set one up for plugin.xml
  • Install my new project Code/Java blocker

Further Explanation

The specific problem here is the way the "foo.nsf/xsp/*" URL namespace works. That is essentially the "webapp version" of your NSF, and URLs coming in here are processed as Servlets and, failing that, static resources. When a request comes in matching that, the XPages runtime looks for IServletFactory implementations to handle it first - if one of those matches, it hands the request off to the matched Servlet. If none matches, it then moves on to some code that handles static resources like a classic Java web app would. I'm not quite sure why it does this, but I'd guess it's probably a holdover from traditional web behavior and not actually really useful. Still, it may be load-bearing after so many years, so I can see why HCL wouldn't want to outright remove this.

Anyway, the problem arises from the fact that the virtual filesystem used by the "static resource" search includes all file-resource-like entities that don't start with /WEB-INF. Java classes stored as Code/Java resources are this type of file, and so their conceptual file path is included in the pool. Thus, if you know the name of a Java class inside an NSF and have web access to that NSF, you can get its source via URL. This is admittedly a bit of a stretch as an attack vector: it being a problem relies on someone a) knowing the full name of a Java class and b) that Java class containing damaging information. If you have your app set to show stack traces on errors (not the default), someone could potentially glean some local class names, and from there walk the tree by looking at imports and class references, but it's still a long walk.

Long walk or no, though, it's worth fixing.

The first fix - the web redirection rule - should cover the bulk of what you'd want. There's an off chance that it might run afoul of some edge case where there actually is a Servlet that's intentionally serving up files that end in ".java", but that's pretty unlikely.

Because I like writing code, I made a small project that does the job a little more specifically. The way the plugin works is that it contributes a IServletFactory to the XPages runtime for all NSFs that builds a collection of Code/Java files and then, when a request comes in that matches that or some other vetoed paths, returns a stock Servlet that returns 404 in the same way that other non-matched paths in that namespace do. That should make it so that the source files are not accessible and also don't "leak" their presence at all.

Either way, I suggest applying a fix for this until it's done in the product.

Building an App with the frostillic.us Framework, Part 7

Tue Oct 07 21:00:41 EDT 2014

  1. Jul 09 2014 - Building an App with the frostillic.us Framework, Part 1
  2. Jul 11 2014 - Building an App with the frostillic.us Framework, Part 2
  3. Jul 17 2014 - Building an App with the frostillic.us Framework, Part 3
  4. Jul 17 2014 - Building an App with the frostillic.us Framework, Part 4
  5. Jul 21 2014 - Building an App with the frostillic.us Framework, Part 5
  6. Jul 23 2014 - Building an App with the frostillic.us Framework, Part 6
  7. Oct 07 2014 - Building an App with the frostillic.us Framework, Part 7

Well, it's been much longer than planned, and this topic isn't actually particularly groundbreaking, but the series returns!

  1. Define the data model
  2. Create the view and add it to an XPage
  3. Create the editing page
  4. Add validation and translation to the model
  5. Add notification to the model
  6. Add sorting to the view
  7. Basic servlet
  8. REST with Angular.js

One of the edge features of the Framework is that it assists in writing DesignerFacesServlet servlets - which are sort of like XAgents but written directly as Java classes, without an XPage component.

Before I explain how they work in the Framework, there's a caveat: these servlets do not have (reliable) sessionAsSigner access. The reason for this is that IBM's mechanism for determining the signer doesn't cover the case of just having a Java class. That said, it does have access to the rest of the XPages environment, including the same instances of managed beans available to XPages.

With that unpleasantness aside, here's an example servlet:

package servlet;

import javax.faces.context.FacesContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import frostillicus.xsp.servlet.AbstractXSPServlet;

public class ExampleServlet extends AbstractXSPServlet {
	@Override
	protected void doService(HttpServletRequest req, HttpServletResponse res, FacesContext facesContext, ServletOutputStream out) throws Exception {
		out.println("hello");
	}
}

Once you create that class (in the package "servlet"), it is available as "/foo.nsf/xsp/exampleServlet". As with an XPage, you can add arbitrary stuff after the servlet name with a "/" and in the query string. Unlike in an XPage, the servlet name is not removed from the path info. So, for example, this method:

protected void doService(HttpServletRequest req, HttpServletResponse res, FacesContext facesContext, ServletOutputStream out) throws Exception {
	Map<String, String> param = (Map<String, String>) ExtLibUtil.resolveVariable(facesContext, "param");
	out.println("param: " + param);
	out.println("pathInfo: " + req.getPathInfo());
}

...with this URL fragment:

foo.nsf/xsp/exampleServlet/foo?bar=baz
...results in this in the browser:
param: {bar=baz}
pathInfo: /xsp/exampleServlet/foo

By default, the result is served as text/plain, but you can change that as usual, with res.setContentType(...).

For most apps, a servlet like this isn't necessary. And for apps that do have a use for servlets, the XAgent and ExtLib-control routes may be more useful. Nonetheless, I've found a number of uses for these, and I appreciate that I don't have a bunch of extra non-UI XPages cluttering up the list.

Building XPages servlets with FacesContext access

Thu Sep 06 10:05:00 EDT 2012

I have a confession to make: I'm not crazy about XAgents. Don't get me wrong - they do everything they're supposed to and do it well. However, it's always kind of bothered me that you take a visual design element like an XPage and turn off all the higher levels to get back down to the core servlet. Plus, it muddies the list of XPages in the DB - some are actual XPages, some are just wrappers for scripts. So my objection is essentially pedantry.

However, the fact that my objection is wildly exaggerated has never stopped me from sinking a lot of time into finding the "right" answer before, and it hasn't stopped me now. When what I want to build is, say, an Excel exporter for a particular type of document in a reporting DB, what I really want is a basic servlet that exists only in the database and has access to the surrounding XSP environment and custom classes. Fortunately, between a post by Sven Hasselbach, the referenced Chinese-language developerWorks article, the XSP Starter Kit, and a bit about facesContext.release() on a JSF-focused article and reinforced by the FacesContextServlet class from the ExtLib, I made it work.

The developerWorks article covers the bulk of the work - creating the Factory, setting up the file in META-INF, etc.. After that, you can set up your servlets by extending (using the Starter Kit method) DesignerFacesServlet. It turns out that the important thing to remember is to close out your context when you're done - I ran into a lot of trouble from not doing this, which would break XPages visited after the servlet. As an example, here's the test class I ended up building while figuring out how to make it not blow up my application:

import java.io.*;
import java.util.*;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.webapp.DesignerFacesServlet;
import javax.faces.context.FacesContext;
import javax.servlet.*;
import javax.servlet.http.*;

public class TestServlet extends DesignerFacesServlet implements Serializable {
	private static final long serialVersionUID = -1152176824225969420L;

	@SuppressWarnings("unchecked")
	@Override
	public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
		// Set up handy environment variables
		HttpServletRequest req = (HttpServletRequest)servletRequest;
		HttpServletResponse res = (HttpServletResponse)servletResponse;
		ServletOutputStream out = res.getOutputStream();
		FacesContext facesContext = this.getFacesContext(req, res);

		try {
			res.setContentType("text/plain");

			out.println("start");

			// The sessionScope is available via the ExternalContext. Resolving the variable
			//	would work as well
			Map<Object, Object> sessionScope = facesContext.getExternalContext().getSessionMap();
			sessionScope.put("counter", sessionScope.containsKey("counter") ? (Integer)sessionScope.get("counter") + 1 : 1);
			out.println("Counter: " + sessionScope.get("counter"));

			// A query string map is available via the request. This method, as opposed to
			// 	getting the "param" variable, returns arrays of strings, allowing things like
			//	"?foo=bar&foo=baz" properly
			Map<String, String[]> param = req.getParameterMap();
			for(String key : param.keySet()) {
				out.println(key + " => " + StringUtil.concatStrings(param.get(key), ';', false));
			}

			out.println("done");

		} catch(Exception e) {
			e.printStackTrace(new PrintStream(out));
		} finally {
			out.close();

			// It shouldn't be null if things are going well, but a check never hurt
			if(facesContext != null) {
				facesContext.responseComplete();
				facesContext.release();
			}
		}
	}
}

I set up my ServletFactory to use this one for "/test", and so it's available via a URL like "/database.nsf/xsp/test?foo=bar". As with an XPage, you can also chain more path bits on after the servlet name, like "/database.nsf/xsp/test/some/other/stuff" and get to that via req.getPathInfo() - though with the caveat that, unlike with an XPage, the servlet path is included in the path info, so it would return "/xsp/test/some/other/stuff".

So long as I don't run into any other app-exploding problems, I plan to go this route for non-UI requests like exports and actions. When I have a use for it, I'll also go down the related path of writing custom services, for which the ExtLib provides an extensive foundation.