Version 36

    Overview

    This wiki outlines the various steps required to secure a remote connection to JBossMQ using SSL.

     

    The code, build script and configuration files are all attached at the bottom of this page

     

    Setup

     

    Grab a copy of a JBossAS 4.x release and create two new server configurations (based on /default) named respectively /jmsprovider and /client

     

    Provider configuration

     

    Step 1: Generate a private-public key pair using keytool

     

        $ ./j2sdk1.4.2_07/bin/keytool -genkey -alias sslmq -keyalg RSA -keystore sslmq.keystore
        Enter keystore password:  jbossmq
        What is your first and last name?
          [Unknown]:  www.myhost.com
        What is the name of your organizational unit?
          [Unknown]:  Some dot com
        What is the name of your organization?
          [Unknown]:  Security
        What is the name of your City or Locality?
          [Unknown]:  SomeCity
        What is the name of your State or Province?
          [Unknown]:  Washington
        What is the two-letter country code for this unit?
          [Unknown]:  US
        Is CN=www.myhost.com, OU=Some dot com, O=Security, L=SomeCity, ST=Washington, C=US correct?
          [no]:  yes
    
        Enter key password for <jbossmq>
                (RETURN if same as keystore password):
    

     

      And copy sslmq.keystore to /server/jmsprovider/conf

     

     

     

    Step 2: Create a JAAS security domain that uses sslmq.keystore

     

      Create a new MBean configuration ssl-domain-service.xml (see the attached example) and save it in /server/jmsprovider/deploy

    
       <?xml version="1.0" encoding="UTF-8"?>
    
       <server>
           <mbean code="org.jboss.security.plugins.JaasSecurityDomain"
               name="jboss.security:service=JaasSecurityDomain,domain=SSL">
    
               <constructor>
                   <arg type="java.lang.String" value="SSL"></arg>
               </constructor>
    
               <attribute name="KeyStoreURL">resource:sslmq.keystore</attribute>
               <attribute name="KeyStorePass">jbossmq</attribute>
           </mbean>
       </server>
       
    

     

     

     

    Step 3: Create a new UIL2 deployment descriptor ssl-uil2-service.xml and save it in /server/jmsprovider/deploy/jms

     

       <?xml version="1.0" encoding="UTF-8"?>
    
       <server>
           <mbean code="org.jboss.mq.il.uil2.UILServerILService"
               name="jboss.mq:service=InvocationLayer,type=SSLUIL2">
               <depends optional-attribute-name="Invoker">jboss.mq:service=Invoker</depends>
               <attribute name="ConnectionFactoryJNDIRef">SSLUIL2ConnectionFactory</attribute>
               <attribute name="XAConnectionFactoryJNDIRef">SSLUIL2XAConnectionFactory</attribute>
               <!-- The bind address -->
               <attribute name="BindAddress">${jboss.bind.address}</attribute>
               <attribute name="ServerBindPort">8193</attribute>
               <attribute name="PingPeriod">60000</attribute>
               <attribute name="EnableTcpNoDelay">true</attribute>
               <!-- Used to disconnect the client if there is no activity -->
               <!-- Ensure this is greater than the ping period -->
               <attribute name="ReadTimeout">70000</attribute>
               <!-- The size of the buffer (in bytes) wrapping the socket -->
               <!-- The buffer is flushed after each request -->
               <attribute name="BufferSize">2048</attribute>
               <!-- Large messages may block the ping/pong -->
               <!-- A pong is simulated after each chunk (in bytes) for both reading and writing -->
               <!-- It must be larger than the buffer size -->
               <attribute name="ChunkSize">1000000</attribute>
               <attribute name="ClientSocketFactory">org.jboss.security.ssl.ClientSocketFactory</attribute>
               <attribute name="ServerSocketFactory">org.jboss.security.ssl.DomainServerSocketFactory</attribute>
               <attribute name="SecurityDomain">java:/jaas/SSL</attribute>
           </mbean>
       </server>  
    

     

     

    Client configuration

     

    Step 1: Create JMS client

     

    The JMS client code is embedded in an MBean called JBossService. It has got a RW property ProviderURL that stores the IpAddress:[Port|port] of the remote provider. Its default value can be changed in jboss-service.xml or updated on the fly using the jmx console.

     

    
       public void sendMessages() throws NamingException, JMSException
       {
           log.info("sending JMS message to queue bound to JNDI name: "+QUEUE_NAME);
    
          Properties properties = new Properties();
    
          properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
          properties.put(Context.URL_PKG_PREFIXES, "org.jnp.interfaces");
          properties.put(Context.PROVIDER_URL, providerURL);
          InitialContext ctx = new InitialContext(properties);
    
          connectionFactory = (ConnectionFactory)ctx.lookup("SSLUIL2ConnectionFactory");
    
          queue = (Destination)ctx.lookup(QUEUE_NAME);
    
          connection = connectionFactory.createConnection();
    
          session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
    
          producer = session.createProducer(queue);
    
          for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
          {
             Message m = session.createObjectMessage(new Integer(i));
    
             producer.send(m);
          }
    
          session.commit();
    
          log.info(NUMBER_OF_MESSAGES + " messages sent to " +providerURL);
       }
    
    
    

     

    Notice the JNDI name of the ConnectionFactory (configured in /server/jmsprovider/ssl-uil2-service.xml)

     

     

    Step 2: Create the truststore for the client

     

      When an SSL client connects to an SSL server, it receives a certificate of authentication from the server. The client then validates the certificate against a set of certificates in its truststore.

     

        Create the certificate
        $ ./j2sdk1.4.2_07/bin/keytool -export -alias sslmq -keystore sslmq.keystore -rfc -file provider.cer
        Enter keystore password:  jbossmq
    
    
        Import this certificate into a client truststore
        $ ./j2sdk1.4.2_07/bin/keytool -import -alias sslmq -file provider.cer -keystore client.truststore
        Enter keystore password:  jbossmq
      
    

     

    Copy client.truststore to /server/client/conf

     

    We now ready to set the location of the client truststore using two JVM properties; javax.net.ssl.truststore and javax.net.ssl.trustStorePassword. Since we are running 2 servers out of the same installation, we should not set them globally in run.bat or run.sh/run.conf. Instead we use the Properties service.

     

      Edit /server/client/deploy/properties-service.xml and add the following to the 'jboss:type=Service,name=SystemProperties' MBean:

     

        <attribute name="Properties">
    
              javax.net.ssl.trustStore=../server/client/conf/client.truststore 
              javax.net.ssl.trustStorePassword=jbossmq 
    
        </attribute>
    

     

    Note: in run.conf it would translate into

     #JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=$JBOSS_HOME/server/client/conf/client.truststore -Djavax.net.ssl.trustStorePassword=jbossmq"
    

     

     

    Test

     

    Step 1: Compile and deploy

     

    From the attachment section download the archive jmsssl.zip, explode it in the same directory where you put JBossAS then point a command line to the /build directory. Note: Make sure to change the jboss.bundle.dir property.

     

        $ ./src/build/ant -f build.xml

     

    In /server/client/deploy, you should have now a SAR archive named jmsssl.sar

     

    Step 2: Have fun

     

    If you are testing on the same pc, I recommend configuring 2 static ip addresses and binding a JBossAS instance to each one using the option --host=xxx.xxx.xxx.xxx (or -b).

     

    So for instance to start the "provider" you would use

      $ sh ./bin/run.sh -c jmsprovider -b 192.168.4.151
    

    and this for the client

      $ sh ./bin/run.sh -c client -b 192.168.4.150
    

     

    To execute the client code, open the jmx console, find the service JBossService in the JMSSSL domain.

    Scroll down and invoke the go() operation. In the client log, you should see the following:

     21:52:07,906 INFO  [JMSSSL:name=JBossService] sending JMS message to queue bound to JNDI name: queue/A
     21:52:08,031 INFO  [JMSSSL:name=JBossService] 5 messages sent to 192.168.4.151:1099
    

    In another web browser, open the jmx console and check the size of Queue A (name=A,service=Queue in the jboss.mq.destination domain)

    The attribute QueueDepth is now 5 (was zero previously). To see what those messages look like, you may invoke the operation listMessages located further down in the page.

     

     

    Common problems

     

       Coming soon...

     

    I want to use SSL to "authenticate" the client?

     

    Typically, only the client authenticates the server with SSL.

     

    You would need your own

    SSLServerSocketFactory

    as JBoss's org.jboss.security.ssl.DomainServerSocketFactory does not perform or allow this configuration

     

    Resources