RMI Аплети


Особености

В модела на сигурността в Java аплетите се считат за несигурен код изпълняват се в така наречената пясъчна кутия (sandbox)  и имат ограничена функционалност [ аплети и сигурност]:

    * Не могат да зареждат библиотеки и да дефинират "native" методи.    
    * Не могат да четат и пишат файловете на изпълняващата машина.    
    * Не могат да осъществяват мрежови връзки, с изключение към машината откъдето са взети.
    * Не могат да създават сокети.    
    * Не могат да стартират други програми.    
    * Нямат достъп до чувствителни характеристики на операционната система.    
    * Нямат достъп до локални устройства например принтери.



Има различни методи за да се осигури необходимата функционалност на аплетите, но най-просто е цифровото подписване на аплета и допускането му за изпълнение извън пясъчната кутия от потребителя.

Пример - аплет, който проверява и извежда текущото време на сървъра при всяко кликване с мишката върху аплета

1. Отдалечен интерфейс

public interface RemoteInterface extends java.rmi.Remote{
    public java.util.Date askTime() throws java.rmi.RemoteException;
}

2. Отдалечен обект

public class MyRemoteObject extends java.rmi.server.UnicastRemoteObject  implements RemoteInterface{
      public MyRemoteObject() throws java.rmi.RemoteException{
  }
  public java.util.Date askTime() throws java.rmi.RemoteException{
      System.out.println("RemoteObject.askTime called" + new java.util.Date() + "\n");
       return new java.util.Date();
  }
}


3. Сървър

public class Server{
  public static void main(String[] args){
    try{
      System.setProperty("java.security.policy","policy.txt");
      System.setSecurityManager(new java.rmi.RMISecurityManager());
      MyRemoteObject v=new MyRemoteObject();
      java.rmi.registry.LocateRegistry.createRegistry(5099);
      java.rmi.Naming.rebind("//:5099/count", v);
      System.out.println("Server started...");
    }catch(java.rmi.UnknownHostException x){x.printStackTrace();}
     catch(java.rmi.RemoteException x){x.printStackTrace();}
     catch(java.net.MalformedURLException x){x.printStackTrace();}
     catch(Exception x){x.printStackTrace();}
  }
}

Може да се провери регистрирания обект

import java.rmi.*;
import java.rmi.server.*;

public class ShowBindings{
   public static void main (String args[]){
      try{
         String[] bindings = Naming.list("rmi://"+args[0]+":"+args[1]);
         for (int i=0; i< bindings.length; i++)
            System.out.println(bindings[i]);
      }
      catch(IndexOutOfBoundsException ei){
         System.out.println("give the name of the server and the port number");
      } 
      catch(Exception e){
         e.printStackTrace();
      }
   }
}


4. Помощен клас

import java.awt.*;
public class Ball {
      int x,y;
     Color color;
     Ball(int startx, int starty, Color startColor) {
                x = startx;
                y = starty;
               color = startColor;
     }
     public void move(int newX, int newY) {
                x = newX;
                y = newY;
     }
      public boolean inside(int testX, int testY) {
                if (x - 10 < testX && x + 10 > testX && y - 10 < testY && y + 10 > testY) {
                        return true;
                }
                else {
                        return false;
                }
      }
      public void paint(Graphics g) {
                g.setColor(color);
                g.fillOval(x-10,y-10,20,20);
     }
}


