Implementing a simple RMI Application over the Internet

La page est créée Jocelyne Meunier
 
CONTINUER À LIRE
Implementing a simple RMI Application over the Internet
Implementing a simple RMI
 Application over the Internet
(using and comparing HTTP tunneling, RMI Proxy)

                                     Abstract
     Un problème se pose lorsque l’on veut effectuer des appels RMI à travers un
firewall, car souvent il empêche l’accès à certains ports pour cause de sécurité. Une
technique peut être le HTTP tunneling où les appels se font sous forme de requête
HTTP à l’aide d’une servlet. Une deuxième technique expliquée dans ce document
est le RMIProxy, dans laquel on place un proxy RMI pour chaque firewall, celui-ci
effectue un contrôle pour ne laisser passer que les requête RMI, il permet aussi
d’ajouter d’autres contraintes. Ce document permettra de se faire une idée sur ces
deux concepts permettant aux requêtes RMI de traverser des firewall.

                            Master Seminar
                  Advanced Software Engineering Topics
                      Prof. Jacques Pasquier-Rocha

          University of Fribourg, Switzerland
                         Departement of Informatics
                         Software Engineering Group

                           Author : Fabien Pochon
                           fabien.pochon@unifr.ch

                         Supervisor : Patrik Fuhrer
                          patrik.fuhrer@unifr.ch
                                Jun 12, 2003
Implementing a simple RMI Application over the Internet
Master Seminar                                                                         RMI Application over the Internet

                                       Table des matières
         1. Introduction....................................................................................... 3
         2. Problématique ................................................................................... 3
         3. HTTP Tunneling ............................................................................... 4
            3.1 Comment RMI « tunnelle » des messages.................................. 5
            3.2 Naming services and « the server machine ».............................. 6
            3.3 L’implémentation d’un servlet pour le HTTP tunneling ............ 7
               3.3.1 Le code du servlet ................................................................ 7
            3.4 Modifications à apporter afin d’utiliser le Tunneling ............... 12
            3.5 Désavantages du HTTP tunneling ............................................ 12
            3.6 Configuration du fichier policy................................................. 12
            3.7 Exemple d’appel RMI utilisant HTTP tunneling...................... 13
         4. RMIProxy ....................................................................................... 15
            4.1 Où trouve-t-on RMIProxy ........................................................ 15
            4.2 Les objectifs .............................................................................. 15
            4.3 Les caractéristiques................................................................... 15
            4.4 Le contrôle d’accès ................................................................... 16
            4.5 L’architecture............................................................................ 17
            4.6 Comment RMIProxy fonctionne............................................... 17
            4.7 L’API coté client....................................................................... 18
            4.8 L’API côté serveur.................................................................... 19
            4.9 Proxies multiple ........................................................................ 20
            4.10 Limitations du RMI Proxy ...................................................... 21
               4.10.1 Activation......................................................................... 21
               4.10.2 Stubs cachés ..................................................................... 21
               4.10.3 Socket Factories ............................................................... 21
               4.10.4 GetClientHost .................................................................. 21
               4.10.5 RMI / IIOP ....................................................................... 21
               4.10.6 Stubs distants indirectes................................................... 21
            4.11 Les modifications à apporter au client et au serveur............... 22
         5. Les différences entre RMI Proxy et HTTP tunneling..................... 23
         6. Conclusion ...................................................................................... 23
         Le RMI Proxy est certainement une méthode bien meilleur que le
         HTTP tunneling, car elle ne comporte que des avantages sur cette
         dernière. Malheureusement je n’ai pas testée. .................................... 23
         7. Annexes : Configurations ............................................................... 24
            7.1 Installation du seveur Apache................................................... 24
            7.2 Installation de Tomcat............................................................... 24
            7.3 Configuration du serveur Apache ............................................. 24
            7.4 Redirection du script CGI ......................................................... 26
         8. Bibliographie............................................................................... 27

                                                                                                                      2
Master Seminar                                                            RMI Application over the Internet

         1. Introduction
              RMI (Remote Method Invocation) est un système distribué, ce qui signifie que
         une ou plusieurs applications peuvent s’exécuter sur une ou plusieurs machines. Une
         caractéristique d’un système distribué est le besoin de collaboration entre les
         différents processus qui composent le système. Ce qui donne l’illusion à l’utilisateur
         qu’il utilise une application locale, alors que des invocations de méthodes se font
         dans un autre processus qui peut être sur une machine différente. Il y a donc un
         échange d’informations qui s’effectue entre plusieurs machines à l’aide du protocole
         RMI. Ceci peut s’effectuer sans aucun problème lorsque il n’y a aucun firewall entre
         les deux parties communiquant via RMI. Lorsque un firewall sépare le client d’un
         serveur il y aura certainement un problème. C’est ce problème et la solution pour le
         contourner qui va donc être traité plus en détail dans ce document.

         2. Problématique
             Le problème principal qui intervient lorsqu’un client veut effectuer un appel
         RMI sur une machine distante est effectivement le firewall qui peut y avoir entre les
         deux. En effet les firewalls interdisent souvent l’accès à certains ports spécialisés
         comme ceux qu’on désire utiliser lors d’un appel RMI.

             Les firewalls sont capables de filtrer des paquets selon :
             •    Leur adresse source
             •    Leur adresse de destination
             •    Le port de destination
             •    Le protocole de niveau supérieur (exemple : TCP, UDP) utilisé

              Cependant les firewalls sont généralement incapables de prendre des décisions
         en fonction des données contenues dans ces paquets. C’est pourquoi les techniques
         de tunneling, RMI Proxy ou encore d’autres peuvent être utilisées.

                                                                                                         3
Master Seminar                                                            RMI Application over the Internet

         3. HTTP Tunneling
             Le principe de base du http tunneling est d’utiliser comme protocole de
         communication des appelles http à travers le Web pour des application qui ne se font
         pas par le Web. Le requête originale émise n’est pas envoyé par un Web browser
         mais par une instance d’une URLClassLoader, et la réponse n’est pas une page html
         mais le code binaire d’une classe.
              HTTP tunneling est utilisé pour deux raisons essentielles, qui sont les deux très
         pragmatiques. Premièrement il permet au développeur d’applications d’utiliser les
         composants et l’infrastructure qui existe déjà pour les applications web, il est alors
         facile de définir un protocole utilisant ces composants.
              De plus il rend aussi facilement possible aux développeurs d’applications
         d’incorporer de multiples langages. Depuis que presque chaque langage moderne a
         sa librairie permettant de traiter et de générer du XML, utiliser HTTP et XML pour
         définir un protocole permet au client d’être écrit dans un langage et le serveur dans
         un autre.
             La seconde raison d’utiliser HTTP tunneling est qu’il est possible pour des
         applications distribuées d’éviter les firewalls. Pour comprendre pourquoi il suffit de
         regarger la figure 1.

                 Figure 1 : HTTP tunneling en action (tirée de O’Reilly, Java RMI)

              Le point clé dans cette architecture est que le client utilise une couche
         supplémentaire (marshalling layer) qui encode la requête du client en une requête
         HTTP valide. Le serveur de l’autre coté possède aussi une couche supplémentaire
         (layer of demarshalling code), laquelle transforme une requête HTTP en une requête
         correspondant à celle attendue par le serveur.
             Le HTTP tunneling est divisé en trois parties :

                                                                                                         4
