web-dev-qa-db-ja.com

Java:セキュリティマネージャーなし:RMIクラスローダーが無効

こんにちはRMIアプリケーションがあり、クライアントからサーバーでいくつかのメソッドを呼び出そうとしています。私は次のコードを持っています:

_public static void main(final String[] args) {
    try {
        //Setting the security manager

        System.setSecurityManager(new RMISecurityManager());
        IndicatorsService server = (IndicatorsService) Naming
                .lookup("rmi://localhost/" + IndicatorsService.SERVICE_NAME);
        DataProvider provider = new OHLCProvider(server);
        server.registerOHLCProvider(provider);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (RemoteException e) {
        e.printStackTrace();
    } catch (NotBoundException e) {
        e.printStackTrace();
    }
}
_

サーバーは正しくロードされていますが、server.registerOHLCProvider(provider);を呼び出そうとすると、次のエラーが表示されます。

_     Java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    Java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    Java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at Sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.Java:336)
    at Sun.rmi.transport.Transport$1.run(Transport.Java:159)
    at Java.security.AccessController.doPrivileged(Native Method)
    at Sun.rmi.transport.Transport.serviceCall(Transport.Java:155)
    at Sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.Java:535)
    at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.Java:790)
    at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.Java:649)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.Java:886)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:908)
    at Java.lang.Thread.run(Thread.Java:662)
    at Sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.Java:255)
    at Sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.Java:233)
    at Sun.rmi.server.UnicastRef.invoke(UnicastRef.Java:142)
    at sk.fri.statistics.service.impl.IndicatorsServiceImpl_Stub.registerOHLCProvider(Unknown Source)
    at sk.fri.statistics.service.Client.main(Client.Java:61)
Caused by: Java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    Java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at Sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.Java:296)
    at Sun.rmi.transport.Transport$1.run(Transport.Java:159)
    at Java.security.AccessController.doPrivileged(Native Method)
    at Sun.rmi.transport.Transport.serviceCall(Transport.Java:155)
    at Sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.Java:535)
    at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.Java:790)
    at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.Java:649)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.Java:886)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:908)
    at Java.lang.Thread.run(Thread.Java:662)
Caused by: Java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at Sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.Java:375)
    at Sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.Java:165)
    at Java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.Java:620)
    at Java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.Java:247)
    at Sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.Java:197)
    at Java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.Java:1574)
    at Java.io.ObjectInputStream.readClassDesc(ObjectInputStream.Java:1495)
    at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1731)
    at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
    at Java.io.ObjectInputStream.readObject(ObjectInputStream.Java:350)
    at Sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.Java:306)
    at Sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.Java:290)
    ... 9 more
_

ポリシーファイルをVM引数として追加しました。次のようになります。

_grant {
    permission Java.security.AllPermission;
}
_

無効なクラスローディングについて何か言い続けているので、問題はどこかにあると思います...ありがとう!

26
Xorty

リモートクラスのロードには注意が必要です。

元の投稿には、コードベースに関する情報は含まれていません。クライアントのセキュリティ構成は正しいが、リモートコードにアクセスできない可能性があります。クラスは、クライアントによって「コードベース」から直接ロードされます。 RMI接続を介したサービスによってクライアントに提示されることはありません。サービスは単にクラスの外部ソースを参照します。

サーバーは、システムプロパティJava.rmi.server.codebaseを指定する必要があります。値はURLである必要がありますクライアントがアクセス可能そこから必要なクラスをロードできます。これがfile: URLの場合、ファイルシステムクライアントからアクセス可能である必要があります。

他の方法:サーバーがクライアントからクラスをロードできるようにする必要がある場合(次のように)、クライアントはコードベースプロパティをサーバーからアクセス可能なURLに設定する必要があります。

25
erickson

RMI動的プロキシでメソッドを呼び出すたびに、 MarshalInputStream (これは ObjectInputStream を拡張してresolveClassをオーバーライドしますおよびresolveProxyClass)が LoaderHandler に委任して、使用するClassLoaderの3つの場所を検索します。

  1. 呼び出されているプロキシのClassLoader(技術的には、latestUserDefinedLoader()と呼ばれるハックを使用します。JREの一部ではないスタックの最初のメソッドを探してスタックを調べます)。
  2. 呼び出し元のスレッドローカルcontextClassLoader
  3. SecurityManagerが有効な場合のコードベースClassLoader
    1. システムプロパティが_Java.rmi.server.useCodebaseOnly=false_の場合、コードベースClassLoaderはremote_Java.rmi.server.codebase_のURLを使用します。 seCodebaseOnlyのデフォルト値はJDK 7u21で変更されたため、変更しない限りリモートコードベースは使用されません
    2. それ以外の場合、コードベースClassLoaderはlocal_Java.rmi.server.codebase_のURLを使用します。

そのため、Remoteメソッドを呼び出すときにClassNotFoundExceptionを取得する理由はいくつか考えられます。

  • スタックに「セキュリティマネージャーなし:RMIクラスローダーが無効」が含まれている場合、すべてのリモートインターフェイスとシリアル化可能なクラスを取得するために両側でリモートクラスの読み込みが必要な場合は、他の人が説明するようにSecurityManagerを設定してください。
  • リモートクラスロードを使用していて、JRE 7u21にアップグレードしたときに動作しなくなった場合は、_-Djava.rmi.server.useCodebaseOnly=true_を以前の動作に一致するように設定するか、_-Djava.rmi.server.codebase_を両方のローカルでURLのスペース区切りリストに設定しますそして遠隔側。そして、コンピューターがそれらのURLにアクセスできることを確認してください。
  • 親クラスローダーがsomeリモートインターフェースを定義するカスタムClassLoaderをローカルで使用している場合、RMIがそのClassLoaderを使用するようにThread.setContextClassLoader(ClassLoader)を呼び出してください。 (これが私の問題でした:EventDispatchThreadでcontextClassLoaderが設定される前に作成されたワーカースレッドにたまたまスケジュールされたSwingWorkerがありました)。たとえば、AとCはカスタムClassLoaderに属しますが、Bは親ClassLoaderに属します。a.getB()。getC()を呼び出すと、getB()呼び出しはカスタムクラスローダーを使用しますが、getC()呼び出しはlatestUserDefinedClassLoaderでCを見つけられず、contextClassLoaderにフォールバックする必要があります。

これらはすべて、ObjectInputStreamの貧弱なAPI設計に関する警告物語です。 ObjectInputStreamでは、latestUserDefinedLoader、contextClassLoader、およびcodebaseを使用して偶然にパラメータを見つけようとするのではなく、ClassLoaderパラメータを渡す必要があります。

7
yonran

クライアント側だけでなく、サーバー側でもsecurity managerが必要です。

これがないと、サーバーのRMIエンジンはクライアントからのクラスのロードを拒否します。これは、これらがサーバー上で悪事を起こさないことを保証できないためです。

RMIクラスの読み込みが必要ですか?サーバーは、クライアントが送信しようとするクラスをすでに持っていませんか?

4
Paŭlo Ebermann