5. Аплет

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class MyPanel extends java.applet.Applet implements MouseListener
{      
    Ball  one,two;
    int choice=1;
    RemoteInterface remoteClock=null;
    String host = "Unknown Host";
    public void init()
    {
        addMouseListener(this);
        one = new Ball(250,250,Color.red);
        two = new Ball(150,150, Color.blue);
        try{
            host = this.getCodeBase().getHost();
            System.out.println("Host is :"+host);
            remoteClock=(RemoteInterface)java.rmi.Naming.lookup("rmi://192.168.0.141:5099/count");
        }
        catch (Exception x){
            System.out.println("Exception!!"+x);
            x.printStackTrace();
        }
    } 
    public void paint(Graphics g)
    {
        g.drawString("server: "+host, 10, 10);
        one.paint(g);
        two.paint(g);
        try {
            g.drawString(""+remoteClock.askTime(), 100,30);
        }
        catch (Exception x){
            g.drawString("Exception!"+x,10,30);
            x.printStackTrace();
        }       
    }
    public void mousePressed(MouseEvent e)
    {
        int mouseX = e.getX();
        int mouseY = e.getY();
        if (one.inside(mouseX,mouseY)){
                         choice=1;
        }
        else if (two.inside(mouseX,mouseY)) {
            choice = 2;
        }
        else if (choice == 1) {
            one.move(mouseX,mouseY);
        }
        else if (choice == 2) {
            two.move(mouseX,mouseY);
        }
        repaint();
    }
    public void mouseClicked(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
}



втори вариант:

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class MyPanel extends java.applet.Applet implements MouseListener
{     
    Ball  one,two;
    int choice=1;
    RemoteInterface remoteClock=null;
    String host = "Unknown Host";
    TextField serv=new TextField("localhost",8),
    por=new TextField("5099",8);
    public void init()
    {
        addMouseListener(this);
        one = new Ball(250,250,Color.red);
        two = new Ball(150,150, Color.blue);
        add(serv); add(por);
        por.addActionListener(new getSrv());

    }
    class getSrv implements ActionListener{
        public void actionPerformed(ActionEvent e){
            host = serv.getText();
            try{
                int port = Integer.parseInt(por.getText());
                System.out.println("Host is :"+host);
                remoteClock=(RemoteInterface)java.rmi.Naming.lookup("rmi://"+host+":"+port+"/count");
            }
            catch (Exception x){
                System.out.println("Exception!!"+x);
                x.printStackTrace();
            }
            repaint();

        }
    }
    public void paint(Graphics g)
    {
        g.drawString("server: "+host, 10, 10);
        one.paint(g);
        two.paint(g);
        try {
            g.drawString(""+remoteClock.askTime("Pijo"), 100,30);
        }
        catch (Exception x){
            g.drawString("Exception!"+x,10,30);
            x.printStackTrace();
        }      
    }
    public void mousePressed(MouseEvent e)
    {
        int mouseX = e.getX();
        int mouseY = e.getY();
        if (one.inside(mouseX,mouseY)){
            choice=1;
        }
        else if (two.inside(mouseX,mouseY)) {
            choice = 2;
        }
        else if (choice == 1) {
            one.move(mouseX,mouseY);
        }
        else if (choice == 2) {
            two.move(mouseX,mouseY);
        }
        repaint();
    }
    public void mouseClicked(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
}

6. Компилиране на класовете

   javac *.java

7. Създаване на архив от класовете, които ще се прехвърлят при клиента

jar cvf MyPanel.jar MyPanel.class Ball.class RemoteInterface.class
added manifest
adding: MyPanel.class(in = 2532) (out= 1391)(deflated 45%)
adding: Ball.class(in = 745) (out= 469)(deflated 37%)
adding: RemoteInterface.class(in = 226) (out= 168)(deflated 25%)

8. Генериране на публичен и частен ключ [повече за keetool тук]

keytool -genkey -alias applet -keypass privatePass -keystore keystore.bin -storepass publicPass
What is your first and last name?
  [Unknown]:  Ivan Momtchev
What is the name of your organizational unit?
  [Unknown]:  teachers
What is the name of your organization?
  [Unknown]:  TU-Sofia
What is the name of your City or Locality?
  [Unknown]:  Sofia
What is the name of your State or Province?
  [Unknown]:  Sofia
What is the two-letter country code for this unit?
  [Unknown]:  bg
Is CN=Ivan Momtchev, OU=teachers, O=TU-Sofia, L=Sofia, ST=Sofia, C=bg correct?
  [no]:  yes


9. Подписване на архива

jarsigner -keystore keystore.bin -signedjar MyPanelSigned.jar MyPanel.jar applet
Enter Passphrase for keystore: publicPass
Enter key password for applet: privatePass

Warning:
The signer certificate will expire within six months.


10. Проверка на подписания архив

jarsigner -verify -verbose -certs MyPanelSigned.jar

         274 Thu Jun 07 22:19:10 EEST 2007 META-INF/MANIFEST.MF
         395 Thu Jun 07 22:19:12 EEST 2007 META-INF/APPLET.SF
        1043 Thu Jun 07 22:19:12 EEST 2007 META-INF/APPLET.DSA
           0 Thu Jun 07 22:13:48 EEST 2007 META-INF/
sm      2532 Thu Jun 07 13:44:18 EEST 2007 MyPanel.class

      X.509, CN=Ivan Momtchev, OU=teachers, O=TU-Sofia, L=Sofia, ST=Sofia, C=bg
      [certificate will expire on 07-9-5 13:49]

sm       745 Thu Jun 07 13:44:18 EEST 2007 Ball.class

      X.509, CN=Ivan Momtchev, OU=teachers, O=TU-Sofia, L=Sofia, ST=Sofia, C=bg
      [certificate will expire on 07-9-5 13:49]

sm       226 Thu Jun 07 13:44:18 EEST 2007 RemoteInterface.class

      X.509, CN=Ivan Momtchev, OU=teachers, O=TU-Sofia, L=Sofia, ST=Sofia, C=bg
      [certificate will expire on 07-9-5 13:49]


  s = signature was verified
  m = entry is listed in manifest
  k = at least one certificate was found in keystore
  i = at least one certificate was found in identity scope

jar verified.

Warning:
This jar contains entries whose signer certificate will expire within six months.



11. Създаване на html файла

<applet code=MyPanel.class archive=MyPanelSigned.jar width=900 height=300>The code </applet>


12. Стартиране rmi регистрите на сървъра

start rmiregistry


13. Задаване политика на сигурност на сървъра - файл policy.txt

grant {
  permission java.security.AllPermission;
};

14. Стартиране на програмата сървър

start java Server


               Проверка за изнесените обекти

import java.rmi.*;
import java.rmi.server.*;

public class ShowBindings{
   public static void main (String args[]){
      try{
         String[] bindings = Naming.list("rmi://"+args[0]+":"+args[1]);
         for (int i=0; i< bindings.length; i++)
            System.out.println(bindings[i]);
      }
      catch(IndexOutOfBoundsException ei){
         System.out.println("give the name of the server and the port number");
      } 
      catch(Exception e){
         e.printStackTrace();
      }
   }
}

15. Стартиране на web сървър и поставяне на html файла и архива на достъпно място

16. При стартирането от клиента трябва да се разреши работата на аплета извън пясъчната кутия: