SSL
jbertram Feb 11, 2013 3:42 PMI was looking through the documentation and the code to figure out how to configure one-way SSL security using self-signed certs. In general this requires a self-signed certificate on the server stored in a keystore and a trust-store on the client into which the server's certificate has been imported. It shouldn't require a truststore on the server or a keystore on the client. This is the simplest and probably most common SSL use-case. However, this doesn't appear possible with current implementation because:
- If you configure Netty SSL connector/acceptor pair the server won't start unless you define a trust-store on the acceptor. Here's the configuration:
<acceptor name="netty-ssl">
<factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
<param key="host" value="localhost"/>
<param key="port" value="5500"/>
<param key="ssl-enabled" value="true"/>
<param key="key-store-path" value="hornetq.example.keystore"/>
<param key="key-store-password" value="hornetqexample"/>
</acceptor>
And here's the exception:
11:43:33,381 SEVERE [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-4) Failure in initialisation: java.lang.IllegalStateException: Unable to create NettyAcceptor for localhost:5500
at org.hornetq.core.remoting.impl.netty.NettyAcceptor.start(NettyAcceptor.java:344) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.remoting.server.impl.RemotingServiceImpl.start(RemotingServiceImpl.java:240) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.server.impl.HornetQServerImpl.initialisePart2(HornetQServerImpl.java:1495) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.server.impl.HornetQServerImpl.access$1200(HornetQServerImpl.java:138) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.server.impl.HornetQServerImpl$SharedStoreLiveActivation.run(HornetQServerImpl.java:1919) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.server.impl.HornetQServerImpl.start(HornetQServerImpl.java:366) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.jms.server.impl.JMSServerManagerImpl.start(JMSServerManagerImpl.java:277) [hornetq-jms-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.jboss.as.messaging.jms.JMSService.start(JMSService.java:73) [jboss-as-messaging-7.1.2.Final-redhat-1.jar:7.1.2.Final-redhat-1]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.2.GA-redhat-1.jar:1.0.2.GA-redhat-1]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.2.GA-redhat-1.jar:1.0.2.GA-redhat-1]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_13]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_13]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_13]
Caused by: java.lang.Exception: Failed to find a store at hornetq.truststore
at org.hornetq.core.remoting.impl.ssl.SSLSupport.validateStoreURL(SSLSupport.java:200) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.remoting.impl.ssl.SSLSupport.loadKeystore(SSLSupport.java:145) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.remoting.impl.ssl.SSLSupport.loadTrustManager(SSLSupport.java:129) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.remoting.impl.ssl.SSLSupport.createServerContext(SSLSupport.java:64) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
at org.hornetq.core.remoting.impl.netty.NettyAcceptor.start(NettyAcceptor.java:340) [hornetq-core-2.2.16.Final-redhat-1.jar:2.2.16.Final (HQ_2_2_16_FINAL, 122)]
... 12 more
- If you go ahead and define a trust-store on the acceptor the server will start, but the client will fail unless you define a keystore on the connector. Here's the configuration I tried:
<connector name="netty-ssl">
<factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class>
<param key="host" value="localhost"/>
<param key="port" value="5500"/>
<param key="ssl-enabled" value="true"/>
</connector>
And here's the exception on the client:
WARNING: connector.create or connectorFactory.createConnector should never throw an exception, implementation is badly behaved, but we'll deal with it anyway.
java.lang.IllegalStateException: Unable to create NettyConnector for localhost
at org.hornetq.core.remoting.impl.netty.NettyConnector.start(NettyConnector.java:342)
at org.hornetq.core.client.impl.ClientSessionFactoryImpl.getConnection(ClientSessionFactoryImpl.java:1136)
at org.hornetq.core.client.impl.ClientSessionFactoryImpl.getConnectionWithRetry(ClientSessionFactoryImpl.java:993)
at org.hornetq.core.client.impl.ClientSessionFactoryImpl.connect(ClientSessionFactoryImpl.java:224)
at org.hornetq.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:747)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnectionInternal(HornetQConnectionFactory.java:601)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnection(HornetQConnectionFactory.java:119)
at com.redhat.example.jms.PlainMessageSender.main(PlainMessageSender.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.Exception: Failed to find a store at hornetq.keystore
at org.hornetq.core.remoting.impl.ssl.SSLSupport.validateStoreURL(SSLSupport.java:200)
at org.hornetq.core.remoting.impl.ssl.SSLSupport.loadKeystore(SSLSupport.java:145)
at org.hornetq.core.remoting.impl.ssl.SSLSupport.loadKeyManagers(SSLSupport.java:168)
at org.hornetq.core.remoting.impl.ssl.SSLSupport.createClientContext(SSLSupport.java:73)
at org.hornetq.core.remoting.impl.ssl.SSLSupport.getInstance(SSLSupport.java:87)
at org.hornetq.core.remoting.impl.netty.NettyConnector.start(NettyConnector.java:337)
... 12 more
- There no way to define a trust-store on the client. The connector doesn't support "trust-store-path" or "trust-store-password" parameters, and it doesn't obey the universal "javax.net.ssl.trustStore" and "trustStorePassword" Java system properties either.
As noted previously, I don't believe either of these artifacts should be required for this use-case. As I understand it, a server-side truststore and a client-side keystore should only be required when performing 2-way SSL (i.e. mutual authentication). We should definitely support 2-way SSL, but that support shouldn't complicate the configuration for 1-way SSL.
I can do the work to implement this, but I wanted to make sure my understanding here is correct on all points.