Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Creating Signed, Persistent Java Applets


Feb99: Creating Signed, Persistent Java Applets

Paul is a senior architect for Digital Focus. He can be reached at [email protected]


Do you need to use Java for your organization's next intranet project? If so, you'll probably want to deploy your application in a browser. But what about the Java sandbox? Many enterprise applications need to save data to the local disk, connect to dedicated application servers, or even make native calls to legacy libraries. And what about the download time? A 3-MB applet won't make you popular among users waiting for downloads and it is never a good move to anger network administrators.

Luckily, Netscape and Microsoft have facilities for signed, persistent applet deployment that extends the Java security framework to address issues such as these. In this article, I'll show how to develop these applets for both Microsoft Internet Explorer 4.0 (IE4) and Netscape Navigator 4.0. The examples I present here (available electronically; see "Resource Center," page 5) revolve around an applet that writes text from a TextArea component to the local file system.

As you probably guessed, the procedures and resulting functionality differ slightly between Netscape and Microsoft. When you load a signed, persistent applet with IE4, you are prompted to acknowledge trust and grant specified privileges to the classes being installed. The privileges you request from users may be very granular; for example, the applet in Listing One asks for permission to write to a single file (output.txt) on the C: drive. Figure 1 shows the initial security warning dialog presented to users. Clicking on the Permissions hyperlink in the Security Warning dialog displays the specific privileges being requested. With a positive acknowledgment, the applet is granted the permissions and the user will not be prompted again. In this model, all permissions are granted up-front and the applet is installed and immediately off and running.

The Netscape model is a little more inconvenient for both users and developers. The archive installation is triggered by JavaScript, independent of any applet parameters. Redirecting users to an installation page, if necessary, is intuitive. The installation page contains JavaScript that installs the software. If the archive is updated on the client machine, users must restart the browser for the new archive to be loaded. Upon completion, users are instructed with a JavaScript alert message-box to return to the applet page after they restart the browser.

In contrast to IE4 where all permissions are acknowledged up-front, Netscape queries users as permissions are requested in the code and each time the applet is executed in a new instance of Netscape unless the user clicks a checkbox asking to "remember this decision." In short, for the example applet I present here, Netscape prompts users on four occasions for security acknowledgments, and requires a restart in the process.

  • The first dialog asks for permission to install the software.
  • The second dialog repetitively asks the user to install the software.
  • The third dialog asks the user to restart the browser.
  • The remaining dialogs ask for specific permissions requested in the code.

Obviously, it is ridiculous to prompt users so many times and then require a browser to restart. Hopefully, Netscape will address this soon.

The overall process for building an archive for the two browsers has similarities.

The high-level steps are:

  1. Add permission requests in your applet code.

  2. Create installation instructions.

  3. Build the archive.

  4. Sign the archive.

  5. Write HTML for the applet installation.

Step 1, adding permission requests, refers to IE4's Permission Model and Navigator's Capabilities API. The scoping rules for the two are different, but you can structure your code in a consistent manner to target both browsers. Basically, you enable permissions that are granted to a signed class just before you exercise a permission. To enable a permission in IE, call the com.ms.security.PolicyEngine to grant one or more of the 15 (FILEIO, THREAD, PRINTING, and so on) permission types. In Navigator, you call enablePrivilege in the netscape.security.PrivilegeManager class. Netscape defines a multitude of macro, primitive, and parameterized targets that enable a group of specific privileges. Notice how the permission calls in Listing One are surrounded by try/catch blocks so the same code can execute in either environment. Don't forget to add the IE and Navigator security classes to your classpath for compilation. For Navigator, add java40.jar from <Navigator_Program_Dir>\Java\Classes. Include <winnt _dir>\Java\Classes\classes .zip for IE.

Internet Explorer 4.0

Assuming you already have Internet Explorer 4.01 SP1, the first step is to obtain Microsoft's SDK for Java (http:// www.microsoft.com/java/sdk/). In addition to an updated Java VM, Microsoft's JDK equivalent tools, and documentation, you'll find three essential utilities in the <SDK-Java>\Bin\PackSign directory: PIniEdit, DUBuild, and SignCode.

You will also need a digital ID for Microsoft's Authenticode Technology. I picked up a personal software publisher ID from VeriSign (http://www .verisign.com/) for a $20.00 annual fee. The Certificate Authority will issue to you a Certificate (.spc) as well as a private key (.pvk).

