3

我提到了一个小演示。在 为嵌入 HTML 的 Applet 设置策略中,一位冰茶 JRE 用户评论了该演示。对他们来说失败了。他们拒绝了对该小程序的许可(从而将其限制在沙盒中),并且应该看到绿色的“这个小程序是沙盒”页面。相反,小程序完全失败了,他们看到了小程序本应位于的“灰色空间”。

我在 WAGing 它试图实例化一个File不同的对象。IE Sun/Oracle JRE 将毫无问题地允许它,仅当小程序尝试创建JFileChooser. OTOH 冰茶 JRE 不允许 File创建。

因此,这段代码应该可以解决这个问题。它将 JEditorPane第一个“所有其他失败”消息的创建/添加和安装,然后是绿色的“沙盒”页面移动到new File(..)调用之前。

我的问题是。对于拥有冰茶 JRE 的用户,此代码是否“像广告宣传的那样工作”?

要测试它:

  1. 访问 pscode.org/test/docload/applet-latest.html上的小程序
  2. 拒绝数字签名的代码。 这对于创建合适的条件来测试小程序非常重要。
  3. 观察/报告小程序是否加载了绿色的 sandbox.html。沙盒文档将代表修复错误的“成功”。

同样令人感兴趣(可能很少)是 Demo of Defensive Loading of Trusted Applets的主页,它链接到 applet 页面、applet 中显示的每个 HTML 文件,以及包含源代码的 ZIP 存档的代码和 HTML,以及 Ant build.xml,这样您就可以“在家做这件事,孩子们”。

这是新代码。

package org.pscode.eg.docload;

import java.awt.BorderLayout;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JFileChooser;

import java.net.URL;
import java.net.MalformedURLException;

import java.io.File;
import java.io.IOException;

import java.security.AccessControlException;

/** An applet to display documents that are JEditorPane compatible.
This applet loads in a defensive way in terms of the security environment,
in case the user has refused to accept the digitally signed code. */
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);

        document = new JEditorPane("text/html",
            "<html><body><h1>Testing</h1><p>Testing security environment..");
        main.add( new JScrollPane(document), BorderLayout.CENTER );
        System.out.println("init(): entering 'try'");

        try {
            // set up the green 'sandboxed URL', as a precaution..
            URL sandboxed = new URL(getDocumentBase(), "sandbox.html");
            document.setPage( sandboxed );

            // 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.
            System.out.println("init(): instantiate file");
            File f = new File(".");
            System.out.println("init(): file instantiated, create file chooser");
            // 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);

            System.out.println(
                "init(): file chooser created, " +
                "create/add 'Load Document' button");
            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();
            document.setText( murle.toString() );
        } catch (IOException ioe) {
            ioe.printStackTrace();
            document.setText( ioe.toString() );
        } catch (AccessControlException ace) {
            ace.printStackTrace();
            // document should already be showing sandbox.html
        }
    }

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

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

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

2 回答 2

3

这是输出java.stderr(相当于Java控制台的一半 - 另一半是java.stdout,在您的情况下为空):

net.sourceforge.jnlp.LaunchException: Fatal: Initialization Error: Could not initialize applet.
        at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:604)
        at net.sourceforge.jnlp.Launcher.getApplet(Launcher.java:548)
        at net.sourceforge.jnlp.Launcher$TgThread.run(Launcher.java:729)
Caused by: net.sourceforge.jnlp.LaunchException: Fatal: Launch Error: Jars not verified.
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.checkTrustWithUser(JNLPClassLoader.java:467)
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.initializeResources(JNLPClassLoader.java:410)
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.<init>(JNLPClassLoader.java:168)
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:249)
        at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:575)
        ... 2 more
Caused by: 
net.sourceforge.jnlp.LaunchException: Fatal: Launch Error: Jars not verified.
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.checkTrustWithUser(JNLPClassLoader.java:467)
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.initializeResources(JNLPClassLoader.java:410)
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.<init>(JNLPClassLoader.java:168)
        at net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:249)
        at net.sourceforge.jnlp.Launcher.createApplet(Launcher.java:575)
        at net.sourceforge.jnlp.Launcher.getApplet(Launcher.java:548)
        at net.sourceforge.jnlp.Launcher$TgThread.run(Launcher.java:729)
java.lang.NullPointerException
        at net.sourceforge.jnlp.NetxPanel.runLoader(NetxPanel.java:99)
        at sun.applet.AppletPanel.run(AppletPanel.java:380)
        at java.lang.Thread.run(Thread.java:636)
java.lang.NullPointerException
        at sun.applet.AppletPanel.run(AppletPanel.java:430)
        at java.lang.Thread.run(Thread.java:636)
java.lang.Exception: Applet initialization timeout
        at sun.applet.PluginAppletViewer.handleMessage(PluginAppletViewer.java:637)
        at sun.applet.PluginStreamHandler.handleMessage(PluginStreamHandler.java:270)
        at sun.applet.PluginMessageHandlerWorker.run(PluginMessageHandlerWorker.java:82)
java.lang.RuntimeException: Failed to handle message: handle 60822154 for instance 2
        at sun.applet.PluginAppletViewer.handleMessage(PluginAppletViewer.java:660)
        at sun.applet.PluginStreamHandler.handleMessage(PluginStreamHandler.java:270)
        at sun.applet.PluginMessageHandlerWorker.run(PluginMessageHandlerWorker.java:82)
