Applet Input/Output

Applet I/O is a tricky subject. Applets are designed to execute within the browser of a person who is surfing the Web. Our Web surfer might have no idea what type of Web site he or she is about to encounter. If an applet within one of those Web pages could read and, more important, write to the disk with impunity, Java would be doomed as a Web language. No one would allow potentially dangerous applets to execute on their machine. People would turn off the Java interpreter within their browsers and leave it off.

This disk I/O security problem has led to the oft-heard comment that Java applets can't read or write to the hard disk. Although Java applets must make some concessions to security concerns, they can perform disk I/O.

Client-Side I/O

Writing a Java program to perform disk I/O isn't difficult. Part I contains several examples of apps that read and write files on the disk. To avoid the data-loss problem inherent in I/O-capable applets, Java has adopted a series of security models over time.

Originally, Java didn't allow applets to perform any type of file access. Applets executing within the client's browser had no access to the underlying machine. This security model was known as the sandbox model (the idea being that the applet could play with the sand inside the browser all it wanted but it couldn't get out of the box). Although this form of security kept the client safe, it severely limited the usefulness of Java applets.

Even in the initial release of Java, its developers conceded that some type of security model other than the sandbox model was needed. Eventually, Microsoft and the rest of the Java community developed a more advanced security model that allowed various forms of I/O on the client machine at the user's discretion. This security model involved what is known as applet signing and is referred to as the trusted applet model.

The trusted applet model allows the Java applet to request some level of access from the user. The Java developers realized that it was impossible for the browser to determine access automatically because the browser is unable to differentiate a benign Java applet from an attacker. To the VM, one set of disk write instructions looks like another.

The only form of security that the Java authors could offer was to inform the person running the browser of who the originator of the applet was, and then let the user decide whether to give the applet access to the client computer. The Java developers felt that a programmer would be loath to write attack applets if his or her identity were attached. Therefore, applet authors must electronically sign their applets. Before a programmer can sign an applet, he or she must have a signature. Such a signature must verify the identity of the author. In addition, the signature must be tamper proof.

NOTE
An applet whose signature has been accepted by the user is known as a secure applet.

Getting a signature

Several companies dispense electronic signatures. Probably the most popular signature company is VeriSign (www.verisign.com). This company sells a number of different types of signatures. The easiest (and cheapest) is a Class 1 signature. The Class 1 signature is meant for an individual programmer. For a Class 1 license, VeriSign verifies data such as an e-mail address, phone number, and mail address.

If a programmer of a Class 1_signed applet intentionally generates an applet that damages someone's data files, that person can contact VeriSign, who can find (and perhaps legally charge) the individual who wrote the applet. In addition, any Internet user presented with an applet request for I/O signed with only a Class 1 license has reason to be suspicious, because Class 1 licenses lack the extra security and identification of higher classes.

Screenshot-10 shows the first page of the VeriSign questionnaire I filled out to receive my Class 1 license.

VeriSign also sells licenses that offer higher levels of security. Class 2 licenses are available to small companies and offer more protection than a Class 1 license does. Class 3 licenses are available only to software companies, not to individuals. Before being granted a license, a company must demonstrate that it is a viable software company, and not some shadow company created for the purpose of generating damaging applets. Applets carrying the signature of a Class 3 license holder are fairly safe. For example, you can assume that an applet signed by Microsoft is safe.

Java Click to view at full size.

Screenshot-10. Obtaining an electronic signature involves filling out a detailed questionnaire from a company registered to dispense such signatures.

Signing an applet

Unfortunately, when the format of the Java .class file was created, no room was allocated for storing a signature. Therefore, before an applet can be signed, the .class file must be wrapped in some other type of file that does allow space for an electronic signature. Visual J Plus Plus v6 uses the cabinet (.CAB) file for this purpose.

These .CAB files existed long before Java appeared on the scene. Microsoft uses CAB files to save data in compressed format. The CAB file uses a compression technique similar to that of the ZIP file.

Fortunately, the CAB file is ideal for applet signing. First, the increased compression of the CAB file provides reduced download times. Second, the CAB file allows for the inclusion of user-defined record types. Visual J Plus Plus v6 added a new record type to contain the electronic signature.

Prior to Visual J Plus Plus v6, generating and electronically signing a CAB file involved a number of commands, all of which had an assortment of mysterious arguments. Fortunately, Visual J Plus Plus v6 has automated applet signing to the point that all you need to do is to make a few selections in dialog boxes.

An example secure applet

To demonstrate the process of applet signing, let's create an applet that reads a user-specified file from the local client disk. We'll begin by creating an empty project that we'll name SecureApplet. Use the Add Item command to add the class SecureApplet and the HTML file SecureApplet.htm.

code

The SecureApplet.java file appears as follows:

import java.awt.*;
import java.applet.Applet;
import java.io.*;
import java.awt.event.*;
/**
 * The following applet reads a user-specified file
 * from the client's hard disk.
 */
public class SecureApplet extends Applet
{
 // the following objects are used to read
 // the file name and save the data read
 Button button = new Button("Read Text");
 TextArea textArea = new TextArea();
 TextField fileName = new TextField();
 /**
 * Lay out the applet window.
 */
 public void init()
 {
 // make the background color white so that
 // it blends in with the browser's default background
 this.setBackground(Color.white);
 Font font = new Font("Arial", Font.PLAIN, 18);
 this.setFont(font);
 // use a slightly smaller font for the text area
 Font textFont = new Font("Arial", Font.PLAIN, 12);
 textArea.setFont(textFont);
 // lay out the text area, label subpanel,
 // and button subpanel
 Panel buttonSubPanel = new Panel();
 Panel labelSubPanel = new Panel();
 this.setLayout(new BorderLayout());
 this.add("North", labelSubPanel);
 this.add("Center", textArea);
 this.add("South", buttonSubPanel);
 // layout label area
 labelSubPanel.setLayout(new BorderLayout());
 labelSubPanel.add("West", new Label("File Name:"));
 labelSubPanel.add("Center", fileName);
 // set the button in an evenly spaced horizontal layout
 GridLayout gl = new GridLayout();
 gl.setVgap(5);
 buttonSubPanel.setLayout(gl);
 buttonSubPanel.add(new Label(" "));
 buttonSubPanel.add(button);
 buttonSubPanel.add(new Label(" "));
 // create an action listener for the button to
 // perform the actual read
 button.addActionListener(new ReadActionListener());
 }
 class ReadActionListener implements ActionListener
 {
 // read the filename specified in the fileName
 // text field, and write it to textArea
 public void actionPerformed(ActionEvent ae)
 {
 // get the name of the file
 String fName = fileName.getText();
 String text;
 try
 {
 // open the file, and read its contents
 // into a byte array buffer
 FileInputStream fis = new FileInputStream(fName);
 int size = fis.available();
 byte[] buffer = new byte[size];
 fis.read(buffer);
 // turn the buffer into a String
 text = new String(buffer);
 }
 catch(Exception e)
 {
 // on failure, set the text to a meaningful message
 text = "Read Failed:" + e.toString();
 }
 // display the text string in textArea
 textArea.setText(text);
 }
 }
}


Compared with other applets you've seen in this chapter, this applet is reasonably straightforward. The constructor builds three controls: a TextField object in which the user can enter the input filename, a Button object to effect the read operation, and a TextArea object in which to display the contents of the file read.

The init() method begins by setting the font to a pleasingly large 18-point Arial. The font for the text area is set to a somewhat smaller 12-point font to allow more of the display text to be visible. The applet then sets about building subpanels to arrange the three components attractively.

The ReadActionListener that's attached to the button begins by retrieving the name of the file to read from the fileName text field. A FileInputStream object is created using this name, and then the entire contents of the file are read into a byte buffer. Finally, this buffer is converted into a string that is displayed in the text area. If an exception is generated anywhere during the read operation, an error message is displayed instead.

Signing SecureApplet

Before we can execute the SecureApplet applet, we must first compile the project to create the SecureApplet.class file, and then generate a CAB file from the SecureApplet.class file and sign the CAB file. From the Project menu, choose SecureApplet Properties. Select the Output Format tab. This page allows you to generate a number of different output format types for your applet in addition to the .class format. Select the Enable Packaging option, and then select CAB Archive (.CAB) from the Packaging Type drop-down list. Select These Outputs in the Package Contents section, and make sure that all of the necessary files are included in the CAB file. (The source .java and .htm files aren't necessary and increase load time.) The resulting Properties window appears in Figure 14-11.

Java Click to view at full size.

Screenshot-11. Generating a CAB file via the Output Format tab in the Project Properties window.

To sign this CAB file, choose the Advanced button on the Output Format tab. The Advanced Properties window is where you can enter your approved signature. This signature consists of two parts: the user-defined private key and the signature provider_generated certificate. I keep my signature files on a floppy disk. Figure 14-12 shows the entries I would use to sign the SecureApplet.cab file.

If you don't have a personal signature file, you can select the Use Test Certificate File button. Selecting this option will sign the applet with a test certificate that doesn't identify the user and that no self-respecting Web surfer would ever accept. (We'll see why later.) Choose OK to close the Advanced Properties window and choose OK again to close the SecureApplet Properties window.

Now rebuild the applet. You should notice that the Visual J Plus Plus v6 compiler goes through a couple of extra steps after compilation, called building and signing the CAB file. (You might not notice the Building CAB File step unless you watch the status bar carefully—the step notification goes by quickly.) Your directory should now have a SecureApplet.cab file in addition to the .class file.

Java Click to view at full size.

Screenshot-12. Signing an applet with my electronic signature, which I keep on a floppy disk.

HTML page

The HTML page for a signed applet is slightly different from a "normal" applet page. The following HTML page instructs the browser to download the SecureApplet.cab file from the server and then read SecureApplet.class from this file rather than directly from the server.

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<TITLE></TITLE>
</HEAD>
<BODY>
<HR>
<OBJECT code=SecureApplet.class HEIGHT=200 WIDTH=300 VIEWASTEXT>
 <PARAM NAME="cabbase" VALUE="SecureApplet.cab">
</OBJECT>
<HR>
</BODY>
</HTML>


Notice the extra parameter, cabbase. This command tells the browser to download the SecureApplet.cab file. Also, notice that the name of the CAB file is normally the same as the name of the project. In this case, it is also the same as the name of the .java and .class files, but that's not necessary.

result

Open the HTML file in Design mode. The dialog box generated by the test signature generates the rather dire warning shown in Figure 14-13. A real signature generates a similar dialog box except that it reassures the user that the signature is valid and identifies the signer. Either way, the decision whether or not to trust the applet is still left to the user.

Java Click to view at full size.

Screenshot-13. A warning dialog box asking the user whether or not he or she trusts the creator of the applet.

Screenshot-13 also notes that the applet is requesting Full Permissions. This means that the applet is asking to be able to do anything it wants. Our applet simply reads a file, but the user can't know that from this dialog box.

Because we wrote the applet, we know it's safe, so choose Yes to accept the signature. Switch to Quick View mode. Because the HTML file is a text file, enter SecureApplet.htm in the File Name field and click the Read Text button. You'll need to enter the full path to the file if you're running the applet outside the Visual J Plus Plus v6 IDE because the concept of a default client directory has no meaning in the context of a browser. The results should appear as shown in Figure 14-14.

Screenshot

Screenshot-14. SecureApplet applet displaying the contents of its own HTML file.

Signing an applet using permissions

Even though applet signing provides the user with some level of reassurance, there's still a problem. Once the user has given the applet full permissions, the applet is capable of doing anything it wants, from reading a file on the disk (as our applet does) to wiping out the hard drive. This level of permission seems a bit severe.

Internet Explorer 4 introduced a new security model: permission-based security. Under permission-based security, an applet can ask for just the permission it needs and no more. Thus, our applet could get by with read permission. A user would certainly feel more comfortable granting read permission than allowing the full permissions the applet requested under the simple trusted applet model.

To request file I/O permission, which includes both read and write capability, return to the Advanced page of the Project Properties Output Format tab. Now select the Java Permissions tab. Select Custom from the Permission Level drop-down list. Clear the Contains ActiveX Controls option, because our applet doesn't have ActiveX capability. Scroll down through the Permissions options if necessary, and click the File I/O option. Choose OK to close the Advanced Properties window and choose OK again to close the Project Properties window. Now rebuild the applet.

Running the applet again generates a dialog box like the one shown in Figure 14-15. (You might have to close and reopen the .htm file for the permission changes to take effect and this dialog box to appear.) Notice that this time the applet is asking only for File I/O Permission. Select Yes. The applet runs exactly as before.

Try repeating the process but signing the applet with some lesser permissions, such as Printing Permission; this time a similar dialog box appears, requesting print permission. Select Yes. The applet appears as before, but when you click the Read File button, the error message shown in Figure 14-16 appears, warning of a SecurityException because the applet didn't request the capability to perform file I/O. (This is the same error message you would see had you not signed the applet at all.)

Java Click to view at full size.

Screenshot-15. An applet asking only for the permissions that it needs.

Screenshot

Screenshot-16. The error message that appears when an applet with the wrong or insufficient privileges attempts to read from the disk.

Server-Side I/O

Although you might not immediately think about it, one aspect of reading and writing to the disk involves reading and writing to disk files on the server. The applet can read or write to a disk file contained on the computer from which the applet's .class file originated.

Java doesn't hinder this type of I/O in any way. After all, if you want to write an applet that wipes out your own hard drive, so be it. You as the programmer are precluded from damaging data on any server other than your home directory by the protection features built into all Web servers' operating systems. Allowing access to the server's files poses no threat to the client.

At first glance, access to server-side files might not seem all that useful; however, this type of access is what allows applets to read images and sound from the server for output to a browser. (We'll see how to read such images in .) In addition, you could build database files on the server. A program on the server could update this data regularly so that remote applets could read it. The data contained within these files could even be processed by the applet and then written back out to the server. This remote access approach would be very useful to businesspeople on the road.

problem

The ServerRead demonstration program is very simple. In this case, a fixed-named file, file.txt, is read from the current directory and displayed in a text area.

code

Begin by creating an empty project named ServerRead. To this project, add the class ServerRead and the HTML file ServerRead.htm.

Then edit the ServerRead.java file as follows:

import java.applet.Applet;
import java.awt.*;
import java.io.*;
import java.net.*;
/**
 * The following class reads a fixed file from the server.
 */
public class ServerRead extends Applet
{
 // create a fixed-size text area
 TextArea textArea = new TextArea(); public void init()
 {
 this.setLayout(new BorderLayout());
 this.add("Center", textArea);
 try
 {
 // read a file off the server
 // start by getting the name of the HTML file
 // (full path)
 String base = getDocumentBase().toExternalForm();
 // remove the trailing HTML filename
 int index = base.lastIndexOf("/") + 1;
 String path = base.substring(0, index);
 // create a URL by concatenating the
 // path to the fixed-file name "file.txt"
 String fileName = "file.txt";
 String totalName = path + fileName;
 URL url = new URL(totalName);
 // open an input stream on the URL
 InputStream connection = url.openStream();
 // now read the file
 int size = connection.available();
 byte[] block = new byte[size];
 connection.read(block);
 String s = new String(block);
 textArea.setText(s);
 }
 catch(Exception e)
 {
 textArea.setText(e.toString());
 }
 }
}


The applet begins by creating a display text area and attaching it to the center of the applet window. (If there are no other constraints, this will make the text area take up the entire applet window.)

The applet continues by retrieving the URL path of the HTML file that launched the applet. By searching for the "/" preceding the HTML name, the substring() statement effectively removes the HTML file name, leaving just the path. To this path, the program appends the fixed-file name file.txt.

The total name (including both path and file name) is used to create a URL object. This URL object represents a connection either to the local disk in the form of a file::// prefix or to a server in the form of an http:// prefix. The openStream() method opens an InputStream object, which can be used like any other input file stream.

The remaining statements simply read the contents of the file and display them in the text area window.

NOTE
Keep in mind that we couldn't have used this trick in the SecureApplet example because there's no equivalent to a default client directory when using a browser.

HTML file

The HTML file is completely conventional:

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<TITLE></TITLE>
</HEAD>
<BODY>
<HR>
<OBJECT CODE="ServerRead.class"
 HEIGHT=100
 WIDTH=300 VIEWASTEXT>
</OBJECT>
<HR>
</BODY>
</HTML>


result

The result appears in Figure 14-17 for the simple file.txt file containing "This is an experimental string." We didn't need to turn this .class file into a .CAB file (although it is allowed) or sign it to read the server file.

Screenshot

Screenshot-17. The resulting display from reading the file file.txt from the server. Comments