JMS over SSL: Client starting STARTTLS but channel doesn't support SSL
ybxiang.china Oct 5, 2012 3:02 AMDear jboss guys,
My client has a problem about JMS over SSL: Client starting STARTTLS but channel doesn't support SSL.
Please help me.
Thank you in advance.
1. standalone.xml
I copied standalone-full.xml to standalone.xml, then modifed it.
Please refer to the attachment for details.
I post management and JMS related configuration here:
| <management> | |
| <security-realms> | |
| <security-realm name="ManagementRealm"> | |
| <authentication> | |
| <local default-user="$local"/> | |
| <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/> | |
| </authentication> | |
| </security-realm> | |
| <security-realm name="ApplicationRealm"> | |
| <server-identities> | |
| <ssl> | |
| <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="ybxiang_keystore_password"/> | |
| </ssl> | |
| </server-identities> | |
| <authentication> | |
| <jaas name="nms-jaas-security-domain"/> | |
| </authentication> | |
| </security-realm> | |
| </security-realms> | |
| <management-interfaces> | |
| <native-interface security-realm="ManagementRealm"> | |
| <socket-binding native="management-native"/> | |
| </native-interface> | |
| <http-interface security-realm="ManagementRealm"> | |
| <socket-binding http="management-http"/> | |
| </http-interface> | |
| </management-interfaces> | |
| </management> |
...
| <subsystem xmlns="urn:jboss:domain:messaging:1.3"> | ||||||
| <hornetq-server> | ||||||
| <persistence-enabled>true</persistence-enabled> | ||||||
| <journal-file-size>102400</journal-file-size> | ||||||
| <journal-min-files>2</journal-min-files> | ||||||
| <connectors> | ||||||
| <netty-connector name="netty-ssl-connector" socket-binding="messaging"> | ||||||
| <param key="ssl-enabled" value="true"/> | ||||||
| <param key="key-store-path" value="server.keystore"/> | ||||||
| <param key="key-store-password" value="ybxiang_keystore_password"/> | ||||||
| </netty-connector> | ||||||
| <netty-connector name="netty-throughput" socket-binding="messaging-throughput"> | ||||||
| <param key="batch-delay" value="50"/> | ||||||
| </netty-connector> | ||||||
| <in-vm-connector name="in-vm" server-id="0"/> | ||||||
| </connectors> | ||||||
| <acceptors> | ||||||
| <netty-acceptor name="netty-ssl-acceptor" socket-binding="messaging"> | ||||||
| <param key="ssl-enabled" value="true"/> | ||||||
| <param key="key-store-path" value="server.keystore"/> | ||||||
| <param key="key-store-password" value="ybxiang_keystore_password"/> | ||||||
| <param key="trust-store-path" value="client.truststore"/> | ||||||
| <param key="trust-store-password" value="ybxiang_truststore_password"/> | ||||||
| </netty-acceptor> | ||||||
| <netty-acceptor name="netty-throughput" socket-binding="messaging-throughput"> | ||||||
| <param key="batch-delay" value="50"/> | ||||||
| <param key="direct-deliver" value="false"/> | ||||||
| </netty-acceptor> | ||||||
| <in-vm-acceptor name="in-vm" server-id="0"/> | ||||||
| </acceptors> | ||||||
| <security-settings> | ||||||
| <security-setting match="#"> | ||||||
| <permission type="send" roles="guest"/> | ||||||
| <permission type="consume" roles="guest"/> | ||||||
| <permission type="createNonDurableQueue" roles="guest"/> | ||||||
| <permission type="deleteNonDurableQueue" roles="guest"/> | ||||||
| </security-setting> | ||||||
| </security-settings> | ||||||
| <address-settings> | ||||||
| <!--default for catch all--> | ||||||
| <address-setting match="#"> | ||||||
| <dead-letter-address>jms.queue.DLQ</dead-letter-address> | ||||||
| <expiry-address>jms.queue.ExpiryQueue</expiry-address> | ||||||
| <redelivery-delay>0</redelivery-delay> | ||||||
| <max-size-bytes>10485760</max-size-bytes> | ||||||
| <address-full-policy>BLOCK</address-full-policy> | ||||||
| <message-counter-history-day-limit>10</message-counter-history-day-limit> | ||||||
| </address-setting> | ||||||
| </address-settings> | ||||||
| <jms-connection-factories> | ||||||
| <connection-factory name="InVmConnectionFactory"> | ||||||
| <connectors> | ||||||
| <connector-ref connector-name="in-vm"/> | ||||||
| </connectors> | ||||||
| <entries> | ||||||
| <entry name="java:/ConnectionFactory"/> | ||||||
| </entries> | ||||||
| </connection-factory> | ||||||
| <connection-factory name="RemoteConnectionFactory"> | ||||||
| <connectors> | ||||||
| <connector-ref connector-name="netty-ssl-connector"/> | ||||||
| </connectors> | ||||||
| <entries> | ||||||
| <entry name="java:jboss/exported/jms/RemoteConnectionFactory"/> | ||||||
| </entries> | ||||||
| </connection-factory> | ||||||
| <pooled-connection-factory name="hornetq-ra"> | ||||||
| <transaction mode="xa"/> | ||||||
| <connectors> | ||||||
| <connector-ref connector-name="in-vm"/> | ||||||
| </connectors> | ||||||
| <entries> | ||||||
| <entry name="java:/JmsXA"/> | ||||||
| </entries> | ||||||
| </pooled-connection-factory> | ||||||
| </jms-connection-factories> | ||||||
| <jms-destinations> | ||||||
| <jms-queue name="testQueue"> | ||||||
| <entry name="queue/test"/> | ||||||
| <entry name="java:jboss/exported/jms/queue/test"/> | ||||||
| </jms-queue> | ||||||
| <jms-topic name="testTopic"> | ||||||
| <entry name="topic/test"/> | ||||||
| <entry name="java:jboss/exported/jms/topic/test"/> | ||||||
| </jms-topic> | ||||||
| </jms-destinations> | ||||||
| </hornetq-server> | ||||||
| </subsystem> |
2. I put client.truststore and server.keystore in both
jboss-as-7.2.0.Alpha1\standalone\configuration (for ApplicationRealm)
and
jboss-as-7.2.0.Alpha1\bin (for messaging)
3. I can send message through an ejb and receive it through an MDB successfully:
@Local(ITestQueueSender.class)
@Singleton
@Startup
public class TestQueueSender implements ITestQueueSender {
Logger log = Logger.getLogger(TestQueueSender.class);
@SuppressWarnings("unused")
@Resource
private SessionContext sessionContext;
@Resource
TimerService timerService;
@PersistenceContext
protected EntityManager em;
@PostConstruct
public void createTimer() {
log.info("==>starting TestQueueSender timer...");
timerService.createIntervalTimer(15000L,
3600000,// intervalDuration
new TimerConfig(null, false)
);
log.info("==>timer TestQueueSender started!!!");
}
@Timeout
public void timeout() {
try {
sendMessageMethod1();
} catch (Exception e) {
log.error(e);
}
}
private void sendMessageMethod1() {
Context context = null;
ConnectionFactory connectionFactory = null;
Connection connection = null;
//
try {
context = new InitialContext();
/**
* 如何获取JBoss 7 中的连接工厂,请参见:
* http://stackoverflow.com/questions/7515220/how-to-get-the-new-jndi-names-esp-connectionfactory
*/
connectionFactory = (ConnectionFactory) context.lookup("java:/ConnectionFactory");
Queue queue = (Queue) context.lookup("queue/test");
connection = connectionFactory.createConnection();
Session session = connection.createSession(
false,//transacted
Session.AUTO_ACKNOWLEDGE);
MessageProducer publisher = session.createProducer(queue);
connection.start();
String message = "Hello AS 7(method1) !";
TextMessage textMessage = session.createTextMessage(message);
publisher.send(textMessage);
log.info("Message is sent: "+message);
} catch (Exception exc) {
exc.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
}
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/test"),
//@ActivationConfigProperty(propertyName="messageSelector",propertyValue="MessageFormat = 'Version 3.4'"),
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")
}
)
public class TestQueueMDB implements MessageListener {
Logger log = Logger.getLogger(TestQueueMDB.class);
@PostConstruct
public void init() {
//log.info("TestQueueMDB.init...");
}
@PreDestroy
public void cleanup( ) {
//log.info("TestQueueMDB.cleanup...");
}
@Override
public void onMessage(Message message) {
TextMessage tm = (TextMessage) message;
try {
System.out.println("Received message " + tm.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
After JBoss AS is started, It print bellow log:
14:34:35,484 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.2.0.Alpha1-SNAPSHOT "Steropes" started in 13797ms - Started 538 of 627 services (87 services are passive or on-demand) 14:34:48,046 INFO [com.ybxiang.nms.ejb.jms.demo.TestQueueSender] (EJB default - 3) Message is sent: Hello AS 7(method1) ! 14:34:48,078 INFO [stdout] (Thread-1 (HornetQ-client-global-threads-4846268)) Received message Hello AS 7(method1) !
This mean my JMS configuration is correct.
4. But now, my client can NOT find "jms/RemoteConnectionFactory" successfully.
4.1 My client code:
public class MyClient{
...
public void connectToServer(String serverIP, String username, String password) throws Exception{
this.username = username;
this.serverIP = serverIP;
InitialContext context;
try{
Properties p = new Properties();
p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "true");
p.put("remote.connections", "default");
p.put("remote.connection.default.host", serverIP);
p.put("remote.connection.default.port", "4447");
p.put("remote.connection.default.username", username);
p.put("remote.connection.default.password", password);
p.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
p.put("remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS", "JBOSS-LOCAL-USER");
p.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
p.put("remote.connection.default.connect.options.org.xnio.Options.SSL_STARTTLS", "true");
p.put("remote.connection.default.connect.timeout", "30000");//for xnio
EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);
EJBClientContext.getCurrent().registerInterceptor(0,new ClientSessionTokenInterceptor());
EJBClientContext.getCurrent().registerInterceptor(1,new ClientExceptionInterceptor());
Properties props = new Properties();
props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
context = new InitialContext(props);
securedRemoteSessionProxy = (ISecuredRemoteSession)context.lookup(jndiName);
}catch(Exception e){
throw ConnectionToServerFailedException.INSTANCE;
}
shakeHands(username, password);//fetch initial data from server.
testJms2(context,username,password);
}
public static void testJms2(InitialContext context, String username, String password) throws Exception {
ConnectionFactory connectionFactory = null;
Destination destination = null;
try {
connectionFactory = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
destination = (Destination) context.lookup("jms/queue/test");
//
sendJmsMessage(connectionFactory,destination,username,password);
} catch (Exception e) {
log.error(e);
}
}
public static void sendJmsMessage(ConnectionFactory connectionFactory, Destination destination, String username, String password){
Connection connection = null;
Session session = null;
MessageProducer producer = null;
MessageConsumer consumer = null;
TextMessage message = null;
try {
// Create the JMS connection, session, producer, and consumer
connection = connectionFactory.createConnection(username,password);
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
consumer = session.createConsumer(destination);
connection.start();
int count = 1;
String content = "Hellow World!";
log.info("Sending " + count + " messages with content: " + content);
// Send the specified number of messages
for (int i = 0; i < count; i++) {
message = session.createTextMessage(content);
producer.send(message);
}
// Then receive the same number of messaes that were sent
for (int i = 0; i < count; i++) {
message = (TextMessage) consumer.receive(5000);
log.info("Received message with content " + message.getText());
}
} catch (Exception e) {
log.error(e);
} finally {
if (connection != null) {
try{
connection.close();
}catch(Exception e){
log.error(e);
}
}
}
}
}
VM arguments:
-Djavax.net.ssl.trustStore=D:\\java\\jboss-as-7.2.0.Alpha1\\standalone\\configuration\\client.truststore -Djavax.net.ssl.trustStorePassword=ybxiang_truststore_password
The client can fetch initial data though EJB calling from the jboss as successfully.
But it can NOT find the jms connection factory:
"javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial"
Now, I change
| Properties props = new Properties(); | ||
| props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); | ||
| context = new InitialContext(props); |
to
| Properties props = new Properties(); | ||
| props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); | ||
| props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory"); | ||
| props.put(Context.PROVIDER_URL, System.getProperty(Context.PROVIDER_URL, "remote://"+serverIP+":4447")); | ||
| props.put(Context.SECURITY_PRINCIPAL, username); | ||
| props.put(Context.SECURITY_CREDENTIALS, password); | ||
| context = new InitialContext(props); |
This time, I got bellow Exception:
org.jboss.remoting.remote.connection: "JBREM000200: Remote connection failed: java.io.IOException: Client starting STARTTLS but channel doesn't support SSL" "javax.naming.NamingException: Failed to connect to any server. Servers tried: [remote://192.168.1.100:4447]"
I think there is something wrong with my client code.
Would you please help me to fix it???
Thank you VERY much!!!
I do need JMS client function!
-
standalone.xml 26.7 KB