Caused by: java.lang.Exception: Applet initialization timeout
        at sun.applet.PluginAppletViewer.handleMessage(PluginAppletViewer.java:637)
        ... 2 more

因此,如果我在对话框中按取消,您的小程序代码似乎甚至没有加载。

确认对话框

我认为您在 Java 方面无能为力 - 也许使用另一个签名过程或通过 JNLP 启动小程序会有所帮助。或者在 IcedTea 上提交错误报告。


为了证明这一点,我创建了一个真正简单的小程序,省略了小程序中的所有关键内容:

package org.pscode.eg.docload;

import java.awt.FlowLayout;
import javax.swing.*;

public class Example extends JApplet {


    JLabel label;

    public void init()
    {
        System.out.println("init()");
        SwingUtilities.invokeLater(new Runnable(){public void run() {
            label = new JLabel("inited.");
            getContentPane().setLayout(new FlowLayout());
            getContentPane().add(label);
        }});
    }

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

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

    @Override
    public void destroy() {
        System.out.println("destroy()");
        label.setText("destroyed.");
    }
}

我编译了这个并修改了你的 HTML 文件来使用它,它给出了完全相同的症状。

似乎 IcedTea 重新定义了用户按下取消时的操作。公平地说,对话框中的按钮是“运行”和“取消”,而不是“以所有权限运行”和“沙盒运行”。

(在 Sun 的对话框中,有相同的按钮,但实际上它们的含义不是被问到的。)

于 2011-03-18T19:37:54.650 回答
1

作为参考,我可以在 Ubuntu 10.04 上使用 IcedTea 1.9.7 确认@Paŭlo Ebermann 的结果:

$ java -版本
java版本“1.6.0_20”
OpenJDK 运行时环境 (IcedTea6 1.9.7) (6b20-1.9.7-0ubuntu1~10.04.1)
OpenJDK Client VM(build 19.0-b09,混合模式,共享)

appletviewer显示预期的沙箱和流动的诊断输出。Ubuntu 上的 Firefox 仅提供Run(受信任)或Cancel(无)。

$ appletviewer http://pscode.org/test/docload/applet-latest.html
警告:无法读取 AppletViewer 属性文件:... 使用默认值。
在里面()
init(): 输入“尝试”
init():实例化文件
init():文件实例化,创建文件选择器
java.security.AccessControlException:访问被拒绝(java.util.PropertyPermission user.home 读取)
    在 java.security.AccessControlContext.checkPermission(AccessControlContext.java:393)
    在 java.security.AccessController.checkPermission(AccessController.java:553)
    在 java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
    在 java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1302)
    在 java.lang.System.getProperty(System.java:669)
    在 javax.swing.filechooser.FileSystemView.getHomeDirectory(FileSystemView.java:397)
    在 javax.swing.plaf.metal.MetalFileChooserUI.installComponents(MetalFileChooserUI.java:282)
    在 javax.swing.plaf.basic.BasicFileChooserUI.installUI(BasicFileChooserUI.java:153)
    在 javax.swing.plaf.metal.MetalFileChooserUI.installUI(MetalFileChooserUI.java:155)
    在 javax.swing.JComponent.setUI(JComponent.java:651)
    在 javax.swing.JFileChooser.updateUI(JFileChooser.java:1781)
    在 javax.swing.JFileChooser.setup(JFileChooser.java:374)
    在 javax.swing.JFileChooser.(JFileChooser.java:347)
    在 javax.swing.JFileChooser.(JFileChooser.java:330)
    在 org.pscode.eg.docload.DocumentLoader.init(DocumentLoader.java:57)
    在 sun.applet.AppletPanel.run(AppletPanel.java:436)
    在 java.lang.Thread.run(Thread.java:636)
开始()
停止()
破坏()

在 Mac OS X 上,Safari 5.05 产生了预期的结果;并appletviewer产生可比较但不相同的输出。

$ java -版本
java版本“1.6.0_24”
Java(TM) SE 运行时环境 (build 1.6.0_24-b07-334-9M3326)
Java HotSpot(TM) 64 位服务器 VM(内部版本 19.1-b02-334,混合模式)

$ appletviewer http://pscode.org/test/docload/applet-latest.html
在里面()
init(): 输入“尝试”
init():实例化文件
init():文件实例化,创建文件选择器
java.security.AccessControlException:访问被拒绝(java.io.FilePermission。读取)
    在 java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
    在 java.security.AccessController.checkPermission(AccessController.java:546)
    在 java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
    在 java.lang.SecurityManager.checkRead(SecurityManager.java:871)
    在 java.io.File.exists(File.java:731)
    在 javax.swing.JFileChooser.setCurrentDirectory(JFileChooser.java:548)
    在 javax.swing.JFileChooser.(JFileChooser.java:334)
    在 javax.swing.JFileChooser.(JFileChooser.java:316)
    在 org.pscode.eg.docload.DocumentLoader.init(DocumentLoader.java:57)
    在 sun.applet.AppletPanel.run(AppletPanel.java:424)
    在 java.lang.Thread.run(Thread.java:680)
开始()
停止()
破坏()
于 2011-04-22T08:25:14.477 回答