3

I have designed an Applet to take a screenshot and save it on the users computer using the java.awt.Robot class. I need to embedd this applet into an html page (using the object tag) so that when the user clicks a button on the webpage the screenshot is taken.

The applet itself works fine, i've tested it by adding a temporary main method to it and running it on my local machine as a regular java app.

Where I'm having difficulty is setting up permissions to allow it to run from its embedded location. Obviously the robot class is somewhat hazardous so an AWTPermission needs to be established and the applet itself needs to be signed.

I followed through the tutorial at http://download.oracle.com/javase/tutorial/security/toolsign/index.html and succeeded in creating a signed .jar file and then a policy file that allowed the demo application in that tutorial to run. Where I am now running into issues is how to reconcile what I've learned with the situation my applet will be used in.

My target audience comprises around 100 machines and I need it to be executable on all of them. I have packed my java .class file into a .jar and signed it using keytool and jarsigner. I then uploaded the .jar and .cer files to the server directory where the pages in question are hosted.

However: When I then used policytool to create a new policy file on one of the machines to test the setup I am still unable to execute the applet from the HTML. I get Java.Security.AccessControlException Acess Denied java.awt.AWTPermission createRobot errors.

I rather suspect its the policy step that is going awry, so I'll outline the steps I took: I download the certificate to the local machine and generate a keystore from it, I launch 'policytool' from this directory through the commandline I add the directory on the local machine where the keystore generated from and my certificate is located. I then hit the add policy button and enter the SignedBy alias Then Add Permissions and select AWTPermission Targets name I select createRobot The function field I have been leaving blank as I cant think what would apply here Signed By in this window is also left blank I then hit 'OK' and 'Done' and get a warning that there is no public key for the alias I've entered in the first step. I do a 'save as' and save my policyfile to the same directory as I put the certificate and the keystore generated from it.

This is not allowing me to run the applet from the webpage however and my limited understanding of this aspect of programming offers no clues as to what has gone wrong.

Ideas, thoughts, observations? If I havent explicitly mentioned something then I havent done it. My biggest suspect is the warning I recieve but I cant seem to find why its appearing

EDIT: Forgot to mention a step. I manually added to my jre\lib\security\java.security file the line 'policy.url.3=file:/C:/Testing/debugpolicy' since thats the path and policy filename I created during the above steps. I also just now managed to remove the warning I mentioned earlier, I'd been mixing up my alias' and gave the alias for the private keystore rather than the public one during policyfile creation, however I still encounter the same problems

celem
  • 404
  • 3
  • 10

1 Answers1

7

If an applet is correctly signed, no policy file is required, nor is it required to separately upload any certificate. A correctly signed applet will prompt the user for permission when the applet is visited, before it loads. Does the prompt appear?

Here is a small demo. I wrote that demonstrates Defensive loading of trusted applets. That is the security prompt I am referring to.

If the applet is both digitally signed by the developer and trusted by the end user, it should be able to take a screen-shot.

There is one other thing you might try if the applet is trusted, just as an experiment (1). Early in the applet init(), call System.setSecurityManager(null). That will both test if the applet has trust, and wipe away the last remnants of the 'trusted' security manager given to applets.

And in the case that works, and it makes the screen capture successful, it suggests either a bug or Oracle changed their mind about the defaults of what a trusted applet could do.

1) Don't do this in a real world or production environment. To quote Tom Hawtin:

This question appears to have given some the impression that calling System.setSecurityManager(null); is okay. ... In case anyone has any doubts, changing global state in an applet will affect all applets in the same process. Clearing the security manager will allow any unsigned applet to do what it likes. Please don't sign code that plays with global state with a certificate you expect anyone to trust.


Edit 1: Here is the source of the simple applet used in that demo. For some reason when I originally uploaded it, I decided the source was not relevant. OTOH 3 people have now asked to see the source, for one reason or another. When I get a round tuit I'll upload the source to my site. In the mean time, I'll put it here.

package org.pscode.eg.docload;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.*;
import java.security.*;

/** An applet to display documents that are JEditorPane compatible. */
public class DocumentLoader extends JApplet {
    JEditorPane document;