Master Seminar                                                               RMI Application over the Internet

                      •   Le client :
                          Envoie une requête au serveur web
                      •   Le servlet :
                          Transmet la requête à la socket du serveur RMI en préservant la
                          structure HTTP qui a été envoyée par le client
                      •   Le serveur :
                          Transforme automatiquement l’envoi HTTP en une commande JRMP
                          (Java Remote Method Invocation)

         3.1 Comment RMI « tunnelle » des messages

             Maintenant le but du mécanisme de RMI HTTP tunneling devrait être clair : il
         encode un appel de méthode à distance à la façon d’une requête HTTP POST, et
         ensuite décode la « page web » retournée en une réponse du type approprié. RMI
         accomplit ceci de la même manière en utilisant un type élaboré de socket, dans
         laquelle une sérialisation est faite pour générer aussi bien les requêtes que les
         réponses HTTP.
              Bien qu’un différent mode de socket est utilisé, RMI va utiliser par défaut son
         propre mode de socket quand des connections seront créées. Les sockets par défauts
         retournées par RMI tentent d’utiliser HTTP tunneling si auparavant elles ont reçu
         une erreur du serveur. Les sockets par défaut emploient la stratégie suivante quand
         elles tentent une invocation de méthode sur un serveur :

                 1.   Tentent d’établir une connexion JRMP directe vers le serveur.
                 2.   Si la connexion échoue, elles tentent d’établir une connexion HTTP directe
                      avec le serveur. Ainsi elles créent une connexion par socket vers le port sur
                      lequel le serveur est en train d’écouter et ensuite communique en
                      encapsulant les méthodes demandées dans des requêtes HTTP. La première
                      chose que le « RMI demarshalling » effectue est de déterminer si la requête
                      a été encodée en utilisant JRMP ou HTTP.
                 3.   Si la requête échoue encore, elles tentent d’utiliser le firewall comme un
                      serveur proxy (demandant au firewall de transmettre la requête au port
                      approprié du serveur). Le firewall transmettra la requête comme une
                      requête HTTP (le firewall ne va pas traduire la requête en appel RMI).
                 4.   Si il y a encore un échec, elles tentent de se connecter sur le port 80 de la
                      machine serveur et lui envoie la requête selon un URL commençant avec
                      /cgi-bin/java-rmi.cgi. Cet URL signifie que la requête doit être transmise
                      vers un programme qui interprète les requêtes HTTP et qui la transmet,
                      comme une requête HTTP, vers le port approprié du serveur.

              Cette façon de communiquer peut paraître plutôt complexe. Ces points sont
         classés dans l’ordre décroissant de leur privilège. De plus ces points sont
         indépendants les uns des autres, il est possible d’imaginer un scénario pour lequel le
         quatrième point soit l’unique possibilité d’établir une communication.
              Par exemple supposons qu’un firewall ait été installé pour ne permettre
         qu’uniquement les connexions HTTP vers un serveur et qu’un serveur RMI soit
         derrière le firewall. Un client qui essaye de communiquer avec le serveur aura besoin

                                                                                                            5
Master Seminar                                                                RMI Application over the Internet

         d’utiliser une stratégie différente selon si il se trouve derrière le firewall (il se trouve
         dans un intranet) ou en dehors du firewall (il se situe n’importe où ailleurs sur
         l’Internet). Si il se trouve à l’intérieur du firewall, la première stratégie de connexion
         (direct JRMP) sera disponible et aura donc un sens.
              Si le client est à l’extérieur du firewall, il y aura deux options qui dépendront du
         « firewall policy » . Si le firewall permet les connexions HTTP sur n’importe quel
         port et n’insiste pas sur un trafic sur le port 80, la seconde option d’envoyer une
         information HTTP directement sur le port sur lequel le serveur écoute est plus
         efficace. Cependant si le firewall insiste sur le fait que tout trafic HTTP doit être
         envoyé sur le port 80, alors la quatrième option sera la seule façon d’établir une
         connexion.

         3.2 Naming services and « the server machine »

             Un point important, qui n’a pas encore été traité est que « la machine serveur »
         dans la quatrième option est une abstraction, elle n’est pas nécessairement sur la
         même machine que l’objet serveur actuel. C’est simplement un nom de machine
         stocké dans le stub.
             Ce niveau supplémentaire d’indirection permet au HTTP tunneling d’être
         implémenté de façon flexible. Prenons par exemples un firewall qui réduit toutes les
         connexions entrantes à être des requêtes HTTP sur le port 80. Si nous mettons le
         « naming service » à l’extérieur du firewall et la valeur du java.rmi.server.hostname
         prend le nom du server web, alors la quatrième option devra être utilisée. De cette
         façon, RMI tentera d’envoyer des messages à notre serveur en appelant un URL
         commançant par /cgi-bin/java-rmi.cgi.
             Ceci ne force pas le serveur RMI à fonctionner sur la même machine que le
         serveur web. Cela signifie simplement que nous avons besoin d’écrire une classe
         servlet qui effectue l’étape finale dans la redirection de la requête RMI et qui ensuite
         configure le serveur web afin qu’il envoye toutes les requêtes avec l’URL approprié
         au servlet.

                   Figure 2 : Le cheminement des messages (tirée de O’Reilly, Java RMI)

                                                                                                             6