Listing Two is a DOS batch file that automates the process of building the archive.

There are only three steps:

  1. Use DUBuild to create a Distribution Unit.

  2. SignCode to add your digital signature.

  3. SignCode again to timestamp the archive.

It seems simple, but there is a lot going on behind the scenes. Before you run the batch file, you must create signing directives with the Permission INI File Editor tool called "PIniEdit." With PIniEdit, you specify what sandbox liberties you require. For this example, I loaded HIGH permissions into PIniEdit, then specified write access to c:\output.txt (see Listing Three). These directives produce the standard sandbox limitations with the privilege to write to the specified local file.

In Listing Two, DUBuild is used to create an Open Software Distribution (OSD) and package it with the classes you specify into a cabinet archive (.cab). If you've made cabinets with IE3, DUBuild is similar to CABArc, but uses the OSD manifest instead of .inf files. It is important to note that DUBuild and Distribution Units are only used by Internet Explorer 4.0. This new Distribution Unit technology is powerful and complex. The key issue for Java deployment is the concept of the namespace. The namespace you specify is used by the Java Package Manager to create an application namespace layer above the namespace of packages and classes. With an application namespace, there is no concern about class name collisions with other software developers. This even applies to the classes in the anonymous (no package) namespace; but, you must place all anonymous classes in a directory called "default" for IE to find your classes. For the example presented here (available electronically; see "Resource Center," page 5), I placed the batch file in the MyApplet project directory and the MyApplet.class file in the default subdirectory. The next two SignCode commands in the batch file sign and timestamp the archive. You will want to consult the SDK documentation for details on the parameters.

Finally, you need to build the applet HTML (Listing Four). There are four applet parameters -- namespace, useslibrary, useslibrarycodebase, and useslibraryversion -- that direct IE to check for an installed Distribution Unit and download it if necessary.

Navigator 4.0

For Navigator, you will need a Netscape Object Signing digital ID (yes, another $20.00 to VeriSign) and Netscape's SignTool (formerly Zigbert; see http://developer .netscape.com/software/signedobj/jarpack .html). Your ID will automatically be loaded into Netscape's key database as part of the CA's issue procedure. I tend to wipe out configurations periodically, so I'm careful to export the key from Netscape right away.

As with IE, I built a DOS batch file (Listing Five) to automate the Navigator archive creation. In the batch file, you will notice references to inner and outer jars and corresponding subdirectories off of the base project directory. This structure parallels the archive that will be produced.

The outer jar contains JavaScript installation directives (Listing Six) and the inner jar. The inner jar contains the class files. Overall, JavaScript plays a critical role in Netscape's LiveUpdate technology. JavaScript in the applet HTML page immediately queries the Netscape Client Version Registry to see if an installation/update is needed and, if so, redirects users to an install HTML page. Following the JavaScript logic in the applet HTML page (Listing Four), the Netscape Client Version Registry is queried for a "java/download/ MyApplet" registry entry. The resulting version, if found, is compared to a hard-coded netscape .softupdate.VersionInfo JavaScript object. When redirected to the install HTML page, the ConditionSoftwareUpdate method of netscape .softupdate.Trigger is called to install or update the Java software. The install HTML page is linked to the outer jar, MyAppletInstall.jar, by the parameters to the ConditionalSoftwareUpdate method.

When the JavaScript triggers the update, the MyAppletInstall.jar is down- loaded to the client. Netscape opens this outer jar and processes the install script within it (Listing Six).

