15

昨日、JavaRMIを使い始めようとしました。このSunチュートリアル(http://java.sun.com/docs/books/tutorial/rmi/index.html)を見つけて、サーバーの実装から始めました。しかし、pogramを開始するたびに(rmiregistryが実行されている)、次のStackTraceでAccessControlExceptionが発生します。

LoginImpl exception:
java.security.AccessControlException: access denied (java.io.FilePermission \\\C\ProjX\server\serverProj\bin\usermanager read)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264)
    at java.security.AccessController.checkPermission(AccessController.java:427)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
    at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
    at java.io.File.exists(File.java:700)
    at sun.net.www.protocol.file.Handler.openConnection(Handler.java:80)
    at sun.net.www.protocol.file.Handler.openConnection(Handler.java:55)
    at java.net.URL.openConnection(URL.java:943)
    at sun.rmi.server.LoaderHandler.addPermissionsForURLs(LoaderHandler.java:1020)
    at sun.rmi.server.LoaderHandler.access$300(LoaderHandler.java:52)
    at sun.rmi.server.LoaderHandler$Loader.<init>(LoaderHandler.java:1108)
    at sun.rmi.server.LoaderHandler$Loader.<init>(LoaderHandler.java:1089)
    at sun.rmi.server.LoaderHandler$1.run(LoaderHandler.java:861)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.server.LoaderHandler.lookupLoader(LoaderHandler.java:858)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:541)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:628)
    at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:238)
    at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1494)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1457)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1693)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1299)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:339)
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:375)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:240)
    at sun.rmi.transport.Transport$1.run(Transport.java:153)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)
    at java.lang.Thread.run(Thread.java:595)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
    at sun.rmi.server.UnicastRef.invoke(Unknown Source)
    at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
    at startserver.StartServer.main(StartServer.java:22)

私のserver.policyファイルは次のようになります。

grant {
    permission java.security.AllPermission;
};

しかし、私もこれを試しました...

grant {
    permission java.security.AllPermission;
    permission java.io.FilePermission "file://C:/ProjX/server/serverProj/bin/usermanager", "read";
};

...そしてこれ(そして他のいくつか:-():

grant codeBase "file:///-" {
    permission java.security.AllPermission;
};

しかし、いずれの場合も結果は同じです。はい、ポリシーファイルはパス内にあります(ポリシーファイルに間違ったステートメントを書き込むと、解析例外が表示されます)。他のいくつかの「/」と「\」の星座を試しましたが、効果がありません。

私はEclipseを使用しており、VM-パラメーターは次のようになっています。

-cp C:\ProjX\server\serverProj\bin\usermanager\
-Djava.rmi.server.codebase=file://C:/ProjX/server/serverProj/bin/usermanager/
-Djava.rmi.server.hostname=XYZ (anonymized)
-Djava.security.policy=server.policy

コンパイルされたRemote-Interfaceクラスとinterface-implementationクラス(LoginImpl)クラスは、「C:/ ProjX / server / serverProj / bin /usermanager/」のパスにあります。スタブをインスタンス化してレジストリに再バインドする主な方法は、別のパッケージにあり、次のようになります。

public static void main(String[] args) {
    if (System.getSecurityManager() == null) {
        System.setSecurityManager(new SecurityManager());
    }
    try {
        String name = "Login";
        Login login = new LoginImpl();
        Login stub = (Login) UnicastRemoteObject.exportObject(login, 0);
        Registry registry = LocateRegistry.getRegistry();
        registry.rebind(name, stub);
        System.out.println("LoginImpl bound");
    } catch (Exception e) {
        System.err.println("LoginImpl exception:");
        e.printStackTrace();
    }
}

誰かアドバイスはありますか?助けてくれてありがとう。


したがって、質問は同じです(java.rmi.UnmarshalExceptionは、コードベースの変更がAccessControlExceptionの解決策ではないことを示しています)。いいえ:プラグイン「GB」は購入したくありません;-)。

4

5 に答える 5

7