Master Seminar                                                                  RMI Application over the Internet

            L’architecture résultante ressemble au diagramme de la figure 2. Les nombres
         montrent le cheminement des messages.

         3.3 L’implémentation d’un servlet pour le HTTP
         tunneling

              Pour le déroulement de la quatrième stratégie, il y a une manière de transmettre
         l’invocation de méthode au serveur RMI. La première implémentation de cette
         méthode que Sun Microsystems, Inc. développa était un script CGI. Les points
         suivants sont requis :

             •     Chaque invocation distante de méthodes est envoyée comme une requête
                   HTTP POST
             •     L’URL complet utilisé est de la forme /cgi-bin/java-rmi.cgi ?forward=[port
                   number]
             •     Le corps du POST contient toutes les données de la requête distante comme
                   un objet sérialisé qui est ensuite converti en une chaîne de caractères ASCII.

              Après que la spécification des servlets fut défini, Sun créa un servlet qui fournit
         les mêmes fonctionnalités que le script CGI.

         3.3.1 Le code du servlet

             Le code du servlet développé consiste en deux classes principales et en une liste
         de classes d’exceptions. Les deux classes principales sont SimplifiedServletHandler et
         ServletForwardCommand. Elles ont les rôles suivants :
         SimplifiedServletHandler :
         Cette classe étend HTTPServlet. Elles reçoit les requêtes et effectue un validation
         préliminaire.
         ServletForwardCommand :
         C’est une liste de méthodes statiques qui sait comment interpréter un HTTP POST et
         renvoyer ceci au serveur RMI qui tourne sur la même machine.

         Le code de SimplifiedServletHandler :

             public class SimplifiedServletHandler extends HttpServlet {

                 public void init(ServletConfig config) throws ServletException {
                   super.init(config);
                   System.out.println("Simplified RMI Servlet Handler loaded sucessfully.");
                 }

                 public void doPost(HttpServletRequest req, HttpServletResponse res)
                   throws ServletException, IOException {
                   try {
                      String queryString = req.getQueryString();
                      String command, param;

                                                                                                               7
Master Seminar                                                                      RMI Application over the Internet

                       int delim = queryString.indexOf("=");

                       if (delim == -1) {
                           command = queryString;
                           param = "";
                       } else {
                           command = queryString.substring(0, delim);
                           param = queryString.substring(delim + 1);
                       }

                        if (command.equalsIgnoreCase("forward")) {
                            try {
                               LoggingServletForwardCommand.execute(req, res, param);
                            } catch (ServletClientException e) {
                               returnClientError(res, "client error: " + e.getMessage());
                               e.printStackTrace();
                            } catch (ServletServerException e) {
                               returnServerError(res, "internal server error: " + e.getMessage());
                               e.printStackTrace();
                            }
                        } else {
                            returnClientError(res, "invalid command: " + command);
                        }
                     } catch (Exception e) {
                        returnServerError(res, "internal error: " + e.getMessage());
                        e.printStackTrace();
                     }
                 }

               public void doGet(HttpServletRequest req, HttpServletResponse res)
                 throws ServletException, IOException {
                 returnClientError(res, "GET Operation not supported: " + "Can only forward
         POST requests.");
               }

               public void doPut(HttpServletRequest req, HttpServletResponse res)
                 throws ServletException, IOException {
                 returnClientError(res, "PUT Operation not supported: " + "Can only forward
         POST requests.");
               }

                 public String getServletInfo() {
                   return "RMI Call Forwarding Servlet Servlet.\n";
                 }

                 private static void returnClientError(HttpServletResponse res, String message)
                   throws IOException {

                     res.sendError(HttpServletResponse.SC_BAD_REQUEST,
                       "" +
                       "Java RMI Client Error" +
                       "" +
                       "" +
                       "Java RMI Client Error" +
                       message +
                       "");

                     System.err.println(HttpServletResponse.SC_BAD_REQUEST +
                       "Java RMI Client Error" + message);
                 }

                 private static void returnServerError(HttpServletResponse res, String message)

                                                                                                                   8
Master Seminar                                                                   RMI Application over the Internet

                     throws IOException {

                     res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                       "" +
                       "Java RMI Server Error" +
                       "" +
                       "" +
                       "Java RMI Server Error" +
                       message +
                       "");

                     System.err.println(HttpServletResponse.SC_INTERNAL_SERVER_ERROR +
                       "Java RMI Server Error: " + message);
                 }

             }

              Presque tout du processus logique de SimplifiedServletHandler est contenu à
         l’intérieur de la méthode doPost(). La méthode doPost() parcourt l’URL pour
         déterminer le port sur lequel le serveur écoute. Si l’URL est un URL valide et
         contient le port, la requête est ensuite transmise à la méthode statique execute() du
         ServletForwardCommand .

         Le ServletForwardCommand comprends une série de méthodes statiques présentées
         ci-dessous :

              public class ServletForwardCommand {
                 public static void execute(HttpServletRequest request, HttpServletResponse response,
         String stringifiedPort)
                    throws ServletClientException, ServletServerException, IOException {
                    int port = convertStringToPort(stringifiedPort);
                    Socket connectionToLocalServer = null;

                     try {
                        connectionToLocalServer = connectToLocalServer(port);
                        forwardRequest(request, connectionToLocalServer);
                        forwardResponse(response, connectionToLocalServer);
                     } finally {
                        if (null != connectionToLocalServer) {
                            connectionToLocalServer.close();
                        }
                     }
                 }

                private static int convertStringToPort(String stringfiedPort) throws
         ServletClientException {
                   int returnValue;

                     try {
                         returnValue = Integer.parseInt(stringfiedPort);
                     } catch (NumberFormatException e) {
                         throw new ServletClientException("invalid port number: " + stringfiedPort);
                     }
                     if (returnValue  0xFFFF) {
                         throw new ServletClientException("invalid port: " + returnValue);
                     }
                     if (returnValue < 1024) {
                         throw new ServletClientException("permission denied for port: " + returnValue);

                                                                                                                9
Master Seminar                                                                   RMI Application over the Internet

                     }
                     return returnValue;
                 }

                 private static Socket connectToLocalServer(int port) throws ServletServerException {
                   Socket returnValue;

                     try {
                        returnValue = new Socket(InetAddress.getLocalHost(), port);
                     } catch (IOException e) {
                        throw new ServletServerException("could not connect to " + "local port");
                     }
                     return returnValue;
                 }

                private static void forwardRequest(HttpServletRequest request, Socket
         connectionToLocalServer)
                  throws IOException, ServletClientException, ServletServerException {
                  byte buffer[];
                  DataInputStream clientIn = new DataInputStream(request.getInputStream());

                     buffer = new byte[request.getContentLength()];
                     try {
                        clientIn.readFully(buffer);
                     } catch (EOFException e) {
                        throw new ServletClientException("unexpected EOF " + "reading request body");
                     } catch (IOException e) {
                        throw new ServletClientException("error reading request" + " body");
                     }

                     DataOutputStream socketOut = null;

                    // send to local server in HTTP
                    try {
                       socketOut = new
         DataOutputStream(connectionToLocalServer.getOutputStream());
                       socketOut.writeBytes("POST / HTTP/1.0\r\n");
                       socketOut.writeBytes("Content-length: " + request.getContentLength() +
         "\r\n\r\n");
                       socketOut.write(buffer);
                       socketOut.flush();
                    } catch (IOException e) {
                       throw new ServletServerException("error writing to server");
                    }
                 }

                private static void forwardResponse(HttpServletResponse response, Socket
         connectionToLocalServer)
                  throws IOException, ServletClientException, ServletServerException {
                  byte[] buffer;
                  DataInputStream socketIn;

                     try {
                        socketIn = new DataInputStream(connectionToLocalServer.getInputStream());
                     } catch (IOException e) {
                        throw new ServletServerException("error reading from " + "server");
                     }
                     String key = "Content-length:".toLowerCase();
                     boolean contentLengthFound = false;
                     String line;
                     int responseContentLength = -1;

                                                                                                               10
Master Seminar                                                                  RMI Application over the Internet

                  do {
                     try {
                         line = socketIn.readLine();
                     } catch (IOException e) {
                         throw new ServletServerException("error reading from server");
                     }
                     if (line == null) {
                         throw new ServletServerException("unexpected EOF reading server
         response");
                     }
                     if (line.toLowerCase().startsWith(key)) {
                         responseContentLength = Integer.parseInt(line.substring(key.length()).trim());
                         contentLengthFound = true;
                     }
                  }
                  while ((line.length() != 0) &&
                     (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));

                  if (!contentLengthFound || responseContentLength < 0)
                      throw new ServletServerException("missing or invalid content length in server
         response");
                  buffer = new byte[responseContentLength];
                  try {
                      socketIn.readFully(buffer);
                  } catch (EOFException e) {
                      throw new ServletServerException("unexpected EOF reading server response");
                  } catch (IOException e) {
                      throw new ServletServerException("error reading from server");
                  }

                     response.setStatus(HttpServletResponse.SC_OK);
                     response.setContentType("application/octet-stream");
                     response.setContentLength(buffer.length);

                     try {
                        OutputStream out = response.getOutputStream();

                        out.write(buffer);
                        out.flush();
                     } catch (IOException e) {
                        throw new ServletServerException("error writing response");
                     }
                 }
             }

              Il y a trois points importants à relever dans ServletForwardCommand.
         Premièrement, on utilise des sockets pour transmettre le corps du message HTTP au
         serveur RMI et ensuite des simples « pipes » que le serveur RMI retourne dans des
         sorties HttpServletResponse.
             Le second point important est que ServletForwarder transmet le message sans
         décoder les données ou comprendre le message. Même si le corps de la requête
         HTTP contient des instances de classes sérialisées, ServletForwarder n’a pas besoin
         d’avoir ces classes dans son classpath ou de traiter les instances sérialisées, il
         s’occupe simplement de copier des bytes d’un endroit vers un autre.

                                                                                                              11
Master Seminar                                                               RMI Application over the Internet

         3.4 Modifications à apporter afin d’utiliser le
         Tunneling

              La socket RMISocketFactory tentera par défaut automatiquement d’utiliser le
         HTTP tunneling quand les autres connexions auront échouées. Il n’y a pas besoin de
         changer ni le code du serveur ni le code du client, il suffit simplement d’ajouter un
         ligne dans le code du client afin qu’il puisse utiliser le HTTP tunneling. Cette ligne
         est la suivante :

             RMISocketFactory.setSocketFactory(
                new sun.rmi.transport.proxy.RMIHttpTOCGISocketFactory()) ;

         3.5 Désavantages du HTTP tunneling

              HTTP est souvent considéré comme une mauvaise idée à cause des quatres
         raisons suivantes :

                  •    Sécurité
                       Le HTTP tunneling évite délibérément un mécanisme de sécurité qui a
                       été mis en place par une autre personne qui le jugeait nécessaire.
                  •    L’inefficacité de la bande passante
                       RMI est déjà à la base un protocole gourmand, il encode beaucoup
                       d’informations dans chaque message de requête. Donc prendre le
                       message RMI et l’insérer dans un envoi HTTP utilisera une plus grande
                       largeur de bande.
                  •    L’inefficacité de la connexion
                       HTTP tunneling ne peut pas créer une connexion puis la laisser ouverte
                       et la réutiliser, il devra créer une nouvelle socket pour chaque requête
                       qu’il effectuera.
                  •    La fragilité de l’application
                       L’application entière est vulnérable à des changements dans la
                       configuration du firewall ou du la topologie du réseau.

         3.6 Configuration du fichier policy

              Chaque servlet est obligatoirement exécutée sous le contrôle d’un gestionnaire
         de sécurité (Security Manager). Celui-ci s’interpose entre la servlet et les ressources
         du système afin d’empêcher toutes tentatives d’accès illégales aux ressources du
         client. Les permissions d’accès sont définies par la politique de sécurité (Security
         Policy) installée sur le poste de travail. Lorsque aucune politique de sécurité n’est
         définie explicitement sur le client, le gestionnaire utilise alors la politique par défaut
         qui s’appelle le bac à sable (Sandbox). Le bac à sable interdit aux servlets tout accès
         (lecture et écriture) aux ressources de la machine locale.
             Quand une servlet tente d’accéder à une ressource du système, le gestionnaire de
         sécurité vérifie si le code exécuté a la permission d’accéder à cette ressource en

                                                                                                           12
Master Seminar                                                              RMI Application over the Internet

         consultant la politique de sécurité. Si la permission est accordée, tout se passe
         normalement. Dans le cas contraire, une exception est levée.
              Les fichiers « .policy » servent à paramétrer la politique de sécurité du système
         local. Un fichier « .policy » contient un ensemble de répertoires auxquels sont
         attribués individuellement un ensemble de permissions.
             Avant de lancer le serveur web il est important de noter que dans Java 2 (jdk1.2
         et versions ultérieures) les politiques de sécurité appliquées par la JVM ne
         permettent pas du téléchargement du code sans permission explicite. Pour cela nous
         avons besoin, du côté client comme du côté serveur d'un fichier de politique de
         sécurité qu'on nommera java.policy et contenant les lignes suivantes :

             permission java.net.SocketPermission "*:1024-65535","connect,accept";
             permission java.net.SocketPermission "*:80", "connect";

             Le fichier « .policy » utilisé pour pouvoir effectuer un HTTP tunneling doit
         contenir une ligne de plus chez le client afin de lui permettre l’utilisation de la
         « RMISocketFactory ». Cette ligne est la suivante :

             permission java.lang.RuntimePermission "setFactory";

         3.7 Exemple d’appel RMI utilisant HTTP tunneling

              Le serveur Apache, Tomcat et le serveur RMI tourne sur la même machine (ip :
         134.201.21.73) à l’intérieur du firewall. Afin de pouvoir effectuer un appel RMI à
         travers le firewall nous devons nous connecter au serveur Apache depuis une
         machine extérieur au firewall. Si l’on a à disposition uniquement une machine à
         l’intérieur du réseau local, on peut utiliser comme illustré dans la figure 3 un
         programme s’appelant VNC qui permet de prendre le contrôle d’une machine distante
         (dans ce cas nous prendrons le contrôle d’une machine à l’extérieur du firewall).

             Déroulement des étapes :
                  •   Le client fait un appel RMI au serveur sous forme de requête HTTP
                      grâce au socket factory utilisé. Un message de la forme /cgi-bin/java-
                      rmi.cgi?forward=[port number] sera envoyé au serveur Apache (dans le
                      cas présent le port 80 sera utilisé car c’est celui qui est à disposition par
                      le firewall).
                  •   Dans un premier temps une servlet (fonctionnant sur le serveur grâce à
                      Tomcat) contrôlera la syntaxe de ce message. Puis l’enverra sous forme
                      HTTP POST au serveur RMI.

                  •   Le serveur RMI la traitera et enverra au serveur Apache une réponse de
                      type HttpServletResponse.
                  •   Le servlet transmettra cette réponse au client sous la forme d’une
                      réponse HTTP à l’aide de la socket factory utilisée.

                                                                                                          13
Master Seminar                                                      RMI Application over the Internet

                 Figure 3 : Déroulement d’un appel RMI utilisant HTTP tunneling

                                                                                                  14
Master Seminar                                                            RMI Application over the Internet

         4. RMIProxy
              Une seconde technique permettant le passage des appels RMI à travers un
         firewall est la méthode RMIProxy. Dans cette technique le client doit être configuré
         afin de pouvoir utiliser des sockets qui traversent le firewall.

         4.1 Où trouve-t-on RMIProxy

             La version d’évaluation de RMIProxy peut être téléchargé sur le site
         www.rmiproxy.com.

         4.2 Les objectifs

             Les objectifs de RMI Proxy sont les suivants :

             1.   Eliminer les problèmes de sécurités de RMI à travers HTTP pour
                  l’administrateur réseau en fournissant des contrôles des exportations et des
                  importations des services RMI, via une application firewall qui ne supporte
                  uniquement le protocole RMI/JRMP. Aucune autre solution que RMIProxy
                  existe.
             2.   Fournir une grande réduction des overhead dans le passage à travers un
                  firewall comparé au HTTP tunneling.
             3.   Permettre un accès contrôlé vers le serveur RMI derrière le firewall.
                  Aucune autre solution que RMIProxy existe.
             4.   Permettre un accès contrôlé des appels du côté client derrière un firewall.
                  Aucune autre solution que RMIProxy existe.
             5.   Permettre au client RMI se trouvant derrière un firewall de contrôler l’accès
                  vers un serveur RMI de l’autre côté du firewall. Les seules solutions
                  existantes à ce problème sont les SOCKS et le HTTP tunneling.
             6.   Préserver toutes les propriétés de RMI.
             7.   Requérant un minimum de changement de code chez le client et le serveur
                  RMI.
             8.   Reprendre le maximum d’avantages existants dans les classes java, les
                  packages, et la configuration et les dispositifs de sécurité.

         4.3 Les caractéristiques

             RMI Proxy est une application Java et une API qui permet le contrôle de la
         pénétration dans un firewall en approuvant les clients et les serveurs RMI.

                                                                                                        15
Master Seminar                                                             RMI Application over the Internet

             RMI Proxy fournit un protocole RMI intermédiaire qui remplace RMI/HTTP
         tunneling, avec un haut degré de contrôle d’accès pour l’administrateur réseau.
             RMI Proxy est capable de :
             •    bloquer l’accès aux protocoles non-JRMP
             •    contrôler les écritures vers la RMI Proxy registry selon l’identification de
                  l’hôte client.
              • permettre ou refuser l’accès et l’exécution de méthodes distantes au client
                  RMI, selon l’identification de l’hôte client.
              • Permettre ou refuser le transfert de code par le service du codebase RMI,
                  dans les deux directions.
              RMI Proxy fournit donc une grande réduction des overhead par rapport au
         HTTP tunneling. La durée de la connexion TCP est identique à une connexion RMI
         directe. L’overhead découlant de tout RMI Proxy dans la chaîne de proxy est
         moindre qu’une indirection RMI supplémentaire par proxy.

             RMI Proxy supporte entièrement :

             •    Les firewalls coté client
             •    Les firewalls coté serveur
             •    Les appels du client derrière le firewall client

              RMI Proxy préserve toutes les propriétés de RMI excepté l’activation (les stubs
         activables sont séparés comme des stubs unicast), RMI/IIOP, et l’exactitude des
         valeurs retournées par le RemoteServer.getClientHost.
              L’utilisation de RMI Proxy nécessite uniquement un changement d’utilisation de
         la classe Naming en ProxyNaming, et modifier les propriétés du rmi.proxyHost chez
         le client, le serveur et les proxy intermédiaires.
              RMI Proxy utilise le mécanisme Java de security-policy existant pour contrôler
         la configuration, et utilise la java.rmi.AccessException existante pour le rapport des
         erreurs.
             RMI Proxy est une solution 100% Java.
             Les composants firewall RMI Proxy implémentent une RMI registry standard.

         4.4 Le contrôle d’accès

            Le contrôle d’accès est fournit par les fichiers Java policy, lesquels contrôlent la
         communication à travers les firewalls.
             Le contrôle d’accès s’effectuent selon l’adresse IP ou le nom d’un client voulant
         passé le firewall et selon l’action que celui-ci veut effectuer, à l’aide d’une classe
         spéciale FirewallPermission.
             Le contrôle d’accès est capable d’être contre les actions suivantes :

             •        L’accès à certains objets reçus ou envoyés implémentant l’interface
                      distant
             •        Bind, rebind ou unbind certains noms
             •        L’exécution de certaines méthodes distantes
             •        Chercher certains noms dans la proxy registry

                                                                                                         16
Master Seminar                                                            RMI Application over the Internet

         4.5 L’architecture
             RMI Proxy comprend les composants importants suivants :

                  1.   le programme RMI Proxy, lequel s’exécute dans les proxy machines
                       désignées
                  2.   la classe ProxyNaming, une classe Naming modifiée, appelée par les
                       clients et serveurs RMI.

             RMI Proxy comprend les sous-composants suivants :

                  1.   Le Proxy Registry : une RMI Registry normale qui est soumise aux
                       règles de contrôles d’accès fournis par l’implémentation du serveur
                       RMIProxy.
                  2.   Un protocole RMI qui négocie entre les flux descendants du serveur
                       RMI et les flux montants du client RMI, effectuant la validation du
                       protocole et le contrôle d’accès dans le processus.

              Le système compte sur deux faits élémentaires de RMI : une référence distante
         peut seulement être obtenue par un paramètre ou le résultat d’un appel de méthode
         distante, et la référence distante initiale est amorcée par un naming service (la RMI
         Registry).

         4.6 Comment RMIProxy fonctionne

             Un serveur RMI derrière un firewall utilise le plus proche RMI Proxy afin
         d’avoir son RMI Registry. Le coté extérieur du serveur RMI Proxy rend disponible
         un objet distant aux clients extérieurs.
              Pour le client RMI, une opération « lookup » sur un objet distant doit être
         dirigée vers le serveur proxy. Si le client est aussi lui-même derrière un firewall, le
         « lookup » est délégué à son RMI Proxy. La partie extérieure du proxy du client est
         capable de communiquer par RMI avec la partie extérieure du proxy serveur.
              Les proxies RMI servent d’intermédiaires entre les entrées vers le serveur et les
         sorties du client. Ils effectuent la validation du protocole RMI et transmet les appels
         RMI de l’un vers l’autre.

                                                                                                        17
Master Seminar                                                            RMI Application over the Internet

            Figure 4 : Exemple de configuration réseau RMI (tirée du guide de RMIProxy)

             Le RMI Proxy comprend trois composants :

             •    RMI proxy Registry
             •    un serveur RMI Proxying
             •    une API utilisée par les client et les serveurs

             Le RMI proxy Registry et les composants serveur sont installés en association
         avec chaque firewall qui existe entre le client RMI et le serveur RMI. Il peut y avoir
         un nombre quelconque de firewall. Chacun doit ouvrir son port au trafique RMI,
         lequel est ensuite manipulé d’un manière sécurisée par le RMI proxy associé.
              La propriété système rmi.proxyHost, placée sur chaque hôte impliqué, dicte s’il
         faut déléguer la requête du coté client (comme par exemple : lookup), ou s’il faut la
         propager à la registry du coté serveur (par exemple : bind ou rebind), vers le
         prochain RMI Proxy dans la chaîne. Chaque RMI proxy a le droit de restreindre
         l’accès à l’aide d’un fichier policy. Des Restrictions peuvent être imposées comme
         nous l’avons vu plus haut par l’adresse IP ou le nom de l’hôte, par le nom du service
         distant, ou par l’interface distant et les noms de méthodes.

         4.7 L’API coté client

            Quand un client RMI obtient une référence, il utilise normalement la méthode
         naming.lookup, avec un URL RMI de la forme :

             rmi://host/name

         où le host est le nom de l’hôte sur lequel la RMI Registry tourne, et le name est le
         nom de l’objet distant se trouvant dans la registry.

                                                                                                        18
Master Seminar                                                              RMI Application over the Internet

              Dans l’API de RMIProxy, le client utilise ProxyNaming à la place de Naming, Si
         un proxy est présent du coté client, les propriétés du système rmi.proxyHost
         spécifient son emplacement comme une URL RMI. Si cette propriété est présente, le
         client fonctionne dans un environnement RMI Proxy, donc le lookup est délégué au
         RMI Proxy, lequel est moins restrictif vers l’extérieur que le client original. Si ce
         Proxy fonctionne avec un autre Proxy le lookup est redélégué et ainsi de suite
         jusqu’au Proxy final atteint à l’extérieur du firewall coté client, à ce point le
         Naming.lookup standard est exécuté, comme si aucun Proxy n’avait été entre deux.
             Ce lookup, soit il réussi soit il échoue.
              Si il échoue, une exception RMI est propagé en retour vers le client original, et
         rien de remarquable se produit (l’objet distant n’a pas été trouvé).
              Si le lookup réussit, le stub obtenu (le flux descendant du stub) vérifie l’accès au
         RMI Proxy. Cela peut encore échouer avec une java.rmi.AccessException ;
         autrement un stub se référant à l’hôte RMI Proxy est retourné au client (le flux
         montant du stub). Le RMI Proxy maintient un lien entre le flux montant et
         descendant du stub, et transmet les appels RMI de l’un à l’autre, sujet du contrôle
         d’accès.
              Du point de vue du client, l’existence de RMI Proxy est invisible. Tout ce que le
         client sait, c’est qu’il a demandé un naming service (en utilisant ProxaNaming) pour
         une référence distante et qu’il la obtenu ; le référence distante est du type expected,
         et le travail de la référence est de communiquer avec l’objet distant.

         4.8 L’API côté serveur

              Un serveur RMI accessible par internet est lié avec la méthode
         ProxyNaming.bind à la place de Naming.bind ou Registry.bind, avec une URL RMI
         de la forme :

             rmi://host/name

         où host est le nom de l’hôte sur lequel tourne la RMI Registry, et name est le nom de
         l’objet distant dans cette registry.
             Avec les règles normales de RMI, un serveur RMI peut seulement être lié à un
         nom dans la RMI Registry par un processus tournant sur la même machine que la
         Registry. RMI Proxy modifie ces contraintes (le sujet du contrôle d’accès pour le
         proxy).
              Les propriétés système rmi.ProxHost nomment un hôte accessible où un RMI
         Proxy tourne. Si cette propriété est présente, la JVM tourne dans un environnement
         RMI Proxy, donc l’opération ProxyNaming.bind est exécutée en même temps dans la
         registry locale et dans le RMI Proxy. Si il y a un autre proxy pour ce proxy,
         l’opération est redéléguée et ainsi de suite jusqu’à ce que le proxy final soit atteint.
         Dans l’hôte original et dans chaque proxy incluant le dernier, le standard
         Naming.bind est exécuté par le ProxyNaming.bind. Ceci force le binding à se produire
         dans toutes les registry exécutées dans la chaîne des proxy.
             Le serveur est donc lié à la registry locale et aux registries de la chaîne des
         proxy. Une opération lookup de chaque proxy registries retourne un stub de flux
         montant se référant à un RMI Proxy, lequel transmet vers le stub de flux descendant
         après avoir effectué un contrôle d’accès, exactement comme dans le cas de l’API
         coté client, éventuellement en atteignant le serveur RMI original.

                                                                                                          19
Master Seminar                                                               RMI Application over the Internet

              A l’instar de l’appel Naming.unbind ou Registry.unbind, un proxied RMI serveur
         est délié par ProxyNaming.unbind. Cette action d’abord appelée Naming.unbind et
         ensuite délégué à la chaîne de proxy, entraîne unbinding de toutes les registries de la
         chaîne de proxy.
              De cette manière, chaque RMI serveur se lie vers une registry se trouvant
         dernière un ou plusieurs firewalls, et chaque serveur RMI accessible du serveur
         initial, sont rendus accessibles depuis internet, en étant rendus visibles par le plus
         proche RMI Proxy, et ainsi de suite récursivement.
              Un client RMI peut maintenant rechercher un serveur RMI à l’extérieur du
         proxy côté serveur et obtenir un stub de flux descendant lequel finalement il se
         réfère, en passant par une chaîne de RMI Proxies, vers un serveur à l’intérieur du
         firewall. Ce serveur n’est donc pas directement accessible par le client.

         4.9 Proxies multiple

              Si le client est derrière un ou plusieurs firewalls, ses propres RMI Proxies côté
         client feront leurs propre délégations, ainsi le client reçoit un stub qu’il peut utiliser.
         Le dernier stub de flux montant pointe à l’intérieur du proxy côté client, lequel
         pointe lui-même vers le suivant, lequel pointe éventuellement à l’extérieur du proxy
         côté serveur, lequel pointe à l’intérieur vers le suivant, lequel finalement point vers le
         serveur de flux descendant, comme illustré dans la figure 4.

          Figure 5 : multiples proxies côté client et serveur (tirée des « white paper » de
                                          RMIProxy)

                                                                                                           20
Master Seminar                                                             RMI Application over the Internet

         4.10 Limitations du RMI Proxy

         4.10.1 Activation

             RMI Proxy supporte l’activation RMI de façon limitée.
              L’implémentation actuelle réécrit les stubs activables comme des stubs unicasts
         normaux (UnicastRemoteObject). L’effet de ceci est que « l’activabilité » de l’objet
         est perdu après le passage dans le premier proxy de la chaîne sortant du serveur ;
         tous les clients de flux montant, incluant les autres chaînes de proxies du coté serveur
         et client et éventuellement le vrai client, sont retournés comme des stubs non-
         activables.

         4.10.2 Stubs cachés

              L’implémentation actuelle n’effectue pas d’arrangement proxying pour les stubs
         cachés (les stubs à l’intérieur de MarshalledObjects), c’est le but de la classe
         MarshalledObject pour rendre ses contenus invisibles aux programmes Java
         intermédiaires.

         4.10.3 Socket Factories

              Les socket factories ne sont actuellement pas supportées, principalement pour
         des raisons liées à la standardisation des numéros de port. Chaque nouvelle socket
         factory introduite dans une nouvelle RMI JVM requiert un nouveau numéro de port.
         Nous créons un plan pour supporter RMI/SSL par un numéro de port standard, ce qui
         résout de nombreux problèmes liés.
             Quand ce sera disponible, RMI Proxy pourra être intégré avec l’extension de
         sécurité RMI proposée par JDK 1.4.

         4.10.4 GetClientHost

              Le résultat retourné par RemoteServer.getClientHost est l’InetAddress du RMI
         Proxy le plus proche dans la chaîne de proxies, jamais le vrai client RMI. Pour cette
         raison l’hôte client validé par la firewallPermission peut être le RMI Proxy suivant
         plutôt que le vrai client.

         4.10.5 RMI / IIOP

              L’implémentation actuelle ne supporte pas les stubs RMI/IIOP. Avec une petite
         modification dans l’implémentation des classes stub javax.rmi.* ce problème peut
         être résolu.

         4.10.6 Stubs distants indirectes

                                                                                                         21
Master Seminar                                                             RMI Application over the Internet

              L’implémentation actuelle traite correctement les stubs distants lesquels sont
         accessibles par des paramètres ou des valeurs retournées. Ceci oblige de changer le
         RMIProxy avec une petite modification dans la classe sun.rmi.MarshalOutputStream.
         Ceci est requit uniquement chez le RMI Proxy mais pas dans l’API du serveur ou du
         client.

         4.11 Les modifications à apporter au client et au
         serveur

             Les points suivants sont nécessaires pour établir un RMI Proxying :

                 •    Modifier le code du client et du serveur pour qu’ils utilisent la classe
                      com.rmiproxy.ProxyNaming au lieu de java.rmi.Naming.
                      Exemple de code :
                         RemoteEcho echoObject =
                         (RemoteEcho)ProxyNaming.lookup(« rmi://rmi.server.com/ »+
                         RemoteEcho.class.getName()) ;
                 •    Définir correctement les propriétés du système rmi.proxyHost chez le
                      client, le serveur et chaque serveurs proxy afin que celle-ci contienne
                      l’URL du RMI Proxy le plus proche.
                      Exemple : Rmi.proxyHost=rmi://proxy.clientlan0.client.com
                 •    Configurer correctement le fichier policy chez le client et le serveur.
                 •    Installer, configurer et exécuter le programme RMI Proxy sur les
                      serveurs proxy.
                 •    Du coté serveur la classe com.rmiproxy.ProxyNaming doit être utilisée
                      à la place de la classe java.rmi.Naming.
                      Exemple de code :
                      ProxyNaming.bind(« rmi://localhost/ »+RemoteEcho.class.getName());

                                                                                                         22
Master Seminar                                                            RMI Application over the Internet

         5. Les différences entre RMI Proxy et HTTP
         tunneling

                      HTTP tunneling                             RMI Proxy
                      Il n’est pas très fiable. Si on            Plus robuste au changement
                 modifie le firewall il est possible que    du firewall.
                 le tunneling ne fonctionne plus.
                      Ces performances sont faibles.Il          Les requêtes sont des requêtes
                 encode beaucoup d’informations dans        RMI sans information
                 chaque message de requête. Il doit         supplémentaire.
                 créer une nouvelle socket pour chaque
                 requête qu’il effectue.
                      Il ne fonctionne pas à travers tous        Fonctionne avec tout type de
                 les types de firewall.                     firewall.
                      Inefficacité de la connexion, il ne        Connexion ne se referme pas
                 peut pas créer un connexion et la          après chaque requête.
                 laisser ouverte pour pouvoir la
                 réutiliser, il doit créer une nouvelle
                 socket pour chaque requête qu’il
                 effectue.

         6. Conclusion
             Le RMI Proxy est certainement une méthode bien meilleur que le HTTP
         tunneling, car elle ne comporte que des avantages sur cette dernière.
         Malheureusement je n’ai pas testée.
              La configuration de Apache afin qu’il supporte Tomcat et qu’il puisse utiliser
         une servlet à la place du fichier cgi-bin m’a pris énormément de temps, pour que je
         puisse finalement montrer un exemple utilisant le HTTP tunneling. L’emplacement
         des fichiers servlet dans le serveur n’est pas si évident non plus.
              Il est finalement intéressant de s’apercevoir qu’avec le HTTP tunneling il est
         possible de contourner une permission qui n’a volontairement pas été donnée par au
         firewall en « marshallisant » un requête et en l’a « démarshallisant » de l’autre coté
         du firewall.
             Même si j’ai trouvé un peu moins intéressant la technique du RMIProxy car elle
         ne contourne pas vraiment une interdiction que l’on a définit (elle laisse ouvert un
         port tout en contrôlant ce qui y passe), c’est une technique qui me paraît comme
         expliquée dans ce document plus stable et plus robuste que le HTTP tunneling.

                                                                                                        23
Master Seminar                                                             RMI Application over the Internet

             7. Annexes : Configurations

         7.1 Installation du seveur Apache

              Il suffit simplement de télécharger le fichier binaire Win32 apache_1.3.27-
         win32-x86-no_src.msi à l’adresse http://httpd.apache.org/download.cgi. Puis lancer
         ce fichier en double cliquant dessus et l’installation commencera.

         7.2 Installation de Tomcat
              Télécharger       le     fichier      jakarta-tomcat-4.0.6.exe      à     l’adresse
         http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.0.6/bin/ , puis exécuter
         l’installation en double-cliquant sur ce fichier.

         7.3 Configuration du serveur Apache

             Tomcat doit être intégré à Apache afin de pouvoir interpréter les servlets qui
         sont nécessaire au HTTP tunneling. Pour mettre en oeuvre une telle architecture, il
         faudra donc disposer d'un serveur Apache "up and running" et de Tomcat.
              Pour vérifier que Tomcat est convenablement installé, ouvrez votre navigateur et
         saisissez comme URL http://nomduserveur:8080/. Essayez de naviguer dans la
         section "Web Applications" et testez les exemples "Servlet" et "JSP". En cas de
         problème, vous pouvez consulter les journaux de Tomcat dans le sous-répertoire logs
         de Tomcat.
             L'intégration de Tomcat et d'Apache se fait par l'intermédiaire du module
         mod_webapp.
         Assurez-vous tout d'abord de disposer d'une installation fonctionnelle d'Apache.
         Ouvrer votre navigateur et à l’adresse http://nomduserveur la page principale
         d’apache doit apparaître. Télécharger ensuite mod_webapp à l'URL suivante :
             http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.0.1/
         bin/win32/webapp-module-1.0-tc40-windows.zip.

         Décompactez le contenu de l'archive téléchargée dans le sous-répertoire modules
         d'Apache.
            Editez le fichier httpd.conf et, dans la section 1, dans la partie relative aux
         modules, ajoutez la ligne suivante après toute autre concernant le chargement de
         modules optionnels :
             LoadModule webapp_module modules/mod_webapp.so

             Ajoutez ensuite les lignes suivantes juste avant la section trois (consacrée aux
         hôtes virtuels) :

                                                                                                         24
Master Seminar                                                             RMI Application over the Internet

             # Tomcat

             WebAppConnection warpConnection warp localhost:8008
             WebAppDeploy examples warpConnection /examples/
             WebAppInfo /webapp-info

         Voici une description des directives utilisées :
             WebAppConnection warpConnection warp localhost:8008

         Indique à Apache d'établir une connexion avec Tomcat par l'intermédiaire d'un
         processus spécifique, Warp, écoutant sur le port 8008. Un bref aperçu de la directive
         ci-dessus :

             WebAppConnection [connection name] [provider] [host:port]

             [connection name]
             Un nom qui va être utilisé pour décrire la connexion entre Apache et Tomcat.

             [provider]
             Le nom du fournisseur de service permettant de se connecter à Tomcat.
             Actuellement, seul le mot-clé "warp" est utilisable.

             [host:port]
             Le couple nom d'hôte:port décrivant le nom du serveur Tomcat et le port utilisé
             pour se connecter au fournisseur de service décrit ci-dessus. Il faut remplacer
             localhost par le nom du serveur Tomcat si Apache et Tomcat ne sont pas sur la
             même machine.
              Le port utilisé pour la connexion entre Apache et Tomcat est défini dans le
         fichier server.xml, dans la section "org.apache.catalina.connectors.warp.WarpConnector",
         pas la section HTTP. Ce fichier peut être trouvé dans le sous-répertoire conf de
         Tomcat.
             WebAppDeploy examples warpConnection /examples/

             Cette directive indique de "déployer", c'est-à-dire mettre à disposition une
         application Web. Dans le cas présent, nous déployons une application nommée
         "examples" (à laquelle correspond un sous-répertoire examples dans le répertoire
         webapps de Tomcat), accédée par Apache au travers de la connexion
         "warpConnection" et disponible pour l'utilisateur à l'URL "/examples/".

         Voici le détail de la directive ci-dessus :
             WebAppDeploy [application name] [connection name] [url path]

             [application name]
             Le nom de l'application Web correspondant à un répertoire dans le sous-
             répertoire webapps de Tomcat. Celui-ci contient une structure complète
             décrivant l'application. Si l'application se présente sous la forme de fichier
             portant l'extension "war", il convient de spécifier le nom du fichier, par exemple
             "monApplication.war".
             [connection name]
             Le nom de connexion précédemment déclarée au niveau de la directive
             WebAppConnection.

                                                                                                         25
Master Seminar                                                             RMI Application over the Internet

             [url path]
             L'URL par laquelle l'application Web sera joignable.

              La directive "WebAppDeploy" est liée à la déclaration d'un hôte. Ainsi, si une
         directive "WebAppDeploy" se trouve déclarée au niveau d'une section , l'application
         Web ne sera disponible que pour cet hôte virtuel.

         WebAppInfo /webapp-info

             Cette dernière directive permet de connaître le statut de toutes les connexions
         configurées et des applications déployées. Son utilisation est très simple :
         WebAppInfo /URL
              Le statut du serveur Tomcat pourra être consulté                        à   l'URL
         http://server.name:port/webapp-info/ (le "/" à la fin est indispensable).
             Après avoir modifié le fichier httpd.conf, stoppez et rédemarrez Apache.
         Rendez-vous ensuite à l'URL http://nomduserveurApache/examples/jsp/index.html.
         Après ceci vous devriez disposer d'une plate-forme permettant de développer des
         applications Web basées sur Java.

         7.4 Redirection du script CGI

              Puisque l’on n’utilise pas le script CGI mais un servlet pour effectuer le
         tunneling il faudra donc effectuer une redirection à l’intérieur du serveur, du script
         forme java-rmi.cgi afin que ce soit le servlet SimplifiedServletHandler qui soit exécuté
         lorsque le serveur appellera le script avec l’adresse /cgi-bin/java-
         rmi.cgi ?forward=[port numbe].
             Deux modules sont utilisés pour la redirection ce sont mod_alias et mod_rewrite.
             Il faut éditer le fichier httpd.conf d’Apache et ajouter le script ci-dessous juste
         après les directives concernant les Alias.

             •    RewriteEngine on
                  RewriteLog /usr/local/Apache/logs/rewrite.log
                  RewriteLogLevel 9
                  RewriteRule ^/cgi-bin/java\-rmi\.cgi$
                  http://localhost/rmi/servlet/ServletHandler                             [P]
             •    L’option [P] force la redirection.

                                                                                                         26
Master Seminar                                                              RMI Application over the Internet

                    8. Bibliographie

                 [1] William Grosso. Java RMI, O’Reilly & Associates, Inc. 2002

                 [2] Esmond Pitt and Neil Belford. The RMI Proxy White Paper, 2002

                 [3] JGuru, Remote Methode Invocation (RMI),
                     http://developer.java.sun.com/developer/onlineTraining/rmi/RMI.html#Fir
                     ewallIssues, 1996-2000 (accédée le 10. 06. 03)

                 [4] David M. Howard, Apache – Tomcat – RMI HTTP TUNNELING HOW-TO
                     or 10 Steps to RMI Tunneling, http://shannon.informatik.fh-
                     wiesbaden.de/jsp/jsp/docs/ApacheTomcatRMI.html (accédée le 10. 06. 03)

                 [5] Yun, Young-Sik. Frequently Asked Questions RMI and Object
                     Serialization.
                     http://caic.chungnam.ac.kr/youngsik/rmi/sun/start_tutorial/faq.html, 1999
                     (accédée le 10. 06. 03)

                 [6] M.Geldenhuys, Le Guide d'installation de Tomcat pour Windows,
                     http://www.apachefrance.com/Articles/5/, 2001 (accédée le 10. 06. 03)

                 [7] Sun Microsystems, Inc. Java Security Architecture.
                     http://java.sun.com/products/jdk/1.2/docs/guide/security/spec/security-
                     specTOC.fm.html, 1997-1998 (accédée le 10. 06. 03)

                                                                                                          27
Vous pouvez aussi lire