When you deploy applications through Sun’s Java Web Start, they can’t hurt the end user’s system because they're run in a sandbox, a restrictive area that limits access to system resources. Although the sandbox mechanism is generally beneficial, it can sometimes handcuff developers by imposing restrictions that prevent basic application functionality. If you’re writing a tic-tac-toe gaming program, you can accommodate the sandbox’s blocking of all access to the local file system. But if you’re writing a file browser, you’ll need more access than is provided by default.
Fortunately, you can use a couple of tricks to get the user’s permission to escape the safety container imposed by Web Start. Let's review how sandboxes operate; then we'll see how you can get around them with your Web Start deployed apps.
Understanding the basics of Web Start
Part one of this series covered the basics of Sun's Java Web Start technology, including concepts and the packaging of applications for Web Start deployment. In this installment, I will detail techniques available to application authors who want to make greater use of system resources than is permitted by the default Web Start execution sandbox. If you are unfamiliar with Java Web Start, the first article will give you some background.
What is a sandbox?
An application sandbox is a space in which programs can be run with less access to system resources than would be available under normal circumstances. Modern operating systems run all applications in a sandbox of sorts, which prevents them from accessing and corrupting memory outside of their allotted regions. Java execution sandboxes operate at a much higher level than their operating system counterparts but provide essentially the same role: They prevent applications from making greater use of the system than is necessary.
This first sandbox that most Java developers collide with is the one that contains applets within a Web browser. The default behavior, the most restrictive one, prohibits almost all access to system resources, such as the file system. Network connectivity is prohibited. Even the system environment variables are filtered.
The Web Start application sandbox is a close cousin to the original applet sandboxes, with a few modifications found in Java 1.2 SecurityManager. Applications launched through Web Start will find that many methods that worked fine directly atop the Java virtual machine will fail with SecurityExceptions inside the Web Start imposed sandbox. Applications that need to operate outside of the sandbox have two choices: Java Network Launching Protocol (JNLP) services and application signing.
Although the designers of Web Start were familiar with the frustrations of developers forced to live within the constraints of the applet sandbox, they also recognized that most applications don't want or require full, unfettered access to system resources. Frequently, applications want nothing more than to persist a little data between execution instances. This is where JNLP services prove to be useful.
Web Start application containers can offer any or all of the JNLP services, and good applications degrade gracefully when services are unavailable. Each JNLP service has a name and a corresponding interface. Two of the most useful services are FileOpenService and FileSaveService, which allow for the reading and writing of files, respectively.
Web Start Application Developer’s Guide
You can explore the JNLP syntax and API in the Sun’s Web Start Application Developer’s Guide.
By default, the Web Start sandbox blocks access to the file system through conventional java.io access mechanisms; however, by requiring user interaction for every read and write, the FileOpenService and FileSaveService services can be used to gain this access with the user's knowledge and permission.
FileOpenService provides file-reading capabilities. Since the java.io file system interrogation mechanisms are out of bounds for Web Start applications, there is no way to associate a string file path with a file resource on the system and no way to create a FileInputStream to that resource even if you could. FileOpenService provides a method that causes a JFileChooser to be opened on the screen. A FileContents object that provides access to the contents of the user-selected file is returned to the calling application. An example of this can be found in Listing A. You should note that at no time does the calling application receive information about the actual location of the file within the user's file system.
FileSaveService provides the corresponding file-writing functionality. When invoked, a JFileChooser prompts the user for a location to save data. The data to save is provided as a FileContents object, as shown in Listing B. Again, at no time does the calling application receive information about the layout of the underlying file system.
JNLP services work by requiring the user to okay each violation of the Web Start sandbox constraints. Application signing, on the other hand, relies on first convincing the user that the application author is who he or she claims and second, on asking the user to trust that author's code with full access to all the system resources available to the virtual machine.
The first of these two steps is accomplished through the signing of an application's resources—chiefly, the Java Archive Files (JARs). Every Java development kit comes with two little used applications: keytool and jarsigner. Keytool can create and manage digital keys. Jarsigner employs those keys to sign digital resources. During development, self-generated keys are sufficient for testing Web Start deployment. However, with self-generated keys, Web Start displays a dialog advising users not to trust your application—which is definitely not conducive to building developer/user trust. For this reason, you will want to sign public releases with a key obtained from a recognized signing authority, such as Thawte or Verisign, which eliminates this warning.
The keytool application creates keys and places them within keystores, encrypted files that contain digital keys. The keys within a keystore are themselves encrypted. All this symmetric encryption means a lot of passwords, and that's a good thing. When a key signs a resource, it makes the statement that the owner of that key vouches for the contents of that signed resource. Protecting keys with password prevents others from signing without the key owner's permission.
How to generate your own key
Generating your own self-created key is as easy as using the first command line found in Listing C. Remember the passwords that are provided when prompted, as they're irretrievable in the event of loss. The newly generated key now exists in a keystore in the current directory named mykeystore.
Signing JARs with a digital key is done using the jarsigner tool. The syntax for the process is straightforward, as you can see in the second line of Listing C. Every JAR deployed as part of a Web Start application must be signed. If there is more than one, all must be signed by the same key. In some third-party applications, the originators must sign JARs. If that is the case, you need to split apart and re-create these jars before signing them. Multiple signatures on a JAR will prevent Web Start from considering them as verified.
After all the application JARs have been signed, you just need to make a small change to the application's JNLP file to request full system rights. This XML snippet must be placed inside the JNLP file's <jnlp> tag:
The first time Web Start launches an application that is requesting all permissions, it prompts the user to determine whether he or she trusts the signer of the accompanying JARs. Employing this method of creating self-generated keys, the prompt will advise against granting trust. Signatures created using keys from trusted key authorities will produce a prompt with a less discouraging message. Regardless, if the user replies yes, the application will be launched and will have full access to the underlying system as is generally expected. Since the user's permission is cached, the trust query does not reappear in the future.
Executing outside the box
Sandboxes are designed to ensure that applications don't wreak any sort of havoc on system resources—and in most cases, that's exactly what you want. But in situations where users need an app to have more access, it's useful to know how to outmaneuver the sandbox constraints. JNLP services and application signing offer two ways to give your applications more freedom.