Проблемы с подписанным апплетом

Я разрабатываю приложение, которое будет выполнять шифрование / дешифрование только на стороне клиента. Я использую Spring, JDK 1.6+ и Eclipse. Я разработал апплет, который содержит криптографический код, который выглядит так:

public void accessToken(){
        try{
            File tmpConfigFile = File.createTempFile("pkcs11", "conf");
            tmpConfigFile.deleteOnExit();
            PrintWriter configWriter = new PrintWriter(new FileOutputStream(tmpConfigFile), true);
            configWriter.println("name=eToken");
            configWriter.println("library=" + "C:\\WINDOWS\\system32\\eTPKCS11.dll");
            configWriter.println("slotListIndex=0");
            configWriter.println("showInfo=true");

            this.pkcs11Provider = new SunPKCS11(tmpConfigFile.getAbsolutePath());
            Security.addProvider(this.pkcs11Provider);

            CallbackHandler cbh = new DialogCallbackHandler();
            KeyStore.Builder ksBuilder = KeyStore.Builder.newInstance("PKCS11", null, new KeyStore.CallbackHandlerProtection(cbh));                     
            KeyStore ks = ksBuilder.getKeyStore();
            ks.load(null, null);            
        }catch(Exception e){
            e.printStackTrace();
        }
    }

Я создал JAR-файл и подписал его, он работает хорошо, когда я запускаю его как "запустить на Java-апплете" на локальном компьютере из Eclipse, также он хорошо работает и запрашивает пароль при загрузке страницы, когда я открываю HTML-страницу, которая включает этот апплет, но когда Я нажимаю на флажок, который вызывает этот метод апплета accessToken(), который выдает ошибку на консоли Java, например:

java.lang.SecurityException: Unable to create temporary file
    at java.io.File.checkAndCreate(Unknown Source)
    at java.io.File.createTempFile(Unknown Source)
    at java.io.File.createTempFile(Unknown Source)
    at message.MessageApplet.accessToken(MessageApplet.java:49)
    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.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.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)

и моя HTML-страница выглядит так:

<SCRIPT LANGUAGE="JavaScript">
            function selectedCity() 
            {
                var elem = document.getElementById('cityRb');

                if(elem.checked)
                {
                    document.messageApplet.accessToken();
                }      
            }
        </SCRIPT></HEAD>
    <BODY >
        <b>This is the Applet</b>
     <script src="http://www.java.com/js/deployJava.js"></script>
    <script>
        <!-- applet id can be used to get a reference to the applet object -->
        var attributes = { id:'messageApplet', code:'message.MessageApplet',  width:1, height:1} ;
        var parameters = {jnlp_href: 'message-applet.jnlp'} ;
        deployJava.runApplet(attributes, parameters, '1.6');
    </script>

    <FORM NAME="CityChoice">
        <input type="radio" id="cityRb" name="City" value="Boston" onClick="selectedCity()"> Boston<br>
    </form>
</BODY > 

и мой файл JNLP выглядит так:

<jnlp spec="1.0+" codebase="" href="">
    <information>
        <title>Message Applet</title>
        <vendor>Fountainhead</vendor>
    <offline-allowed/>
    </information>
<update check="background"/>
    <security>
    <all-permissions/>
    </security>
    <resources>
        <!-- Application Resources -->
    <j2se version="1.6+"
              href="http://java.sun.com/products/autodl/j2se"/>
        <jar href="message.jar" main="true" />

    </resources>
    <applet-desc 
         name="Message Applet"
         main-class="message.MessageApplet"
         width="300"
         height="300">
     </applet-desc>
     <update check="background"/>
</jnlp>

все файлы и jar находятся в одном каталоге, а мой класс апплета находится в папке сообщений, пожалуйста, помогите мне, я застрял здесь...

4 ответа

Решение

Это произошло потому, что вы вызываете метод своего апплета из своего JavaScript. На самом деле, когда вы вызываете метод любого подписанного апплета из javascript, он ведет себя как неподписанный, потому что оба имеют собственную изолированную программную среду безопасности, и вы должны работать в этой конкретной изолированной программной среде. Теперь я внес изменения в ваш код, как показано ниже.

final File myFile = (File) AccessController.doPrivileged(new PrivilegedAction() {
                public Object run(){
                    String fileName = System.getProperty("user.home") +
                      System.getProperty("file.separator") +
                      "pkcs11.conf";                    
                    return new File(fileName);
                }});

этот AccessController позволит вам создать файл на клиентском компьютере. Я не очень хорошо говорю по-английски, поэтому, если будут какие-то ошибки, извините.

Если вы вызываете из (неподписанного) javascript функцию ВНУТРИ подписанного апплета, вы мгновенно сломаете подпись. Это означает, что апплет МГНОВЕННО теряет все привилегии и не сможет ничего записать на диск...

Посмотрите на это, внизу страницы: http://docs.oracle.com/javase/tutorial/deployment/applet/security.html

Примечание. Код JavaScript обрабатывается как неподписанный код. При доступе к подписанному апплету из кода JavaScript на HTML-странице апплет выполняется в изолированной программной среде безопасности. Это подразумевает, что подписанный апплет по существу ведет себя как неподписанный апплет.**

Поэтому вам, вероятно, придется запустить вашу функцию сразу после init(), а затем, через liveconnect, вызвать функции js на вашей странице ОТ апплета, уведомляющего о "завершении операции"...

Вы всегда можете передать данные апплету через Javascript для хранения их в объекте FIFO (первым пришел - первым обслужен) и использовать таймер в апплете для проверки FIFO и обработки запросов. Но я думаю, что возвращать значения кода ошибки / успеха будет нелегко...

Вам также нужен файл политики, чтобы разрешить подписанному апплету создавать временный файл.
Пожалуйста, добавьте номер строки в свой код, чтобы люди могли связать трассировку стека.

Я думаю, что вы код File.createTempFile("pkcs11", "conf"); бросает SecurityException, Видеть это message.MessageApplet.accessToken(MessageApplet.java:49) взяты из вашего стека трассировки.

Другие вопросы по тегам