Java: нет менеджера безопасности: загрузчик класса RMI отключен - PullRequest
26 голосов
/ 12 июня 2011

Привет, у меня есть приложение 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;
}

Он постоянно что-то говорит об отключенной загрузке классов, так что я думаю, проблема где-то есть ... Спасибо!

Ответы [ 4 ]

25 голосов
/ 14 июня 2011

Удаленная загрузка классов может быть сложной.

Оригинальный пост не содержит никакой информации о базе кода.Может случиться так, что конфигурация безопасности клиента верна, но он не имеет доступа к удаленному коду.Классы загружаются непосредственно из «базы кода» клиентом.Они не предоставляются клиенту службой через соединение RMI.Служба просто ссылается на внешний источник для классов.

Сервер должен указать системное свойство java.rmi.server.codebase.Значением должен быть URL-адрес , доступный для клиента, , с которого можно загрузить необходимые классы.Если это URL-адрес file:, файловая система должна быть доступна для клиента.

И наоборот: если сервер должен загружать классы с клиента (как здесь), клиент должен установить свойство базы кода для URL, который доступен для сервера.

7 голосов
/ 29 июля 2013

Каждый раз, когда вы вызываете метод на динамическом прокси RMI, MarshalInputStream (который расширяет ObjectInputStream для переопределения resolveClass и resolveProxyClass) делегирует LoaderHandler для поиска в * 3 местах ClassLoader:

  1. ClassLoader вызываемого прокси (технически он использует хак с именем latestUserDefinedLoader(): он поднимается по стеку, ища первый метод в стеке, который не является частью JRE).
  2. Локальная нить contextClassLoader звонящего
  3. Codebase ClassLoader, если включен SecurityManager
    1. Если свойство System java.rmi.server.useCodebaseOnly=false, то кодовая база ClassLoader использует URL-адреса в remote java.rmi.server.codebase. Обратите внимание, что значение по умолчанию для useCodebaseOnly изменилось в JDK 7u21 , поэтому удаленная кодовая база больше не используется, если вы не измените ее !
    2. В противном случае кодовая база ClassLoader использует URL-адреса в local java.rmi.server.codebase.

Так что есть несколько возможных причин, по которым вы получите ClassNotFoundException при вызове метода Remote:

  • Если в стеке «нет диспетчера безопасности: загрузчик классов RMI отключен», убедитесь, что установили SecurityManager, как описано другими, если вам требуется удаленная загрузка классов для обеих сторон, чтобы получить все интерфейсы Remote и сериализуемые классы.
  • Если вы используете удаленную загрузку классов, и она перестала работать при обновлении до JRE 7u21, то либо установите -Djava.rmi.server.useCodebaseOnly=true в соответствии с предыдущим поведением, либо установите -Djava.rmi.server.codebase на разделенный пробелами список URL-адресов как на локальном, так и на локальном отдаленные стороны. И убедитесь, что компьютер может получить доступ к этим URL.
  • Если вы используете пользовательский ClassLoader локально, чей родительский загрузчик классов определяет некоторые Удаленные интерфейсы, то обязательно вызовите Thread.setContextClassLoader(ClassLoader), чтобы RMI использовал этот ClassLoader. (Это была моя проблема: у меня было SwingWorker, которое, как оказалось, было запланировано на рабочий поток, который был создан до того, как contextClassLoader был установлен на EventDispatchThread). Например, A и C принадлежат вашему пользовательскому ClassLoader, но B принадлежит родительскому ClassLoader, тогда когда вы вызываете a.getB (). GetC (), вызов getB () будет использовать пользовательский загрузчик классов, но вызов getC () не сможет найти C в latestUserDefinedClassLoader и должен будет вернуться к contextClassLoader.

Все это предостерегающая история о плохом дизайне API ObjectInputStream. ObjectInputStream должен был требовать, чтобы вы передавали параметр ClassLoader, а не пытались найти его случайно, используя latestUserDefinedLoader, contextClassLoader и codebase.

4 голосов
/ 14 июня 2011

Вам необходим диспетчер безопасности на стороне сервера, а не только на стороне клиента.

Без этого механизм RMI сервера отказывается загружать классы из клиента, так как он можетНе гарантируйте, что это не принесет зла ​​на сервер.

Вам нужна загрузка класса RMI вообще?Может ли сервер уже иметь классы, которые клиент пытается отправить?

0 голосов
/ 21 апреля 2014

Я знаю, почему это происходит.например, вы запускаете сервер в проекте A, но вы используете клиент в проекте B для запроса этого сервера, это неправильно.Поэтому вы должны поместить сервер и клиент в один и тот же проект.

...