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

Я разрабатываю приложение, которое будет выполнять шифрование/дешифрование только на стороне клиента. Я использую 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 находятся в одном каталоге, а мой класс апплета находится в папке сообщений, пожалуйста, помогите мне, я застрял здесь...


person Pravin    schedule 17.05.2012    source источник
comment
когда я нажимаю на флажок, который вызывает .. По 'флажку' DYM радио cityRb? 1) определение флажка в W3C больше похоже на <input type="checkbox" name="ny">New York 2) Если это так, вызов JS вызывает непосредственную проблему.   -  person Andrew Thompson    schedule 18.05.2012
comment
stackoverflow.com/questions/1006674/   -  person Martin Paljak    schedule 22.05.2012


Ответы (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 позволяет вам создать файл на клиентской машине. Я плохо говорю по-английски, поэтому, если есть какие-то ошибки, извините.

person Balasaheb    schedule 10.08.2012

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

Взгляните на это внизу страницы: http://docs.oracle.com/javase/tutorial/deployment/applet/security.html

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

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

person user1430808    schedule 01.06.2012

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

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

person rot    schedule 17.05.2012
comment
спасибо за повтор, да, вы правы, эта строка вызывает SecurityException. теперь у меня есть файл jnlp, в котором я упомянул ‹security› ‹all-permissions/› ‹/security›, но все же я сталкиваюсь с ошибкой. Должен ли я поместить его в свой подписанный файл jar, если да, то как указать его в моем файле JNLP? - person Pravin; 17.05.2012

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

person user2173353    schedule 05.04.2013