简体   繁体   English

PrivilegedActionException试图从JavaScript调用签名的Java小程序

[英]PrivilegedActionException trying to invoke a signed Java applet from JavaScript

First off, I am not a Java developer. 首先,我不是Java开发人员。 I had to create a Java applet to invoke some code in a native DLL I wrote from the browser. 我必须创建一个Java applet来调用我从浏览器编写的本机DLL中的一些代码。

I use JNA to load a native DLL and invoke its methods. 我使用JNA加载本机DLL并调用其方法。
I have signed the applet using a self-signed certificate. 我使用自签名证书签署了applet。
The browser asks me whether or not to allow the execution of the applet. 浏览器询问我是否允许执行applet。
The applet code which loads my DLL is enclosed within AccessController.doPrivileged block. 加载我的DLL的applet代码包含在AccessController.doPrivileged块中。

Like this: 像这样:

public String Test()
{
    pHelper = AccessController.doPrivileged(new PrivilegedAction<IHelper>() 
    {
        @Override
        public IHelper run() 
        {
            return (IHelper)Native.loadLibrary("Helper", IHelper.class);
        }
    });

    return "test";
}

The code works fine when debugged inside Eclipse. 在Eclipse中调试时,代码工作正常。

It does not work when invoked from JavaScript. 从JavaScript调用时它不起作用。 Causes PrivilegedActionException. 导致PrivilegedActionException。

If I remove the entire AccessController.doPrivileged block and leave return "test" only, the code runs when invoked from JavaScript. 如果我删除整个AccessController.doPrivileged块并仅保留return "test" ,则代码在从JavaScript调用时运行。 Any code that doesn't require privileges runs fine when invoked from JavaScript. 从JavaScript调用时,任何不需要权限的代码都可以正常运行。

Tested from Chrome version 40.something and Firefox 36 on Windows 8.1 64-bit. 在Windows 8.1 64位上测试Chrome版本40.something和Firefox 36。 The native DLL is 32-bit as well as JRE used to run the applet. 本机DLL是32位以及用于运行applet的JRE。

Any tips? 有小费吗?

I have never resolved this particular mystery. 我从未解决过这个特殊的谜团。 However, I was able to find a workaround, thanks to my applet design specification which doesn't require exposing any applet methods which need to be invoked to perform privileged operations. 但是,由于我的applet设计规范不需要公开任何需要调用以执行特权操作的applet方法,我能够找到一种解决方法。

I have found that executing privileged operations inside the applet init() function will work. 我发现在applet init()函数中执行特权操作会起作用。 Only privileged operations executed by invoking from JavaScript seem to cause problems. 只有通过JavaScript调用执行的特权操作才会导致问题。 Consider the following code. 请考虑以下代码。

public class MyApplet extends JApplet {
    private IHelper pHelper = null;
    private MyReturnedInfo pInfo = null;

    public void init() {
        pHelper = (IHelper)Native.loadLibrary("Helper", IHelper.class);
        if (pHelper != null) {
            pInfo = pHelper.GetInfo();
        }
    }

    public String GetInfoString() {
        if (pInfo != null) {
            // need to call toString to convert from native wide char to something JavaScript will be able to interpret
            return pInfo.MyInfoString.toString(); 
        }
        return null;
    }
}

Upon loading this applet, calling document.myApplet.GetInfoString() from JavaScript (providing the applet has an ID "myApplet") will return the required information. 加载此applet后,从JavaScript调用document.myApplet.GetInfoString() (提供applet的ID为“myApplet”)将返回所需的信息。

Interestingly though, after signing the applet with a certificate issued by a trusted authority such as VeriSign, even this would not work in IE , while it would work properly in FF and Chrome. 有趣的是,在使用由VeriSign等受信任机构颁发的证书对applet进行签名之后, 即使这在IE中也不起作用,而在FF和Chrome中也能正常工作。 I have seen signed Java applets which work fine when called from JavaScript in IE, but I guess my applet is special because it requires all-permissions attribute in the manifest and IE probably doesn't like that. 我已经看到签名的Java小程序在IE中从JavaScript调用时工作正常,但我想我的小程序是特殊的,因为它需要清单中的all-permissions属性,IE可能不喜欢这样。 It's a guess. 这是猜测。 However, I have never found the real reason for that either, because I was able to resort to another workaround. 但是,我从来没有找到真正的原因,因为我能够采取另一种解决方法。 :) If you are reading this answer then I bet you are interested in it as well. :)如果你正在阅读这个答案,那么我打赌你也对它感兴趣。

Java applets allow us to provide additional parameters which we are able to obtain by calling this.getParameter() from inside the init() function. Java applet允许我们通过从init()函数内部调用this.getParameter()来提供我们能够获得的其他参数。 Also, if we allow the applet to call JavaScript functions from our HTML document by using mayscript attribute, we can easily combine these two facts to provide the JavaScript function for applet to call after the information from our native DLL has been obtained. 此外,如果我们允许applet通过使用mayscript属性从我们的HTML文档调用JavaScript函数,我们可以轻松地将这两个事实组合起来,以便在获取来自我们的本机DLL的信息之后为applet提供JavaScript函数。

Let's say that in our HTML, we define the JavaScript like this. 假设我们在HTML中定义了这样的JavaScript。

<script type="text/javascript" src="https://www.java.com/js/deployJava.js"></script>
<script type="text/javascript">
    var attributes = {
        id: "myApplet",
        name: "myApplet",
        code: "MyApplet.class",
        mayscript: "true",
        scriptable: "true",
        archive: "/path(s)/to/jar(s)",
        width: 0,
        height: 0
   };

    var params = {
        "AppletReady": "appletInitialized",
    };

    // For convenience, it's easier to deploy the applet using deployJava,
    // so it writes the applet HTML tag for us after checking if Java is installed.
    // We have included it above.
    deployJava.runApplet(attributes, params, "1.8.0");

    function appletInitialized(myString, someOtherArgument) {
        // do something with your parameters
        // NOTE: do NOT call alert() from this function! 
        // Because it will most likely cause your browser to freeze, 
        // I've found that's also one of the things Java doesn't like.
    };
</script>

Then, we modify the Java applet code to look like this. 然后,我们将Java applet代码修改为如下所示。

public class MyApplet extends JApplet {
    private IHelper pHelper = null;
    private MyReturnedInfo pInfo = null;

    public void init() {
        // Read the AppletReady parameter as passed from JavaScript
        String paramKey = "AppletReady";
        String jsLoadedCallback = this.getParameter(paramKey);

        // Load the library and get the information
        pHelper = (IHelper)Native.loadLibrary("Helper", IHelper.class);
        if (pHelper != null) {
            pInfo = pHelper.GetInfo();
            if (pInfo != null && jsLoadedCallback != null) {
                // Get the window which contains "this" applet
                JSObject jsObject = JSObject.getWindow(this);

                // Call the provided JavaScript function.
                // You can use as many parameters as you need.
                jsObject.call(jsLoadedCallback, new Object[] {
                        pInfo.MyInfoString.toString(),
                        pInfo.SomeOtherStringMaybe.toString()
                });
            }
        }
    }
}

However, if you need the applet to call your native DLL methods dynamically during runtime (IE you require the applet to expose functions which need to be called to perform privileged operations dynamically) this solution will not work for you and you are out of luck, at least if using JNA. 但是,如果您需要applet在运行时动态调用本机DLL方法(IE需要applet公开需要调用的函数来动态执行特权操作),这个解决方案对你不起作用,你运气不好,至少如果使用JNA。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM