我在JBoss(4.2.2.GA)服务器和J2SE客户端之间建立了JMS连接。客户端通过Java Web Start运行,在JNLP中,我有以下内容:
<jnlp version="1.5+" codebase="$$codebase" href="start.jnlp">
<!-- Information -->
<security>
<all-permissions />
</security>
<resources>
<!-- Some other non-JMS resources -->
<jar href="concurrent.jar" />
<jar href="jboss-common.jar" />
<jar href="jboss-j2ee.jar" />
<jar href="jbossmq.jar" />
<jar href="jnpserver.jar" />
<jar href="log4j.jar" />
<resources>
</jnlp>
JMS连接正常。我已成功配置,订阅和测试了JMS主题。这是代码:
final String topic = ... ;
final InitialContext context = new InitialContext();
PrivilegedAction<JmsConnectionContext> action = new PrivilegedAction<JmsConnectionContext>() {
@Override
public JmsConnectionContext run() {
try {
TopicConnectionFactory connectionFactory = (TopicConnectionFactory) context.lookup("TopicConnectionFactory");
TopicConnection topicConnection = connectionFactory.createTopicConnection();
int sessionId = Client.getSession().getSessionId();
topicConnection.setClientID("UMClient-" + sessionId);
TopicSession session = topicConnection.createTopicSession(false,
TopicSession.AUTO_ACKNOWLEDGE);
Topic jmsTopic = (Topic) context.lookup(topic);
TopicSubscriber subscriber = session.createDurableSubscriber(jmsTopic, topic + "-" +
sessionId);
subscriber.setMessageListener(new JmsTopicMessageListener());
topicConnection.start();
return new JmsConnectionContext(topic, topicConnection, session);
} catch(Exception e) {
logger.log(Level.SEVERE, "Topic creation and connection failed.", e);
return null;
}
}
};
return AccessController.doPrivileged(action);
我的JNDI属性配置非常简单:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming
java.naming.provider.url=10.1.3.143:1099
此外,所有罐子都是使用我们的公司证书签署的,该证书是通过CA发布的(将在未来几个月内到期,但仍然有效)。我还尝试清除javaws
缓存,以确保它不是过时的代码问题。
为什么警告仍然会出现?我将其作为特权操作运行,据我所知,应该只从JNLP文件中授予代码all-permissions
策略,但是在JNDI查找期间调用sun.rmi.transport.tcp.TCPChannel.checkConnectPermission()
时, JWS安全管理器会显示安全警告。我是否还需要为JNDI查找配置其他具有提升的连接权限的东西,我可以通过Java Web Start配置它吗?
更新
我还在处理这个问题。当我试图访问服务器上的RMI端口时,我将对话框缩小到了(它正在检查权限host:1098
)。我尝试将java.rmi.server.hostname
属性设置为host
,而不是this bug report中列出的解决方法。由于第一次RMI查找直到客户端已经启动之后才会发生,我认为我不需要找到通过<property>
将其添加到JNLP文件的方法。
这是我在安全警告中单击“取消”时的堆栈跟踪:
java.security.AccessControlException: access denied (java.net.SocketPermission 10.1.3.143:1098 connect,resolve)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkConnect(Unknown Source)
at com.sun.javaws.security.JavaWebStartSecurity.checkConnect(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.checkConnectPermission(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at org.jnp.server.NamingServer_Stub.lookup(Unknown Source)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:667)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:627)
at javax.naming.InitialContext.lookup(Unknown Source)
at org.jboss.naming.LinkRefPairObjectFactory.getObjectInstance(LinkRefPairObjectFactory.java:85)
at javax.naming.spi.NamingManager.getObjectInstance(Unknown Source)
at org.jnp.interfaces.NamingContext.getObjectInstance(NamingContext.java:1273)
at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1290)
at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1298)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:763)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:627)
at javax.naming.InitialContext.lookup(Unknown Source)
at com.ultramain.uui.jms.JmsHelper.jndiLookup(JmsHelper.java:145)
...
因此问题特定于RMI访问。为什么不设置主机名来修复对话框,如链接的错误报告和我发现的其他一些资源的变通方法中所建议的那样?还有其他解决方法可以解决这个问题吗?
答案 0 :(得分:0)
解决方案是一个很大的黑客,但这是我能找到的全部。
关闭信息here,JWS安全管理器没有将RMI代码列为可信代码,因为它是在单独的类加载器下加载的。由于代码不是来自JNLP,因此JWS不允许它以all-permissions
安全性运行。
对此的hacky修复只是用以下内容包装每个查找:
Topic topic = null;
SecurityManager prevSecurityManager = System.getSecurityManager();
try {
System.setSecurityManager(null);
topic = (Topic) context.lookup(name);
} finally {
System.setSecurityManager(prevSecurityManager);
}
将SecurityManager
设置为null
会绕过JWS安全管理器,让默认安全管理器接管。
最终,我想找到一种方法将RMI代码添加到JNLP的可信代码库中,但是这个解决方案可以在我们的开发环境和演示中使用,直到我能够做到这一点。这不是一种非常安全的处理方式,尤其是在可以像这样的多线程的应用程序中。它提供了一个没有安全管理器的小机会窗口,所以如果有人有一个允许我信任JNLP配置中的RMI代码的解决方案,发布它并且你的答案将被接受(当然它是有效的)。