Вчера я попытался начать работу с Java RMI. Я нашел это руководство по солнцу (http://java.sun.com/docs/books/tutorial/rmi/index.html) и начал с реализации сервера. Но каждый раз, когда я запускаю программу (запущена rmiregistry), я получаю AccessControlException со следующим StackTrace:
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.access0(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.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.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.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, и мои параметры виртуальной машины выглядят следующим образом:
-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
Скомпилированные классы удаленного интерфейса и класса реализации интерфейса (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). И нет: я не хочу покупать плагин «G B» ;-).




Предоставление всех разрешений для всего кода - это действительно плохо. Любой клиент RMI может делать то, что он хочет, как зарегистрированный пользователь. В общем, постарайтесь максимально ограничить разрешения, особенно если вы не знаете, откуда взялся код.
Вернуться к вопросу ...
-Djava.rmi.server.codebase=file://C:/ProjX/server/serverProj/bin/usermanager/
Это должно быть "file:///C:/..." или "file:/C:/...". Подумайте о http. "http://C:/..." относится к хосту с именем C. Обратите внимание, что в сообщении об исключении пропущено двоеточие, потому что это просто синтаксис для номера порта.
Причина, по которой вы получаете исключение безопасности, даже если вы предоставляете разрешения для всего кода, заключается в том, что RMI ограничивает разрешения соответствующим образом с учетом задействованных URL-адресов (с использованием формы с двумя аргументами AccessController doPrivileged).
Привет! Я нашел это очень полезным. Подскажите, пожалуйста, где хранить текстовый файл server.policy?
@ user1799214 Исходный плакат использовал текущий рабочий каталог сервера hte, указав -Djava.security.policy=server.policy. (Как всегда, снятие ограничений для кода, доступного в сети, сложно сделать безопасно.)
Я думаю, что исключение действительно выходит из реестра. Именно эта часть трассировки стека заставляет меня так думать. Заглушка для rmiregistry получает исключение и передает его обратно в результате попытки повторного связывания.
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)
Попробуйте запустить rmiregistry с -J-Djava.security.policy=all.policy, где файл политики предоставляет все разрешения (по крайней мере, для начала работы).
В конце концов, вы можете также захотеть переключиться на URL-адрес кодовой базы HTTP, чтобы вы могли запускать клиентов на машине отдельно от вашего сервера.
Хорошо, я понял. Это не было свойством rmiregistry (работает без параметров). В моей кодовой базе VM-Parameter было две ошибки:
-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
=> файл: / (только одна косая черта) + неправильное окончание пакета.
Но трассировка была настолько запутанной, что я подумал сначала, что что-то не так с файлом политики или конфигурацией политики.
Тем не менее: Спасибо за помощь и удачного взлома. ;-)
Вы также можете программно установить свойство 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();
}
для какой-то гипотетической службы Hello RMI.
Кажется, мне не удается установить это свойство. Кажется, моя Java не позволяет мне выполнять заданную операцию.
Он просто отлично работает, когда я исправил переменную CLASSPATH перед запуском реестра rmi. Я думаю, что идея в том, что реестр RMI загрузит ваши удаленные заглушки, и у него должен быть доступ. Это было легко, поместив мои классы в CLASSPATH перед запуском реестра. Таким образом, это не связано с какой-либо другой причиной, такой как JDK 7 или протокол file: /.
У меня была аналогичная проблема. Я решил это с помощью такого подхода - stackoverflow.com/a/44275905/1509058