    @Override
    public void init() {
        System.out.println("init()");

        JPanel main = new JPanel();
        main.setLayout( new BorderLayout() );
        getContentPane().add(main);
        try {
            // It might seem odd that a sandboxed applet can /instantiate/
            // a File object, but until it goes to do anything with it, the
            // JVM considers it 'OK'.  Until we go to do anything with a
            // 'File' object, it is really just a filename.
            File f = new File(".");

            // set up the green 'sandboxed page', as a precaution..
            URL sandboxed = new URL(getDocumentBase(), "sandbox.html");
            document = new JEditorPane(sandboxed);
            main.add( new JScrollPane(document), BorderLayout.CENTER );
            // Everything above here is possible for a sandboxed applet

            // *test* if this applet is sandboxed
            final JFileChooser jfc =
                new JFileChooser(f); // invokes security check
            jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
            jfc.setMultiSelectionEnabled(false);

            JButton button = new JButton("Load Document");
            button.addActionListener( new ActionListener(){
                    public void actionPerformed(ActionEvent ae) {
                        int result = jfc.showOpenDialog(
                            DocumentLoader.this);
                        if ( result==JFileChooser.APPROVE_OPTION ) {
                            File temp = jfc.getSelectedFile();
                            try {
                                URL page = temp.toURI().toURL();
                                document.setPage( page );
                            } catch(Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } );
            main.add( button, BorderLayout.SOUTH );

            // the applet is trusted, change to the red 'welcome page'
            URL trusted = new URL(getDocumentBase(), "trusted.html");
            document.setPage(trusted);
        } catch (MalformedURLException murle) {
            murle.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } catch (AccessControlException ace) {
            ace.printStackTrace();
        }
    }

    @Override
    public void start() {
        System.out.println("start()");
    }

    @Override
    public void stop() {
        System.out.println("stop()");
    }

    @Override
    public void destroy() {
        System.out.println("destroy()");
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • Do you have some code for your example applet? After clicking "Cancel" in the confirmation dialog, I see only a gray box (in Opera or Firefox, IcedTea plugin on Linux). The stderr says `net.sourceforge.jnlp.LaunchException: Fatal: Launch Error: Jars not verified`. – Paŭlo Ebermann Mar 15 '11 at 17:22
  • Ran your demo applet through safari on my 10.4.11 mac, applet worked fine when trusted otherwise got the green 'sandboxed' page. My object tag is in the head section of my html page, its init method sets the text inside its frame and that has all been displaying correctly when the page loads though im not prompted for trust. Its when I try and call its public method (which creates a Robot object) that I get the access denied exception. It would seem then that my problem lies in the digital signing somewhere, i'll have another look tommorow – celem Mar 15 '11 at 18:03
  • @Paŭlo Ebermann - see above. I just retested it here (FF/1.6.0_24) & it behaves as I expect (clicking 'OK' to give it trust). Could it be that your testing machine is configured to automatically reject unverified security certificates? It is self-signed. @celem Let us know how you go. – Andrew Thompson Mar 15 '11 at 20:31
  • Yes, I remember having seen this working when I saw this a some time ago in [another answer from you](http://superuser.com/questions/253884/java-applet-needs-permission-but-doesnt-ask-for-it) - but this may have been the Sun Plugin, now I'm on IcedTea (and can't change). When I accept, it works (shows red page), but if I press cancel in the confirmation dialog, I get the mentioned exception on stderr (while creating the applet class loader, from the stacktrace) and only a gray box. Maybe a IcedTea specific bug (non-feature), or the Sun Plugin does actually more than the specification says. – Paŭlo Ebermann Mar 15 '11 at 20:45
  • Maybe it is related to instantiating a File before setting up the JEditorPane & 'sand-boxed' document. If instantiating a File throws a security exception, the rest would fail. If I can get a (slightly altered) zip of the sources and build file up at my site, would you be willing to give it a run on the IcedTea box? BTW - my apologies for not responding to you on the linked question - now I have an RSS feeder, things should be more organized. – Andrew Thompson Mar 16 '11 at 04:01
  • 1
    @Paŭlo Also.. I just realized my first response to you on this thread was nonsense, since you specifically stated that the dialog was **refused.** :( – Andrew Thompson Mar 16 '11 at 04:16
  • 1
    Ran through my code again. Applet was correctly signed, hadnt been seeing trust prompts as entire server was 'always trusted'. Disabling this led to trust prompt on page load, however even when trusted, permission was refused. @Andrew Your System.setSecurityManager(null) fix did the trick, called from first line in init() led to proper functionality. Seems the AWTPermissions (screen shots, mouse/keyboard control) are an exception to the rule that trust = permission to run code. Many thanks guys – celem Mar 16 '11 at 10:27
  • @Andrew: Yeah, with Sun Plugin it works (green page), with IcedTea plugin not (gray box). – Paŭlo Ebermann Mar 16 '11 at 12:00
  • @Paŭlo I started a new thread on my demo. titled "Does this applet work in an Iced Tea JRE?" (http://stackoverflow.com/questions/5356850/does-this-applet-work-in-an-iced-tea-jre). Please drop by the thread, if you can find the time. – Andrew Thompson Mar 18 '11 at 19:25
  • 1
    This question appears to have given some the impression that calling `System.setSecurityManager(null);` is okay. I know Andrew knows this and the answer says "just as an experiment". In case anyone has any doubts, changing global state in an applet will affect all applets in the same process. Clearing the security manager will allow any unsigned applet to do what it likes. Please don't sign code that plays with global state with a certificate you expect anyone to trust. – Tom Hawtin - tackline Jul 22 '11 at 13:27
  • @Tom Good points. Since one person was confused by my comments, I decided to edit the question, and since you stated it well, I quoted your comment. Edit it out if you prefer, and I'll rephrase it in my own words. – Andrew Thompson Jul 22 '11 at 13:34
  • FYI: Since Java7 Update 21 with System.setSecurityManager(null); the applet won't start anymore. You have to sign the applet and use PrivilegedAction (http://stackoverflow.com/questions/3369365/what-permissions-must-be-granted-for-applets-to-write-temporary-files) – Christof Aenderl Apr 24 '13 at 09:26