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
 
     
     
    