logo

Solution to Java Applet Puzzle

Here's the explanation and the solution to the Java applet issue I mentioned yesterday.

As you saw the page combined a Domino Java View applet and an ActionBar applet. They are two separate applets. They talk to each other using JavaScript. You can see how by looking at the source to the page.

Clicking the Refresh button on the applet calls this JavaScript function:

function Action1_onClick() {
 document.applets.view.refresh();
 return false;
}

That code is calling an exposed method of the View applet called "refresh()". And it's failing. Why?

Well, having isolated the issue to the Java code I needed to get to see the Java console in the hope that any errors were dumped there.

I'd previously told Java not to add an icon to the Task Tray in Windows. If you do see the Java icon down there you can right click it and choose "Show Console".

After some digging I found out how to get to see the Java console. All you do is go to the Control Panel, open the Java options from there and make sure the following options are selected:

image

Next time you open the webpage with the Applets you should see the console appear and start logging, like so:

image

If it appears but with less logging detail, focus on the console and press "5" to set the logging level to verbose and reload the page.

With the console on display I then pressed the Refresh button again and "thankfully" saw an error, as below:

network: Connecting http://www.codestore.net/apps/applets.nsf/view?ReadViewEntries&PreFormat&Start=2.1&Navigate=15&Count=40&SkipNavigate=32784&SkipCount=2 with proxy=DIRECT

An error occurred while reading in documents: java.security.AccessControlException: access denied (java.net.SocketPermission 63.254.226.99:80 connect,resolve)
java.security.AccessControlException: access denied (java.net.SocketPermission 63.254.226.99:80 connect,resolve)
                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.checkConnect(Unknown Source)
                at sun.plugin2.applet.Applet2SecurityManager.checkConnect(Unknown Source)
                at java.net.Socket.connect(Unknown Source)
                at sun.net.NetworkClient.doConnect(Unknown Source)
                at sun.net.www.http.HttpClient.openServer(Unknown Source)
                at sun.net.www.http.HttpClient.openServer(Unknown Source)
                at sun.net.www.http.HttpClient.<init>(Unknown Source)
                at sun.net.www.http.HttpClient.New(Unknown Source)
                at sun.net.www.http.HttpClient.New(Unknown Source)
                at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
                at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
                at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
                at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
                at lotus.notes.apps.viewpanel.ViewPanel.postUNIDList(Unknown Source)
                at lotus.notes.apps.viewpanel.ViewPanel.postUNIDList(Unknown Source)
                at lotus.notes.apps.viewpanel.ViewPanel.ReadAndParseViewEntries(Unknown Source)
                at lotus.notes.apps.viewpanel.ViewPanel.ReadLineRange(Unknown Source)
                at lotus.notes.apps.viewpanel.ViewPanel.refresh(Unknown Source)
                at lotus.notes.apps.viewpanel.ViewPanel.refresh(Unknown Source)
                at lotus.notes.apps.viewpanel.ViewPanel.deleteMarkedDocuments(Unknown Source)
                at lotus.notes.apps.viewapplet.ViewApplet.deleteMarkedDocuments(Unknown Source)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
                at java.lang.reflect.Method.invoke(Unknown Source)
                at sun.plugin.javascript.JSInvoke.invoke(Unknown Source)
                at sun.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
                at java.lang.reflect.Method.invoke(Unknown Source)
                at sun.plugin.javascript.JSClassLoader.invoke(Unknown Source)
                at sun.plugin2.liveconnect.JavaClass$MethodInfo.invoke(Unknown Source)
                at sun.plugin2.liveconnect.JavaClass$MemberBundle.invoke(Unknown Source)
                at sun.plugin2.liveconnect.JavaClass.invoke0(Unknown Source)
                at sun.plugin2.liveconnect.JavaClass.invoke(Unknown Source)
                at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$DefaultInvocationDelegate.invoke(Unknown Source)
                at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$3.run(Unknown Source)
                at java.security.AccessController.doPrivileged(Native Method)
                at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo.doObjectOp(Unknown Source)
                at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$LiveConnectWorker.run(Unknown Source)
                at java.lang.Thread.run(Unknown Source)

At this point I'd been trying all kinds of other approaches to debugging this and had spent hours on it. I've never been so grateful to see an error.

What I still didn't get was why the applet could load the view's content on the first page load - this was a major source of confusion.

