9 Replies Latest reply on Aug 1, 2013 2:04 PM by Alexis Hassler

    JMS security with local queues

    Alexis Hassler Apprentice

      I would like to add security to local JMS queues. In my web application, only authenticated users, with a defined role, should be authorized to access to the JMS queue.

       

      I created the queue :

      <jms-destinations>
          <jms-queue name="SwQueue">
              <entry name="java:/queue/SwQueue"/>
              <durable>true</durable>
          </jms-queue>
      </jms-destinations>
      

       

      Then I've setup the security settings :

      <security-settings>
          <security-setting match="jms.queue.SwQueue">
              <permission type="send" roles="foo-role"/>
              <permission type="consume" roles="foo-role"/>
          </security-setting>
      </security-settings>
      

       

      Unfortunately, that doesn't seem to be sufficient, as all user (even anonymous ones) can send messages to the queue. What did I miss ? (I'm working with JBoss AS 7.2.0)

       

      PS :

      I'm creating the JMS connection with

          connectionFactory.createConnection();
      

      When I pass explicit username and password, security is working fine

          connectionFactory.createConnection("alexis", "hassler")
      
        • 1. Re: JMS security with local queues
          xiang yingbing Master

          My example ( works well) in standalone.xml:

           


          <subsystem xmlns="urn:jboss:domain:messaging:1.3">

          <hornetq-server>

          <persistence-enabled>true</persistence-enabled>

          <security-domain>nms-jaas-security-domain</security-domain>

          <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="client.truststore"/>

          <param key="key-store-password" value="ybxiang_truststore_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="admin jms_sender"/>

          <permission type="consume" roles="admin jms_consumer"/>

          <permission type="createDurableQueue" roles="admin jms_DurableQueue_creator"/>

          <permission type="deleteDurableQueue" roles="jms_DurableQueue_killer admin"/>

          <permission type="createNonDurableQueue" roles="admin jms_NonDurableQueue_creator"/>

          <permission type="deleteNonDurableQueue" roles="jms_NonDurableQueue_killer admin"/>

          </security-setting>

          </security-settings>

           


          <address-settings>

          <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-topic name="nmsSOETopic">

          <entry name="topic/nmsSOE"/>

          <entry name="java:jboss/exported/jms/topic/nmsSOE"/>

          </jms-topic>

          </jms-destinations>

          </hornetq-server>

          </subsystem>
          • 2. Re: JMS security with local queues
            xiang yingbing Master

            NOTE:

            if you do NOT set the security domain, it will use "other" by default, so your roles defined in your special doman will NOT work here.

            • 3. Re: JMS security with local queues
              Alexis Hassler Apprentice

              Thanks for your help.

               

              How your clients do connect to JMS ? With connectionFactory.createConnection() or connectionFactory.createConnection(username, password) ? And are non authorized in-vm client effectively rejected ?

              • 4. Re: JMS security with local queues
                xiang yingbing Master

                My code working well:

                 

                 

                ********************************************************************************

                 

                private static ConnectionFactory jmsConnectionFactory = null;
                
                //
                
                private static Connection  
                jmsConnection = null;
                
                private static Session     
                jmsSession = null;
                
                //
                
                private static Destination 
                jmsDestination_topic_nmsSOE = null;
                
                private static MessageConsumer jmsConsumer_topic_nmsSOE = null;
                
                //
                
                private static Destination 
                jmsDestination_queue_test = null;
                
                private static MessageConsumer jmsConsumer_queue_test = null;
                
                private static MessageProducer jmsProducer_queue_test = null;
                
                
                
                
                
                private void initJmsResource(String serverIP, String username, String password)throws Exception {
                    
                Properties props = new Properties();
                    
                props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                
                
                //参见:https://community.jboss.org/message/729801#729801
                    
                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);
                    
                props.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_STARTTLS", "true");
                    
                props.put("jboss.naming.client.remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "true");
                    
                //
                    
                InitialContext jmsInitialContext = new InitialContext(props);
                    
                
                    
                jmsConnectionFactory = (ConnectionFactory) jmsInitialContext.lookup("jms/RemoteConnectionFactory");
                
                
                //jmsConnection = connectionFactory.createConnection();//"javax.jms.JMSSecurityException: Unable to validate user: null"
                
                
                jmsConnection = jmsConnectionFactory.createConnection(username,password);
                    
                jmsSession = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                    
                //
                    
                //jms/topic/nmsSOE
                    
                {
                    
                
                jmsDestination_topic_nmsSOE = (Destination) jmsInitialContext.lookup("jms/topic/nmsSOE");
                        
                jmsConsumer_topic_nmsSOE = jmsSession.createConsumer(jmsDestination_topic_nmsSOE);
                    
                }
                    
                //jms/queue/test
                    
                {
                    
                
                jmsDestination_queue_test = (Destination) jmsInitialContext.lookup("jms/queue/test");
                    
                
                jmsConsumer_queue_test = jmsSession.createConsumer(jmsDestination_queue_test);
                    
                
                jmsProducer_queue_test = jmsSession.createProducer(jmsDestination_queue_test);
                    
                }
                    
                //
                    
                jmsConnection.start();
                    
                //
                    
                testJmsQueue();
                    
                //
                    
                initSoeJmsListener();
                
                }
                
                
                
                
                
                /**
                 
                * https://community.jboss.org/message/721270
                 
                * Like everything else in JBoss AS 7.1.0.Final, JMS is secured by default.  
                 
                * It uses the same security domain as JNDI so you can use the same username and password (i.e. appuser2 and passw0rd respectively) 
                 
                * 
                
                in your call to javax.jms.ConnectionFactory.createConnection(String, String). 
                 
                */
                
                private void testJmsQueue(){
                    
                try {
                    
                
                TextMessage message = null;
                        
                int count = 1;
                        
                String content = "Hellow World from client!";
                        
                log.info("Sending " + count + " messages to [jms/queue/test] with content: " + content);
                
                
                        
                //发送测试
                        
                for (int i = 0; i < count; i++) {
                            
                message = jmsSession.createTextMessage(content);
                            
                jmsProducer_queue_test.send(message);
                        
                }
                        
                //接收测试
                        
                for (int i = 0; i < count; i++) {
                            
                message = (TextMessage) jmsConsumer_queue_test.receive(1000);
                            
                if(message==null){
                            
                
                log.warn("1秒之内没有收到消息,该队列[jms/queue/test]中的消息可能已经被MDB接收!");
                            
                }else{
                            
                
                log.info("Received message with content " + message.getText());
                            
                }
                        
                }
                    
                } catch (Exception e) {
                        
                log.error(e);
                    
                }
                
                }
                
                
                
                
                
                public static final String ATTR_SOE_NOTIFICATION = "ATTR_SOE_NOTIFICATION";
                
                private void initSoeJmsListener(){
                
                
                try {
                
                
                
                jmsConsumer_topic_nmsSOE.setMessageListener(new MessageListener(){
                
                
                
                
                @Override
                
                
                
                
                public void onMessage(Message msg) {
                
                        
                
                try{
                
                        
                
                
                if(msg==null){
                
                        
                
                
                
                //log.warn("没有收到SOE消息...");//不可能
                
                        
                
                
                }else if(msg instanceof ObjectMessage){
                
                                    
                ObjectMessage objectMessage = (ObjectMessage) msg;
                
                                    
                fireSoeListeners(objectMessage); 
                
                                    
                //log.warn("Global SOE JMS 消息 Ne["+objectMessage.getStringProperty(Afn0E.SOE_STRING_PROPERTY_KEY_SOCKETDATA_ADDRESS_HEX)+"]:"+objectMessage);
                
                        
                
                
                }else{
                
                        
                
                
                
                log.warn("SOE JMS 消息应该是ObjectMessage类型!");
                
                        
                
                
                }
                
                        
                
                }catch(Exception exp){
                
                        
                
                
                log.error(exp);
                
                        
                
                }
                
                
                
                
                }
                
                    
                });
                    
                } catch (Exception e) {
                        
                log.error(e);
                    
                }
                
                }
                
                private void fireSoeListeners(ObjectMessage objectMessage){
                
                
                firePropertyChange(ATTR_SOE_NOTIFICATION,null,objectMessage);
                
                }
                
                }
                
                
                private void clearJmsResource(){
                
                
                //jms/queue/test
                
                
                try{if(jmsConsumer_queue_test!=null){jmsConsumer_queue_test.close();}}catch(Exception e){}
                
                
                try{if(jmsProducer_queue_test!=null){jmsProducer_queue_test.close();}}catch(Exception e){}
                
                
                //jms/topic/nmsSOE
                
                
                try{if(jmsConsumer_topic_nmsSOE!=null){jmsConsumer_topic_nmsSOE.close();}}catch(Exception e){}
                
                
                //global resource
                
                
                try{if(jmsSession!=null){jmsSession.close();}}catch(Exception e){}
                
                
                try{if(jmsConnection!=null){jmsConnection.close();}}catch(Exception e){}
                
                }
                
                
                • 5. Re: JMS security with local queues
                  Alexis Hassler Apprentice

                  OK that's clear for me now. You're using jmsConnectionFactory.createConnection(username,password). In my case, I would like to call jmsConnectionFactory.createConnection() and propagate the Web login to the JMS container.

                   

                  Anyway, thanks for your help.

                   

                  Anyone else for a tip for securing my queues with jmsConnectionFactory.createConnection() ?

                  • 6. Re: JMS security with local queues
                    Justin Bertram Master

                    Couple of points...

                     

                    1. To my knowledge, security is not enforced on in-vm JMS connections.  If you want security enforced for an application running in the same JVM then use a connection factory which doesn't use an in-vm connector.
                    2. No matter what your settings are I don't believe createConnection() will simply inherit the security context from the web login.  As I understand it, JMS 1.1 only supports plain username and password for security.
                    1 of 1 people found this helpful
                    • 7. Re: JMS security with local queues
                      Alexis Hassler Apprentice

                      Thanks for your answer Justin. That's useful.

                       

                      The javadoc of javax.jms.ConnectionFactory.createConnection() says

                      Creates a connection with the default user identity.

                      which could probably have different interpretation.

                       

                      Sadly, I don't see any workaround to propagate identity

                      • 8. Re: JMS security with local queues
                        xiang yingbing Master

                        Your case is really strange.

                         

                        JMS client is NOT boundled to (web) app, it can works alone.

                        Why NOT pass your username and password to your JMS connection factory AFTER your login instead of BEFORE login?

                        • 9. Re: JMS security with local queues
                          Alexis Hassler Apprentice

                          I'm convinced that my case is not strange at all.

                           

                          The JMS connection is create after the login but the password is treated in the security-domain and not in the web-app. I have no idea of the passwords in the app.