I'd like to describe a recent discovery with regards to using JavaScript with Applets, and running into security problems. First, I'll give an overview of "The Applet Sandbox", and using JavaScript to call into an Applet.
The Sandbox
When developers are introduced to Java Applet technology, one of the first things they learn about is the Java Applet Sandbox. The sandbox refers to a set of security restrictions imposed on an Applet. The sandbox exists to prevent potentially dangerous code from being executed on a user's machine when they simply browse to a website.
Three of the basic restrictions are as follows:
- No access to the client's local file system.
- No network access to a remote system other than the Applet's host machine.
- No access to the client's printer.
There is a way to break out of the sandbox, via signing. A company can establish itself as a trusted vendor by purchasing certificates from a company like VeriSign. You can then "sign" your Applet and have the ability to do things such as read local files, and connect to an arbitrary URL. In order to write the most powerful Java Applets, this is the way to go.
Calling Applet methods via JavaScript
Since Applets are meant to be embedded in web pages, it would be nice to have your web page interact with your Applet. The way to do this is via JavaScript. Here's a really basic example.
Our Applet has one method, changeColor:
public class ColorApplet extends Applet
{
public void changeColor (String color)
{
if (color.equals("red"))
{
setBackground(Color.red);
}
else if (color.equals("blue"))
{
setBackground(Color.blue);
}
}
}
This is a pretty worthless Applet without some kind of external access into the changeColor method. Here's the HTML to call into the method:
<html>
<body>
<applet height="100" width="100" code="ColorApplet.class" name="ColorApplet"></applet>
<a onclick="javascript:ColorApplet.changeColor('red');" href="#">Red</a>
<a onclick="javascript:ColorApplet.changeColor('blue');" href="#">Blue</a>
</body>
</html>
By clicking on the "Red" and "Blue" Links in the html page, the Applet's background would change accordingly.
Using JavaScript to call restricted methods.
Changing colors in an Applet doesn't seem very useful. But lets say I have an Applet that can open up images from a file name or from a URL. The JavaScript hyperlinks can be used to open different files and URLs in the applet. I implemented a public method,
public void openFile (String filename)
This method will open up a local file or URL and display the image in the Applet. This works fine with any filename or URL since our Applet is signed. However, when I tried to call this method from an html page with JavaScript, I got the following error:
java.security.AccessControlException: access denied (java.io.FilePermission C:\images\img1.tif read)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkWrite(Unknown Source)
I was baffled. I retested openFile via my file menu, and the image opened up fine, so I knew I had signed the applet properly. I tested the JavaScript again and no luck. Hmm. Then I tried another JavaScript method that simply printed out some text to the console and that worked. Finally, I figured that there must be some additional security layer that prevents JavaScript from calling into the sandbox-restricted methods, even if the Applet is signed. After a quick Google search, I found some forum threads such as this one, which confirmed my suspicions. So what to do? I figured I would use the JavaScript method just to set some properties in the Applet. I would then create a separate thread that could be responsible for listening to changes in these fields, and calling the openFile method on behalf of the JavaScript. Here's how that worked. I made a new method called jsOpenFile, like this:
/**
* @param name
*/
public void jsOpenFile(String name)
{
gJavascriptFilename = name;
gJavascriptCalled = true;
}
Then I defined a thread in the init() method of my applet, like this:
Thread javascriptListener = new Thread()
{
public void run()
{
while (true)
{
if (gJavascriptCalled)
{
gJavascriptCalled = false;
openFile(gJavascriptFilename);
}
try
{
sleep(JAVA_SCRIPT_POLL_INTERVAL);
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}
};
javascriptListener.start();
Sure enough it works!
-Alex
Wow, complicated workaround ! (same as mine to indent code below ;-) )
just to inform you that it exist another way to do that quickly when surrounding the content of your method with java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
See example below:
_ public static void doSpecialWork(String param1) {
_ _ final String fParam1 = param1;
_ _ java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
_ _ _ public Object run() {
_ _ _ _ _ //Put the code of your method here
_ _ _ _ _ ...
_ _ _ _ _ ...
_ _ _ _ _ return "";
_ _ _ }
_ _ }
_ _ );
_ }
You only have to convert all method params into final (see fParam1).
No change in your javascript.
Regards,
SteF.
Stéphane Bury
Developper Analyst
IRIS S.A.
http://www.irislink.com
Posted by: Stéphane Bury | October 20, 2006 at 04:12 AM
Hi,
I have created an applet that does the functionality of connecting to remote host using SFTP. When i tried to launch my applet, exception "AccessControlException, access denied" is thrown. I have self signed my jar file. But still same problem persists. How do i solve this issue???
Posted by: Mohan Chandran | November 25, 2006 at 09:44 PM
Thank you so much for your workaround! It has worked for me, while the AccessController one couldn't...Don't know why. Anyway, the important thing is that it works and that my job is going on! :) THANK YOU!!! :)
Posted by: D0nVit0CF | November 27, 2007 at 12:04 PM
Hello,
thank you very very much for this example!!!
i have tried both examples...with one strange fact:
When i trigger the action for the first time it is pretty slow until i get a result back.
When i trigger the actions again it work as i would expected...so nearly realtime.
Is this problem familiar to someone?
If yes...any help is very much appreciated!
Kind regards,
Sebastian
Posted by: Sebastian Adolph | July 10, 2008 at 06:09 PM