5 Replies Latest reply on Jul 23, 2010 11:35 AM by Peter Johnson

    Securing JBoss Messaging and EJB3

    Alexander Hartner Expert

      I would like to ensure all access to any JMS destination is authenticated so I disabled the guest account in messaging-service.xml

       

            <attribute name="DefaultSecurityConfig">
              <security>
                  <role name="jmsuser" read="true" write="true" create="true"/>
              </security>
            </attribute>

      I then added a new users to messaging-roles.properties and messaging-users.properties.

       

      Now my problem is how can I get my application to access the queues. I am using EJB3 annotations as well as dependency injection for the connection factory and destinations. I was hoping to link the entire application to an application-policy specified in login-config.xml using something like this, in a similar way passwords are set on datasources:

       

          <application-policy name="EncryptJMSPassword">

              <authentication>

                  <login-module code="org.jboss.resource.security.SecureIdentityLoginModule" flag="required">

                      <module-option name="username"> jmsuser </module-option>

                      <module-option name="password">XXXXXXXXXXXXXXXXXXXXXXXXX</module-option>

                  </login-module>

              </authentication>

          </application-policy>

      and then to specify the policyname in either jboss.xml or jboss-app.xml. However I haven't found a way of doing this. I did get the application deployed using :

                  <activation-config>

                     <activation-config-property>

                         <activation-config-property-name>user</activation-config-property-name>

                         <activation-config-property-value> jmsuser </activation-config-property-value>

                     </activation-config-property>

                     <activation-config-property>

                         <activation-config-property-name>password</activation-config-property-name>

                         <activation-config-property-value>jmspassword</activation-config-property-value>

                     </activation-config-property>

                 </activation-config>

      in ejb-jar.xml, however this only addresses the reading of messages from a queue, I believe. It also has to be done on each bean which is not ideal and not very flexible as the password is hard coded inside the ear.

       

      Are there any more elegant options of granting one application unrestricted access to any JMS resources.

       

      Without specifying these I am getting the following error message during startup:

      javax.jms.JMSSecurityException: User: null is not authorized to read from destination TransactionJobs

              at org.jboss.jms.server.container.SecurityAspect.check(SecurityAspect.java:312)

              at org.jboss.jms.server.container.SecurityAspect.handleCreateConsumerDelegate(SecurityAspect.java:112)

      as well as:

      20:04:43,097 FATAL [ConfigurationMonitor] Authentication failure

      javax.ejb.EJBAccessException: Authentication failure

              at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.handleGeneralSecurityException(Ejb3AuthenticationInterceptor.java:68)

              at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:70)

              at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:110)

        • 1. Re: Securing JBoss Messaging and EJB3
          Alexander Hartner Expert

          I made some progress and added the mdbuser  / mdbpassword in the jboss.xml file

           

                  <message-driven>
                      <ejb-name>JobRequestListener</ejb-name>
                      <destination-jndi-name>queue/abc/JobRequests</destination-jndi-name>
                      <mdb-user>jmsuser</mdb-user>
                      <mdb-passwd>password</mdb-passwd>

           

          So now I am able to receive messages in my MDB. However any injected resources also need to be authenticated. This is not very nice as I have to include the password in the deployment descriptor as well as the application itself. I am hoping that there is an elegant way of granting the entire EAR application access to read and write to JMS destination and to be able to specify the user credentials outside the application and reference a security policy.

           

          Thanks for your help.

          Alex

          • 2. Re: Securing JBoss Messaging and EJB3
            Alexander Hartner Expert

            I found some other posts dating back some time but none of them seem to have a solution either

             

            http://community.jboss.org/message/147049#147049

             

            http://community.jboss.org/message/156429#156429

             

            The first post seems to suggest that adding a configured identity to the connection factory configuration may get around this issue. Does that mean I can set a reference to a login-module on the connection factory ?

             

             


            • 3. Re: Securing JBoss Messaging and EJB3
              Alexander Hartner Expert

              I added a abc-jms-ds.xml file to my ear in which i define a JMS Provider and two connection factories, one with XA/TX support and one without

               

              <?xml version="1.0" encoding="UTF-8"?>

              <connection-factories>

               

              <!-- The JMS provider loader -->

                <mbean code="org.jboss.jms.jndi.JMSProviderLoader"

                   name="jboss.messaging:service=JMSProviderLoader,name=ABCJMSProvider">

                  <attribute name="ProviderName">ABCJMSProvider</attribute>

                  <attribute name="ProviderAdapterClass">

                    org.jboss.jms.jndi.JNDIProviderAdapter

                  </attribute>

                  <!-- The combined connection factory -->

                  <attribute name="FactoryRef">jms/ABCJMSConnectionFactoryNoTX</attribute>

                  <!-- The queue connection factory -->

                  <attribute name="QueueFactoryRef">jms/ABCJMSConnectionFactoryNoTX</attribute>

                  <!-- The topic factory -->

                  <attribute name="TopicFactoryRef">jms/ABCJMSConnectionFactoryNoTX</attribute>

                  <!-- Access JMS via HAJNDI -->

                  <attribute name="Properties">

                     java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory

                     java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

                     java.naming.provider.url=${jboss.bind.address:localhost}:1100

                     jnp.disableDiscovery=false

                     jnp.partitionName=${jboss.partition.name:DefaultPartition}

                     jnp.discoveryGroup=${jboss.partition.udpGroup:230.0.0.4}

                     jnp.discoveryPort=1102

                     jnp.discoveryTTL=16

                     jnp.discoveryTimeout=5000

                     jnp.maxRetries=1

                  </attribute>

                </mbean>

               

                <!-- JMS XA Resource adapter, use this to get transacted JMS in beans -->

                <tx-connection-factory>

                  <jndi-name>jms/ABCJMSConnectionFactoryTX</jndi-name>

                  <xa-transaction/>

                  <rar-name>jms-ra.rar</rar-name>

                  <track-connection-by-tx/>

                  <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>

                  <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>

                  <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/ABCJMSProvider</config-property>

                  <max-pool-size>20</max-pool-size>

                  <security-domain-and-application>EncryptJMSPassword</security-domain-and-application>

                  <use-java-context>false</use-java-context>

                </tx-connection-factory>

               

                <no-tx-connection-factory>

                  <jndi-name>jms/ABCJMSConnectionFactoryNoTX</jndi-name>

                  <rar-name>jms-ra.rar</rar-name>

                  <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>

                  <min-pool-size>0</min-pool-size>

                  <max-pool-size>20</max-pool-size>

                  <blocking-timeout-millis>50000</blocking-timeout-millis>

                  <idle-timeout-minutes>15</idle-timeout-minutes>

                  <security-domain-and-application>EncryptJMSPassword</security-domain-and-application>

                  <use-java-context>false</use-java-context>

                </no-tx-connection-factory>

               

              </connection-factories>

              I also specify the provide in my ejb-jar.xml file as follows:

                      <message-driven>

                          <ejb-name>JobRequestListener</ejb-name>

                          <ejb-class>com.abc.backend.jobs.JobRequestListener</ejb-class>

                          <message-destination-link>JobRequests</message-destination-link>

                          <activation-config>

                              <activation-config-property>

                                  <activation-config-property-name>providerAdapterJNDI</activation-config-property-name>

                                  <activation-config-property-value>java:ABCJMSProvider</activation-config-property-value>

                              </activation-config-property>

                          </activation-config>

              and map the injected connection factory to the new JNDI name in jboss.xml as follows:

                          <resource-ref>

                              <res-ref-name>jms/ConnectionFactory</res-ref-name>

                              <jndi-name>jms/ABCJMSConnectionFactoryTX</jndi-name>

                          </resource-ref>

              However when I deploy I get the following exception

               

              18:56:12,988 INFO  [JmsActivation] Attempting to reconnect org.jboss.resource.adapter.jms.inflow.JmsActivationSpec@7736b039(ra=org.jboss.resource.adapter.jms.JmsResourceAdapter@61a48515 destination=queue/abc/SendEmails isTopic=false tx=true durable=false reconnect=10 provider=javaABCJMSProvider user=jmsuser pass=<not shown> maxMessages=1 minSession=1 maxSession=1 keepAlive=60000 useDLQ=true DLQHandler=org.jboss.resource.adapter.jms.inflow.dlq.GenericDLQHandler DLQJndiName=queue/DLQ DLQUser=null DLQMaxResent=5)
              18:56:12,990 ERROR [JmsActivation] Unable to reconnect org.jboss.resource.adapter.jms.inflow.JmsActivationSpec@7736b039(ra=org.jboss.resource.adapter.jms.JmsResourceAdapter@61a48515 destination=queue/abc/SendEmails isTopic=false tx=true durable=false reconnect=10 provider=java:ABCJMSProvider user=jmsuser pass=<not shown> maxMessages=1 minSession=1 maxSession=1 keepAlive=60000 useDLQ=true DLQHandler=org.jboss.resource.adapter.jms.inflow.dlq.GenericDLQHandler DLQJndiName=queue/DLQ DLQUser=null DLQMaxResent=5)
              javax.jms.IllegalStateException: This method is not applicable inside the application server. See the J2EE spec, e.g. J2EE1.4 Section 6.6
                      at org.jboss.resource.adapter.jms.JmsSessionFactoryImpl.setExceptionListener(JmsSessionFactoryImpl.java:224)
                      at org.jboss.resource.adapter.jms.inflow.dlq.AbstractDLQHandler.setupDLQConnection(AbstractDLQHandler.java:142)
                      at org.jboss.resource.adapter.jms.inflow.dlq.AbstractDLQHandler.setup(AbstractDLQHandler.java:83)
                      at org.jboss.resource.adapter.jms.inflow.dlq.JBossMQDLQHandler.setup(JBossMQDLQHandler.java:48)
                      at org.jboss.resource.adapter.jms.inflow.JmsActivation.setupDLQ(JmsActivation.java:369)
                      at org.jboss.resource.adapter.jms.inflow.JmsActivation.setup(JmsActivation.java:315)
                      at org.jboss.resource.adapter.jms.inflow.JmsActivation.handleFailure(JmsActivation.java:259)
                      at org.jboss.resource.adapter.jms.inflow.JmsActivation$SetupActivation.run(JmsActivation.java:639)
                      at org.jboss.resource.work.WorkWrapper.execute(WorkWrapper.java:204)
                      at org.jboss.util.threadpool.BasicTaskWrapper.run(BasicTaskWrapper.java:275)
                      at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(PooledExecutor.java:756)
              • 4. Re: Securing JBoss Messaging and EJB3
                Alexander Hartner Expert

                I figure I have to specify the security-domain in a special connection factory. However I am not quite sure how I can for JBoss to use that connection factory when receiving messages in an MDB. I found a way to specify a non-tx-connection factory as shown in my previous post.

                 

                Thanks in advance

                Alex

                • 5. Re: Securing JBoss Messaging and EJB3
                  Peter Johnson Master

                  I'm sorry, but I don't have the time to read through all the stuff you posted and point of specific corrections or changes you have to make to accomplish this. However, if I understand correctly what you are trying to do, there is an example of what you want to do in the book JBoss in Action, chapter 8, section 8.5.2. You can always download the source code for th book and build target 06 in project ch08 (open the index.html in the base directory for detailed instructions), that target builds a MDB that uses a secured destination. (The book uses a database for the authentication, but you can easily change that to use properties files - other sections of the book tell you how)