4 Replies Latest reply on Jan 12, 2018 12:17 AM by v s

    JMS over SSL: Client starting STARTTLS but channel doesn't support SSL

    xiang yingbing Master

      Dear 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!