Detecting Privilege Denial at Startup

M. Gallant 08/18/2000

This page discusses approaches for detecting the situation in which a user declines to accept the privileges requested for running a digitally signed Java applet within Internet Explorer or Netscape Communicator using the browsers native JVM. Since the applet signing, archiving and security manager mechanisms are different for the two browsers, different approaches need to be considered. Combining this information with browser-detection scripting should provide sufficient information needed to code graceful recovery when a user refuses to grant privileges.

Warning: The procedures below depend on the specific error-messages generated by the browsers. They have only been tested on the following configurations:
Win95, WinNT4, Win2000     IE5.01, Netscape Communicator 4.73
Default browser settings are used. With IE, ensure that the Tools/Internet Options/Advanced are the default settings.

Typical "privilege request" dialogs are:
------ Netscape Communicator (4.73 Win95) ---------

------- Internet Explorer (5.01 Win95) -----------



Internet Explorer

The JScript object model for IE Java applets enables detecting privilege-grant status. This is only available after the page has fully loaded (and is therefore typically called with the onLoad() event handler).

------- Approach 1 for IE (Access Java applet object String representation -------
If privileges are NOT granted, IE reports an "ActiveX Control .." security error message (since scripted Java applets in IE are handled by ActiveX Control technology):

whenever the applet object is accessed as a whole from JScript. The string representation of the document.applets[0] object for privileges NOT granted looks like:

    [object] 
whereas, for the usual case where privileges *are* granted, the applet object representation contains useful information:
    classname[panel52,0,0,600,300,layout=java.awt.FlowLayout] 

Therefore, the following JavaScript code snippet, in an onLoad() handler function will detect the substring "layout", and presents the user with a supplementary dialog, or could also redirect the user to another page with further advice. [Note that only the .cab file and NOT the .class file should be in the deployment directory]:


<script language="JavaScript"> function checkappletload() { var appletobjstr = document.applets[0].toString(); // throws IE ActiveX error first. //alert(appletobjstr) ; if(appletobjstr.indexOf("layout")<0) { // if privileges NOT granted, this will be TRUE. var mess = "---- The Java applet didn't start properly -------\n" ; mess += " You must grant the requested privileges to run this applet. \n\n" ; mess += " To reload the applet, press Ctrl + F5 \n\n" mess += " ---- M. Gallant Security Development \n" ; alert(mess) ; // window.location = "advise_page.html" ; } } </script> <body onLoad="checkappletload()">
------- Approach 2 for IE (Access Java applet known method getCodeBase() ) -------
This approach does NOT cause the "ActiveX Control ... " message to appear. When the user does not grant privileges, accessing the document.applets[0].getCodeBase() method throws an IE script error:
"Object doesn't support this property or method"
and the cab file does not load.
[Note that for this method to work, ONLY the .cab file and NOT the .class file should be in the deployment directory.] This error can handled in two different ways:


<SCRIPT> window.onerror = trapError ; function trapError(sMsg, sUrl, sLine) { if(sMsg=="Object doesn't support this property or method") { // only IE responsds var mess = "---- The Java applet didn't start properly -------\n" ; mess += " You must grant the requested privileges to run this applet. \n\n" ; mess += " To reload the applet, press Ctrl + F5 \n\n" mess += " ---- M. Gallant Security Development \n" ; alert(mess) ; return true ; // handle if appropriate. } else return false ; } function checkappletload() { var appletobjstr = document.applets[0].getCodeBase(); // throws script error (method not supproted) if applet not loaded. } </SCRIPT> <body onLoad="checkappletload()">

The second approach, which is only valid for IE (since try/catch is not supported in Netscape 4.7 and lower, and cannot be caught as a JavaScript error):

<SCRIPT> function checkappletload() { try { var appletobjstr = document.applets[0].getCodeBase(); // throws script error (method not supproted) if applet not loaded. } catch(e) { errornum = e.number & 0xFFFF ; // error code is lower word. if(errornum==438) { // if "Object doesn't support this property or method" error ... var mess = "---- The Java applet didn't start properly -------\n" ; mess += " You must grant the requested privileges to run this applet. \n\n" ; mess += " To reload the applet, press Ctrl + F5 \n\n" mess += " ---- M. Gallant Security Development \n" ; alert(mess) ; } else throw e ; // don't handle other errors. } } </SCRIPT> <body onLoad="checkappletload()">
In practice, the browser could be detected at initial page loading, and IE-specific JavaScript could be loaded with: <SCRIPT SRC="iespecific.js"> </SCRIPT>

Netscape Communicator

If privileges are denied via Netscape, the onLoad() event handler for Netscape Communicator 4.7+ does NOT get called unless the ForbiddenTargetException is caught in the Java code. Security request calls in Netscape's object-signing technology are embedded in the actual Java code (unlike MS Authenticode technology). Therefore, if the user denies privileges, this can be caught within the Java code itself, using try/catch phrases. Combining this with defining a public method and private boolean status indicator enables scripted detection within Netscape Communicator of denied privileges. This would typically be implemented in the applet init() method: private boolean grantedprivileges = false; public void init() { try { PrivilegeManager.enablePrivilege("UniversalPropertyRead") ; grantedprivileges = true ; } catch (netscape.security.ForbiddenTargetException e) { System.out.println("Requested privileges were not granted by user."); return ; } catch(Exception cnfe) { System.out.println("netscape.security.PrivilegeManager class not found") ; } // remaining init code .. } public boolean hasPrivileges() { return grantedprivileges ; }
[Note to Developers: If you include the Netscape Capabilities classes into your win32 classpath environment (for compiling with Microsoft jvc.exe) , then IE may find the PrivilegeManager Netscape security classes and return prematurely in the catch clause; to cover this situation, the above code should test for the browser explicitly by using the java.vendor System properly. Another approach is to implement your own security APIs for both browsers with null bodies.]

If this approach for Netscape is implemented in the Java code, the following script will present the same JavaScript alert notification for IE or Netscape browsers when the user denies requested privileges. The script could also be broken up into two scripts, which would be conditionally loaded, depending on the browser:

<SCRIPT> var isNetscape = (navigator.appName=="Netscape") ; window.onerror = trapError ; function trapError(sMsg, sUrl, sLine) { if(sMsg=="Object doesn't support this property or method") { // error message for IE alertMessage() return true ; // handle if appropriate. } else if(sMsg.indexOf("Java object has no field or method")!=-1) { // for NN if method not defined return true ; // transparent handle. } else return false ; } function alertMessage() { var mess = "-------- The Java applet didn't start properly ---------\n" ; mess += " You must grant the requested privileges to run this applet. \n\n" ; mess += " To reload the applet\n"; mess += " Internet Explorer: press Ctrl + F5\n"; mess += " Netscape Communicator: press Reload\n\n"; mess += " M. Gallant 07/2000 \n" ; alert(mess) ; } function checkappletload() { var appletobjstr = document.applets[0].getCodeBase(); // throws IE script error (method not supported) if applet not loaded. if(isNetscape && !document.applets[0].hasPrivileges() ) // for Netscape; if not defined, error handler does nothing. alertMessage() ; } </SCRIPT>
[Note: If privileged Java calls are made directly from JavaScript using Netscape LiveConnect technology, the JavaScript itself must be signed. In this case, a user denying privileges generates a JavaScript ForbiddenTargetException error (similar to and related to the Java code exception above) that can be caught and handled using the onerror() event handler.]


Detecting root CA not installed

If the root CA certificate is not present in the Internet Explorer certificate database (actually in the registry), the end user still gets a security dialog permitting the end user to proceed, but warning that the code signature is not properly recognized. If the root CA certificate is not present in Netscape's certificate database (cert7.db file), Netscape Communicator will automatically not grant the privileges. This situation returns the same error message as if the end user had refused privileges in the security dialog if the root CA was present. The only way to detect the difference between an end user explicitly denying privileges and the absence of the root CA cert is to determine the time interval immediately before to immediately after the privilege request is made in the Java code. If LiveConnect code is used, the timing calculation is made in the JavaScript code just before the security call, and just inside the error-function handler. A security dialog window takes typically > 1.5 seconds to raise, and the end user response (to deny privileges) takes longer. The following code snippet has been tested on Win95 and WinNT on 200 MHz Pentium systems: function onerror(msg, URL, lineNum) { var timetoerror = (new Date()).getTime()-presecuritytime ; if(msg.indexOf("ForbiddenTargetException")>0) { // if Netscape security message if(timetoerror<500) alert("Please install the nortel PKI root CA certificate \n\n --- Time to error: " + timetoerror) ; else alert("You must grant the requested privileges in the dialog \n\n --- Time to error: " + timetoerror) ; return true; } else return false ; // pass up the handling chain if not Netscape error } // some other code here var presecuritytime = (new Date()).getTime() ; netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite'); References