Why was there an "access control" issue only when it reloads the view!?

After some searching and lots of reading (and lots of red herrings) I found out that since Java 6 reached "Update 22" a new security feature was implemented. The fix meant that any Java applet making a URL connection which was the result of being asked to do so by a JavaScript call had to do so with the same security settings/permissions as the JavaScript itself.

That's when the applet goes all paranoid! In doing so it wants to rule out the chance it's the target of cross-domain security breach.

But again, things are odd here. It's not cross domain. The applets are loaded from the same domain as the web page itself. As are the subsequent calls to the XML data via ?ReadViewEntries! Why does it think it's cross domain.

The next step and the eureka moment was in working out how the applet decides if it's cross domain or not.

It all comes down to whether or not a "reverse DNS lookups" of the resolved IP address points to the same domain name as shown in the address bar.

To work this out you first need to ping the domain in use, like so:

image

Then I pinged the resolved IP address directly while including the "-a" parameter (resolves addresses to hostnames) and you can see the result below:

image

Et voila! A reverse DNS lookup for codestore.net points to something completely different! That is why the Java applet breaks!!

To corroborate this I further tested in my own local network on my server called "dover" and resolvable in DNS both as dover and as dover.rockalldesign.com.

I then tried using the applets at the following URLs:

  1. http://dover/apps/applets.nsf/view
  2. http://dover.rockalldesign.com/apps/applets.nsf/view

The Refresh button worked on the first URL but not the second. Why? Consider the following:

image2

On my local network a Reverse DNS Lookup for "dover.rockalldesign.com" doesn't match the expected name of "dover", so the 2nd URL fails. But as you can infer from the above a reverse lookup for "dover" does returns a matching name, so the Java applet is happy to continue loading for the 1st URL.

Solution

The obvious solution would be to make sure you used a domain name in your URL with matches the one returned by a reverse lookup. In the actual customer's case this was a viable solution, as it is for my dover server. But not for the codestore.net version as the mcleodusa.net address it points back to can't be resolved in the address bar.

The alternative (and probably the better) solution is to add a cross-domain.xml file at the root of the HTTP server, so it would be accessible at http://www.codestore.net/cross-domain.xml. The content of the file is simply:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
 <allow-access-from domain="*"/>
</cross-domain-policy>

This will let you access the database using any domain / host which points to the server.

Summary

My customer's response was "Jake, you're a genius!". Well, as much as I'd love to agree, I wouldn't go quite that far. All I am is a patient nerd with enough experience of computers to know how to second guess them. Some times with problems like this it's down to a simple combination of experience and gut instinct.

The fact it's only going to affect users of the Domino View Java Applets made me wonder if it's even worth sharing this (who in their right mind still uses them?!). But then the fact I was asked and then paid to solve it in the first place means people obviously still must use them.

Comments

    • avatar
    • Giulio
    • Fri 4 May 2012 03:27 AM

    Certainly worthwhile from a JVM point of view. Too many little gotchas java that can cause bleeding knuckles.

  1. You well and truly earned your fee on that one. Well caught.

  2. Nice bit of detective work, Jake. There needs to be a trophy of some sort for debugging crap product code... like a golden plunger or something.

  3. Does <allow-access-from domain="*"/> leave the site vulnerable to cross-site exploits?

    This article recommends against such a permissive policy.

    http://curtismorley.com/2007/09/01/flash-flex-tutorial-how-to-create-a-crossdomainxml-file/

    It occurred to me that it would be easy for someone with malicious intent to scan domains looking for cross-domain.xml with this permissive setting for the purpose of targeting them specifically.

    Just some thoughts. I'm no expert on this.

      • avatar
      • Jake Howlett
      • Tue 8 May 2012 04:02 AM

      You're right. I should have mentioned that aspect of it.

      The thing is though, I couldn't get the Java fix to work by adding anything other than the wildcard entry in there. I tried lots of combination of domains, like so:

      <allow-access-from domain="dover.rockalldesign.com"/>

      But they all broke it.

      I'm not expert either and have to admit to getting a bit confused by it all. Even as far as I don't see the issue. By saying all domains can have access, surely that's just like saying it's a public URL in the first place. In most Domino cases it's an internal network and/or locked-down anyway.

      Whether you can get away with a * or not is probably down to each individual case.

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Fri 4 May 2012

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content