Teil 2 - auf Matthias

Werbung
Netzprogrammierung:
Java RMI - Remote Method Invocation
(Teil 2)
Robert Tolksdorf und Peter Löhr
Überblick
1.
2.
3.
4.
Auffinden von .class-Dateien
Serializable Parameter
Sicherheit
Code laden übers Web
Zur Erinnerung - Dokumentation RMI:
http://java.sun.com/javase/6/docs/platform/rmi/spec/rmiTOC.html
http://java.sun.com/docs/books/tutorial/rmi/
Robert Tolksdorf und Peter Löhr
2
Auffinden von .class-Dateien
Robert Tolksdorf und Peter Löhr
Nochmal Beispiel Counter
Zur Erinnerung - Beispiel Counter: Schnittstelle Counter.java
Anbieter
CounterImpl.java
Klient
Inc.java
ann@server:~/anncount
ann@server:~/anncount
ann@server:~/anncount
Counter.class
CounterImpl.class
ann@server:~/anncount
bob@client:~/bobcount
bob@client:~/bobcount
bob@client:~/bobcount
Counter.class
Inc.class
bob@client:~/bobcount
$ javac CounterImpl.java
$ rm *.java
$ ls|more
$
$ javac Inc.java
$ rm *.java
$ ls|more
(... getRegistry("server"); ...)
$
Robert Tolksdorf und Peter Löhr
4
Nochmal Beispiel Counter
ann@server:~ann/anncount $ rmiregistry &
[1] 8774
ann@server:~ann/anncount $ java CounterImpl &
[1] 8777
Dies scheitert, wenn im Klassenpfad
ann@server:~ann/anncount $ des rmiregistry (!) die Counter.class
nicht gefunden wird !
bob@client:~/bobcount $ java Inc 5
counter is 5
bob@client:~/bobcount $
Robert Tolksdorf und Peter Löhr
5
.class-Dateien über das Web laden
Saubere Lösung mit vollständiger Entkoppelung des Registry
von den zu verwaltenden Objekten:
eve@server:~ $ rmiregistry &
[1] 8774
eve@server:~ $
(am besten ohne CLASSPATH)
ann@server:~ann/anncount $ java \
> -Djava.rmi.server.codebase=http://page.mi.fu-berlin.de/~ann/classes/ \
> CounterImpl &
[1] 8777
ann@server:~ann/anncount $
Codebasis für Registry („server“) wird durch URL identifiziert.
Counter.class wird in classes vorgehalten.
Robert Tolksdorf und Peter Löhr
6
Serializable Parameter
Robert Tolksdorf und Peter Löhr
Remote versus Serializable
Zur Erinnerung - Fernaufruf-Parameter mit Verweistyp:
• Wenn der aktuelle Parameter Remote ist:
Übergabe eines Fernverweises.
• Wenn der aktuelle Parameter nicht Remote,
aber Serializable ist:
Übergabe einer Objektkopie.
• Sonst: Laufzeitfehler MarshalException.
Robert Tolksdorf und Peter Löhr
8
Code nachladen
Übergabe einer Kopie eines Serializable Objekts wie kommt der Empfänger zum Code des Objekts?
• Kein Problem, wenn Klasse beim Empfänger vorhanden,
genauer: wenn dort über CLASSPATH erreichbar;
• wenn nicht, eventuell java -cp <classpath> einsetzbar,
wenn Sender und Empfänger im gleichen Dateisystem.
• Fernladen: Häufig liegt die Klasse in einem fremden
Dateisystem auf einem anderem Rechner, typischerweise
am Ort des entfernten Objekts. Dann kann der Code mit einer
URL identifiziert und über das Web geladen werden (s.u.).
• Achtung - Sicherheitsprobleme bei Verwendung fremden Codes!
Robert Tolksdorf und Peter Löhr
9
Beispiel: Fernaufrufbares Factory-Objekt zur Erzeugung
von Serializable Objekten, die die Klienten sich
per Fernaufruf beschaffen können.
Die Klienten wissen nichts von der Implementierung
- und wollen auch nichts davon wissen.
... implements Factory
...
new ...
data
data
code
code
?
Netzdateisystem:
Robert Tolksdorf und Peter Löhr
code
10
Beispiel: Fabrik für Echo-Objekte
interface Echo {
// is not Remote !
void print();
// print echo
}
import java.rmi.*;
interface Factory extends Remote {
Echo create(String s) throws RemoteException;
}
// creates an echo of s
anna als Anbieter der Fabrik stellt den Benutzern
lediglich diese zwei Schnittstellen zur Verfügung.
import java.io.Serializable;
public class EchoImpl implements Echo, Serializable {
public EchoImpl(String s) { echo = s; }
String echo;
import java.rmi.server.UnicastRemoteObject;
public void print() {
import java.rmi.registry.LocateRegistry;
System.out.println(echo);
import java.rmi.registry.Registry;
public class EchoFactory implements Factory {
}
public Echo create(String s) {
}
Robert Tolksdorf und Peter Löhr
return new EchoImpl(s.substring(1,s.length()));
}
public static void main(String[] arg) throws Exception {
Factory f = new EchoFactory();
11
Factory stub = (Factory) UnicastRemoteObject.exportObje
Registry registry = LocateRegistry.getRegistry();
registry.bind("factory", stub);
Beispiel: Fabrik für Echo-Objekte
Mit Kenntnis der Schnittstellen (und des Namens der Fabrik im
Registry) verfasst der Benutzer paul ein Klientenprogramm:
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Test {
public static void main(String[] arg) throws Exception{
Registry registry = LocateRegistry.getRegistry();
Factory f = (Factory) registry.lookup("factory");
Echo x = f.create(arg[0]);
// delivers copy !
x.print();
// local call !
}
}
Robert Tolksdorf und Peter Löhr
12
Test mit Netzdateisystem
anna@human:~/echo/classes
Echo.class
EchoFactory.class
EchoImpl.class
Factory.class
anna@human:~/echo/classes
[1] 1373
anna@human:~/echo/classes
[2] 1374
anna@human:~/echo/classes
$ ls | more
$ rmiregistry &
$ java EchoFactory &
$
paul@troll:~/test/classes $ ls | more
Echo.class
Factory.class
Test.class
paul@troll:~/test/classes $ java Test wesel
Exception in thread "main" java.rmi.UnmarshalException:
error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: EchoImpl .....................
Robert Tolksdorf und Peter Löhr
13
Test mit Netzdateisystem
Reparieren:
paul@troll:~/test/classes $ ls | more
Echo.class
Factory.class
Test.class
paul@troll:~/test/classes $ java -cp .:/home/anna/echo/classes Test wesel
esel
paul@troll:~/test/classes $
(Damit sind übrigens auch diese entbehrlich!)
Achtung: paul muss auf die Dateien in /home/anna/echo/classes
Lesezugriff haben - sonst gibt es wiederum eine
java.lang.ClassNotFoundException: EchoImpl
Robert Tolksdorf und Peter Löhr
14
Entfernte Benutzung der Fabrik
Bei Benutzung der Fabrik von einem fremden Dateisystem aus
(evtl. Firewall mit VPN umgehen) muss der Code von EchoImpl
mit dem RMI-Klassenlader über das Web heruntergeladen werden.
Die URL der entsprechenden Codebasis wird von der Fabrik mit
dem EchoImpl-Objekt mitgeliefert (s.u.).
paul@xyz:~/test/classes $ java Test wesel
Exception in thread "main" java.rmi.UnmarshalException:
error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: EchoImpl
(no security manager: RMI class loader disabled) ...........
Das Nachladen von Code über das Web wird verweigert,
wenn kein Security Manager installiert ist!
Robert Tolksdorf und Peter Löhr
15
Sicherheit
http://java.sun.com/javase/6/docs/technotes/guides/security/
http://java.sun.com/docs/books/tutorial/security/
Robert Tolksdorf und Peter Löhr
Vorsicht vor Schadcode!
• Fremder Code verhält sich vielleicht anders als erwartet!
• Schadcode (malware) hat unerwünschte Funktionalität,
die dem Benutzer Schaden zufügen kann. Typisch sind:
• Trojanische Pferde - haben zwar die gewünschte Funktionalität,
aber zusätzlich (und verdeckt) eine schädliche Funktionalität;
• Viren - sind Schadcode, der zusätzlich zu seiner schädlichen
Funktionalität auch anderen - bislang unschädlichen - Code infiziert.
• ! Sicherheitsbewusstes Verhalten: keinen Code benutzen,
• den man nicht selbst geschrieben hat oder
• dessen Autor man vertraut (?) oder
• der erfahrungsgemäß richtig funktioniert (??).
Robert Tolksdorf und Peter Löhr
17
EchoImpl ein Trojanisches Pferd?
Zur Erinnerung (S. 14): bei der Ausführung des Programms Test
paul@troll:~/test/classes $ java -cp .:/home/anna/echo/classes Test wesel
esel
holt paul sich eventuell ein Trojanisches Pferd von anna ins Haus:
Der Code der von der Echo-Fabrik gelieferten
EchoImpl-Objektkopie produziert zwar das erwartete Echo,
könnte aber auch Schadcode enthalten,
der Dateien zerstört, Dateiinhalte kopiert, etc. etc.
Robert Tolksdorf und Peter Löhr
18
Security Manager
Schutz vor fremdem Schadcode wird durch Mitlaufenlassen eines
Security Manager ermöglicht:
$ java -Djava.security.manager .....
Security Manager folgt benutzerdefinierten Richtlinien (policies),
die in entsprechenden Richtlinien-Dateien bereitgestellt sind:
~/.java.policy
(privat)
$JAVAHOME/jre/lib/security/java.policy
(global)
... und andere, explizit benannte Dateien
Eine Richtlinien-Datei (policy file) enthält eine Menge von
Berechtigungen (Erlaubissen, permissions), die für Code
verschiedener Herkunft verschiedene Aktionen erlauben.
! Was nicht erlaubt ist, ist verboten. Wenn keine Richtlinien-Datei
vorliegt, ist nichts erlaubt !
Robert Tolksdorf und Peter Löhr
19
Richtlinien-Datei
Beispiel für eine einfache Richtlinien-Datei mypolicy von bob:
grant codeBase "file:${user.home}/-" {
permission java.security.AllPermission;
};
grant codeBase "file:/usr/ann/classes/*" {
permission java.io.FilePermission "/usr/bob/help/*", "read";
permission java.net.SocketPermission "localhost:1024-",
"connect, accept";
}
grant {
// allows any code to read in pub subtree
permission java.io.FilePermission "/usr/bob/pub/-", "read";
};
Benutzung z.B. so:
bob: java -Djava.security.manager \
>
-Djava.security.policy=mypolicy ....
Robert Tolksdorf und Peter Löhr
20
Richtlinien-Datei bearbeiten
Fensterbasierte Bearbeitung von Richtlinien-Dateien:
lohr: policytool
-->
http://java.sun.com/javase/6/docs/technotes/guides/security/PolicyFiles.html
http://java.sun.com/javase/6/docs/technotes/guides/security/permissions.html
Robert Tolksdorf und Peter Löhr
21
Beispiel: System Property erfragen
import java.lang.*;
import java.security.*;
class GetProps { // from http://java.sun.com/docs/books/tutorial/security/
public static void main(String[] args) throws Exception {
s = System.getProperty("user.home", "not specified");
System.out.println(" Your user home directory is: " + s);
}
}
$ java GetProps
Your user home directory is: /Users/lohr
$ java -Djava.security.manager GetProps
Exception in thread "main" java.security.AccessControlException:
access denied (java.util.PropertyPermission user.home read) .......
$
Robert Tolksdorf und Peter Löhr
22
Beispiel: System Property erfragen
Geeignete Richtlinien-Datei mypolicy in getprops einrichten:
grant codeBase "file:/Users/lohr/samples/getprops/*" {
permission java.util.PropertyPermission "user.home", "read";
};
Und dann:
$ ls | more
GetProps.class
GetProps.java
mypolicy
$ java -Djava.security.manager -Djava.security.policy=mypolicy GetProps
Your user home directory is: /Users/lohr
$
Robert Tolksdorf und Peter Löhr
23
Security Manager programmatisch
Ein Security Manager kann auch per Programm gesetzt werden:
public static void main(String[] arg) {
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
.......
}
Damit ist sichergestellt, dass ein Security Manager
garantiert vorhanden ist.
Robert Tolksdorf und Peter Löhr
24
Code laden übers Web
http://java.sun.com/javase/6/docs/technotes/guides/rmi/codebase.html
Robert Tolksdorf und Peter Löhr
Codebasis im Web
• Zur Erinnerung: mit CLASSPATH oder mit der Option -cp
kann man sich nur auf Dateien im eigenen Dateisystem
(bzw. Netzdateisystem) beziehen.
• Das Nachladen von Code (.class-Dateien oder .jar-Dateien)
aus fremden Dateisystemen ist nur über das Web möglich:
• Ausnutzung vorhandener Infrastruktur (HTTP-Protokoll)
• keine Probleme mit Firewalls
• Somit wird eine URL verwendet, um ein Verzeichnis, das
als Codebasis (codebase) dienen soll, zu identifizieren.
• Achtung: Da die Firewall zwischen Internet und Intranet
i.a. nur den Verkehr über wenige Standard-Ports erlaubt,
braucht man VPN für intranet-überschreitendes RMI !
Robert Tolksdorf und Peter Löhr
26
Entfernte Benutzung der Echo-Fabrik
Revision des Ansatzes von S. 15:
Anbieter: Benutzer lohr auf human.inf.fu-berlin.de
Klient:
„anderer“ lohr auf PC über VPN
mit diesen Richtlinien testpolicy :
grant codeBase "file:/Users/lohr/-" {
permission java.security.AllPermission;
};
grant codeBase "http://page.mi.fu-berlin.de/~lohr/classes/-" {
permission . . . . . . .
};
Hierfür sollten Berechtigungen nur sehr restriktiv vergeben werden!
In unserem Fall sollte der Eintrag sogar ganz weggelassen werden,
weil die print-Methode von EchoImpl keine Berechtigungen benötigt;
damit sind wir vor Trojanischem Code geschützt!
Robert Tolksdorf und Peter Löhr
27
Randbedingungen
• Die URL einer Codebasis im Web bezeichnet ein Verzeichnis,
• das entweder die Klassendateien (.class) in Unterverzeichnissen
gemäß der Paketstruktur enthält
• oder eine entsprechende Archivdatei (.jar) enthält.
• Für das Echo-Beispiel wählen wir eine einfache Paketisierung:
• echo enthält die Schnittstellen Echo und Factory ;
• factory enthält die Klassen EchoImpl und EchoFactory ;
• echotest enthält die Klasse Test.
• Beim Start der Fabrik EchoFactory muss die Codebasis
angegeben werden, über die der Empfänger eines EchoObjekts sich den zugehörigen Code beschaffen kann (vgl.S.6):
-Djava.rmi.server.codebase=http://page.mi.fu-berlin.de/~lohr/classes/
Achtung: eine solche Angabe ist bei allen Programmen erforderlich, die
Serializable Objekte verschicken, sei es als Argument oder als Ergebnis!
Robert Tolksdorf und Peter Löhr
28
Anbieterseitige Situation
Die Codebasis im Web:
human: cd /web/page.mi.fu-berlin.de/web-home/lohr/public_html/classes
human: ls *
echo:
Factory.class
(die beim Registry benötigte Schnittstelle - vgl. S. 6)
factory:
EchoImpl.class
(die bei Klienten benötigte Klasse)
Der vollständige Code für die Echo-Fabrik:
human: cd ............
human: ls *
echo:
Echo.class
Factory.class
factory:
EchoFactory.class EchoImpl.class
Robert Tolksdorf und Peter Löhr
29
Starten der Echo-Fabrik
human : rmiregistry &
[1] 24365
human: java -Djava.rmi.server.codebase=\
> http://page.mi.fu-berlin.de/~lohr/classes/ \
> factory/EchoFactory &
[2] 24395
human:
Robert Tolksdorf und Peter Löhr
30
Test der Echo-Fabrik
lohr@lohr: cd .......
lohr@lohr: ls *
testpolicy
echo:
Echo.class
Factory.class
echotest:
Test.class
lohr@lohr: java -Djava.security.manager \
>
-Djava.security.policy=testpolicy \
>
echotest/Test wesel
esel
lohr@lohr:
Robert Tolksdorf und Peter Löhr
31
Ein weiteres Beispiel
(aus http://java.sun.com/docs/books/tutorial/rmi/ )
Rechenintensiven Code execute eines Klienten von einem
Anbieter auf leistungsfähiger Maschine ausführen lassen:
public interface Task<T> {
T execute();
}
// not Remote
Anbieter kann über generische Methode executeTask
angesprochen werden:
public interface Compute extends Remote {
<T> T executeTask(Task<T> t) throws RemoteException;
}
Robert Tolksdorf und Peter Löhr
32
... und der Klient
Die Rechenaufgabe des Klienten:
public class Heavy implements Task<Result>, Serializable {...}
... und das Rahmenprogramm:
public class HeavyComputing {
public static void main(String arg[]) {
.....
Compute comp = (Compute)registry.lookup("compute");
Result result = comp.executeTask(new Heavy(...));
.....
}
}
Robert Tolksdorf und Peter Löhr
33
Hier statt Berechnung von Heavy
Berechnung von Pi
Code-Übertragung in andere
Richtung als bei Echo-Beispiel!
Robert Tolksdorf und Peter Löhr
mit HeavyComputing
mit ComputePi
implements Compute
34
Allgemeine Situation
Robert Tolksdorf und Peter Löhr
35
Zusammenfassung
Robert Tolksdorf und Peter Löhr
Zusammenfassung
• Auffinden von .class-Dateien
• classpath bei rmiregistry, Anbieter und Klient beachten!
• ggfls. Codebasis im Web für rmiregistry vorhalten
• vorzugsweise mit .jar-Dateien arbeiten
• Serialisierbare Parameter
• Empfänger erhält Verweis auf lokale Kopie
• eventuell muss auch Code übertragen werden
• Sicherheit
• Schutz vor Trojanischem Code
• Security Manager und Richtlinien-Dateien
• Code laden übers Web
• nur mit Security Manager
Robert Tolksdorf und Peter Löhr
37
Literatur
Sun Microsystems: Security
http://java.sun.com/javase/6/docs/technotes/guides/security/
http://java.sun.com/javase/6/docs/technotes/guides/security/PolicyFiles.html
http://java.sun.com/javase/6/docs/technotes/guides/security/permissions.html
Sun Microsystems: Security Tutorial
http://java.sun.com/docs/books/tutorial/security/
Robert Tolksdorf und Peter Löhr
38
Herunterladen