The install script creates and/or updates the entry in the Client Version Registry, places the inner jar in the specified location, and prompts users to restart the browser and reload the applet HTML page. I have skimmed over the details of the JavaScript objects, but you will want to review the documentation carefully to grasp the true power of LiveUpdate (http://developer.netscape .com/ docs/manuals/softdist.html).

Conclusion

Building signed and persistent applets is not a trivial procedure. However, the benefits warrant the extra effort. Given that Netscape or Internet Explorer are standard infrastructure software, they provide a convenient platform for deployment. So for now, we can deal with the complexity and redundant procedures, while waiting for the Java 1.2 Security Model.

DDJ

Listing One

import java.awt.*;import java.applet.*;
import java.io.*;


</p>
public class MyApplet extends Applet implements 
java.awt.event.ActionListener
{
    java.awt.Button button1;
    java.awt.TextArea textArea1;
    public void init()
    {
        setLayout(null);
        setSize(300,250);
        button1 = new java.awt.Button("Save");
        button1.setBounds(100,175,100,30);
        add(button1);
        textArea1 = new java.awt.TextArea();
        textArea1.setBounds(10,10,280,145);
        add(textArea1);
        textArea1.setText("What you type here will be written to\n" +
                          "c:\\output.txt when you press the button.");
        button1.addActionListener(this);
    }
    public void actionPerformed(java.awt.event.ActionEvent event)
    {
        Object object = event.getSource();
        if (object == button1)
        {
            try {
              try {
                if (Class.forName("com.ms.security.PolicyEngine")
                  != null) {
                     com.ms.security.PolicyEngine.assertPermission(
                                  com.ms.security.PermissionID.FILEIO);
                  }
              } catch (Throwable e) {}
              try {
                if (Class.forName("netscape.security.PrivilegeManager")
                 != null) {
                    netscape.security.PrivilegeManager.enablePrivilege(
                                  "UniversalFileWrite");
                }
              } catch (Throwable e) {}
              FileWriter f = new FileWriter("c:\\output.txt");
              f.write(textArea1.getText());
              f.close();
            } catch (Throwable e) {}
        }
    }
}


</p>

Back to Article

Listing Two

REM MakeCAB.bat

</p>
SET SDK_BIN=d:\SDK-Java.31\bin\PackSign
SET PATH_SAVE=%PATH%
SET PATH=%PATH%;%SDK_BIN%
SET FRIENDLY_NAME="MyApplet"
SET NAMESPACE="MyNameSpace"
SET VERSION="1,0,0,5"
SET CABFILE=MyApplet.cab
SET PINI=MyApplet.ini
SET CERT_FILE="a:\keys\brigner-msie.spc"
SET KEY_FILE="a:\keys\brigner-msie.pvk"
SET TIME_URL="http://timestamp.verisign.com/scripts/timstamp.dll"


</p>
pause "Copy your classes into the package or default directory"


</p>
REM build the archive
dubuild %CABFILE% . /I *.class /D %FRIENDLY_NAME% /N %NAMESPACE% /V %VERSION%


</p>
REM sign the archive
SET ARGS=-j JavaSign.dll
SET ARGS=%ARGS% -jp %PINI%
SET ARGS=%ARGS% -spc %CERT_FILE%
SET ARGS=%ARGS% -v %KEY_FILE%
SET ARGS=%ARGS% -n %FRIENDLY_NAME%
SET ARGS=%ARGS% %CABFILE%
signcode %ARGS%


</p>
REM timestamp the archive
signcode -x -t %TIME_URL%  -tr 5 %CABFILE%


</p>
REM drop the environment variables
SET ARGS=
SET PATH=%PATH_SAVE%
SET PATH_SAVE=
SET FRIENDLY_NAME=
SET NAMESPACE=
SET VERSION=
SET CABFILE=
SET CERT_FILE=
SET KEY_FILE=
SET TIME_URL=
SET SDK_BIN=
SET PINI=


</p>
pause "Finished!"


</p>

Back to Article

Listing Three

[com.ms.security.permissions.FileIOPermission]Version=2
IncludeRead=
ExcludeRead=
IncludeWrite=c:\output.txt
ExcludeWrite=
IncludeDelete=
ExcludeDelete=
ReadFileURLCodebase=true


</p>
[com.ms.security.permissions.NetIOPermission]
Version=2
IncludeConnectIPs=
ExcludeConnectIPs=
IncludeBindIPs=
ExcludeBindIPs=
IncludeMulticastIPs=
ExcludeMulticastIPs=
IncludeConnectHosts=
ExcludeConnectHosts=
IncludeBindHosts=
ExcludeBindHosts=
IncludeMulticastHosts=
ExcludeMulticastHosts=
IncludeConnectGlobalPorts=
ExcludeConnectGlobalPorts=
IncludeBindGlobalPorts=
ExcludeBindGlobalPorts=
ConnectToFileURLCodebase=false
ConnectToNonFileURLCodebase=true


</p>
[com.ms.security.permissions.UIPermission]
Version=2
ClipboardAccess=false
TopLevelWindows=true
NoWarningBanners=false
FileDialogs=false
EventQueueAccess=false


</p>
[com.ms.security.permissions.PropertyPermission]
Version=2
Unrestricted=false
AllowedSuffixes=applet
IncludedProperties=
ExcludedProperties=


</p>
[com.ms.security.permissions.ReflectionPermission]
Version=2
PublicSame=true
PublicDifferent=true
PublicSystem=true
DeclaredSame=true
DeclaredDifferent=false
DeclaredSystem=false


</p>
[com.ms.security.permissions.ThreadPermission]
Version=2
AllThreadGroups=false
AllThreads=false


</p>

Back to Article

Listing Four

<html><head>
<title>MyApplet</title>
</head>


</p>
<body>
<p><script LANGUAGE="JavaScript1.2">
<!--   Hide from other browsers
    if (navigator.appName == "Netscape") {
        ref = location.href.substring (0,
                    location.href.lastIndexOf("/") + 1)
      trigger = netscape.softupdate.Trigger
      version_no = new netscape.softupdate.VersionInfo(1,0,0,0)
    if (version_no.compareTo(
          trigger.GetVersionInfo("java/download/MyApplet")) > 0)  {
            location = ref + "MyAppletInstall.html"
    }
    }
// Stop hiding from other browsers -->
</script> 
<p align="center">
<applet code="MyApplet.class" width="300" height="250">
  <param name="namespace" value="MyNameSpace">
  <param name="useslibrary" value="MyApplet">
  <param name="useslibrarycodebase" value="MyApplet.cab">
  <param name="useslibraryversion" value="1,0,0,0">
</applet>
</body>
</html>


</p>

Back to Article

Listing Five

REM MakeJAR.bat

</p>
SET SDK_BIN=d:\Netscape\bin
SET PATH_SAVE=%PATH%
SET PATH=%PATH%;%SDK_BIN%
SET CERT_DIR="D:\nsprofile\paulb"
SET CERT="Paul Brigner's VeriSign Trust Network ID"
SET INNER_JAR=MyApplet.jar
SET OUTER_JAR=MyAppletInstall.jar
SET INNER_DIR=inner
SET OUTER_DIR=outer
SET INSTALL_SCRIPT=install.js


</p>
pause "Copy your class files into the 'INNER' directory."


</p>
REM sign and build the inner jar
signtool -d %CERT_DIR% -k %CERT% -Z %INNER_JAR% %INNER_DIR%


</p>
REM move the fresh inner JAR into the outer directory
del %OUTER_DIR%\%INNER_JAR%
move %INNER_JAR% %OUTER_DIR%


</p>
REM open notepad here to increment the version info number
pause "Check your version info."
notepad %OUTER_DIR%\%INSTALL_SCRIPT%


</p>
REM build and sign the outer jar. Specify the install script!
SET ARGS=-d %CERT_DIR%
SET ARGS=%ARGS% -k %CERT%
SET ARGS=%ARGS% -Z %OUTER_JAR%
SET ARGS=%ARGS% -i %INSTALL_SCRIPT%
SET ARGS=%ARGS% %OUTER_DIR%
Signtool %ARGS%


</p>
SET ARGS=
SET PATH=%PATH_SAVE%
SET PATH_SAVE=
SET CERT_DIR=
SET CERT=
SET INNER_JAR=
SET OUTER_JAR=
SET INNER_DIR=
SET OUTER_DIR=
SET INSTALL_SCRIPT=
pause "Finished!"


</p>

Back to Article

Listing Six

//Install.js// Make sure Java is enabled before doing anything else.
if ( navigator.javaEnabled() ) {
   // Create a version object and a software update object
   vi = new netscape.softupdate.VersionInfo(1, 0, 0, 0);
   su = new netscape.softupdate.SoftwareUpdate(this, "MyApplet");
   // Start the install process
   err = su.StartInstall("java/download/MyApplet", vi, 
      netscape.softupdate.SoftwareUpdate.LIMITED_INSTALL);
   if (err == 0) {
      // Find the Java download directory on the user's machine
      JavaFolder = su.GetFolder("Java Download");
      // Install the JAR archive. Unpack it and list where it goes
      err = su.AddSubcomponent("MyApplet", vi, "MyApplet.jar",
         JavaFolder, "", this.force);
   }
   // Unless there was a problem, move JAR archive to final location 
   // and update the Client Version Registry
   if (err != 0)
      su.AbortInstall();
   else {
      su.FinalizeInstall();
      alert("Restart your browser and return to this page.");
   }
}

Back to Article


Copyright © 1999, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.