わかりました、私はそれを持っています。rmir​​egistry プロパティではありません (パラメータなしで動作します)。コードベースの VM-Parameter に 2 つのエラーがありました。

-cp C:\ProjX\server\serverProj\bin\usermanager\
-Djava.rmi.server.codebase=file://C:/ProjX/server/serverProj/bin/usermanager/
-Djava.rmi.server.hostname=XYZ (anonymized)
-Djava.security.policy=server.policy

...代わりに次のようになります。

-Djava.rmi.server.codebase=file:/C:/ProjX/server/serverProj/bin/
-Djava.rmi.server.hostname=XYZ (anonymized)
-Djava.security.policy=server.policy

=> file:/ (スラッシュが 1 つだけ) + パッケージの末尾が間違っています。

しかし、トレースは非常に紛らわしく、最初に考えたのは、ポリシー ファイルまたはポリシー構成に何か問題があるに違いないということでした。

それにもかかわらず: ヘルプと幸せなハッキングをありがとう. ;-)

于 2008-10-14T18:10:28.157 に答える
7

すべてのコードにすべての権限を付与することは、本当に悪いことです。どの RMI クライアントも、ログイン ユーザーとして必要なことを実行できます。一般に、特にコードがどこから来たのかわからない場合は、許可をできるだけ制限するようにしてください。

質問に戻る...

-Djava.rmi.server.codebase=file://C:/ProjX/server/serverProj/bin/usermanager/

それは または のいずれかである必要があり"file:///C:/..."ます"file:/C:/..."。httpを考えてください。"http://C:/..."という名前のホストを指しますC。例外メッセージではコロンが削除されていることに注意してください。これは、ポート番号の単なる構文であるためです。

すべてのコードにアクセス許可を付与した場合でもセキュリティ例外が発生する理由は、RMI が関連する URL を考慮して適切なアクセス許可を制限しているためです (AccessController doPrivileged 2 引数形式を使用)。

于 2008-10-07T20:14:02.227 に答える
2

プログラムで java.rmi.server.codebase プロパティを設定することもできます。

Hello h = null;
Properties props = System.getProperties();
System.setProperty("java.rmi.server.codebase", "file:/C:/PROJECTX/bin/");
try {
  h = new HelloImpl();
  Naming.bind("//localhost:1099/HelloService", h);
  System.out.println("Serwis gotów...");
} catch (RemoteException e) {
  e.printStackTrace();
} catch (MalformedURLException e) {
  e.printStackTrace();
} catch (AlreadyBoundException e) {
  e.printStackTrace();
}

いくつかの架空のHelloRMI サービス用。

于 2008-11-12T18:18:47.303 に答える
0

rmi レジストリを開始する前に CLASSPATH 変数を修正すると、問題なく動作します。RMI レジストリがリモート スタブをロードし、アクセスできるようにするという考えだと思います。これは、レジストリを実行する前にクラスを CLASSPATH に置くことで簡単にできました。したがって、JDK 7 や file:/ プロトコルなど、他の理由とは関係ありません。

于 2013-08-22T09:56:04.827 に答える
0

例外は実際にはrmiregistryから出ていると思います。スタック トレースのこの部分がそう思わせる理由です。rmir​​egistry のスタブが例外を受け取り、再バインドの試行の結果としてそれを戻しています。

    sun.rmi.transport.StreamRemoteCall にあります。exceptionReceivedFromServer (不明なソース)
    sun.rmi.transport.StreamRemoteCall.executeCall (不明なソース) で
    sun.rmi.server.UnicastRef.invoke (不明なソース) で
    sun.rmi.registry.RegistryImpl_Stub.rebind で (不明なソース)

rmir​​egistry を-J-Djava.security.policy=all.policyで実行してみてください。ここで、ポリシー ファイルはすべてのアクセス許可を付与します (少なくとも作業を進めるため)。

最終的には、サーバーとは別のマシンでクライアントを実行できるようにするために、HTTP コードベース URL に切り替えたいと思うかもしれません。

于 2008-10-14T16:40:26.653 に答える