3 Replies Latest reply on Jun 15, 2007 10:46 AM by Adrian Brock

    jms client authentication with client certificates

    Dan M Newbie

      Is it possible to authenticate a jms client with client certificates? Here is what I have tried so far. I had to hand type the code below into this post so there might be some typos

      Set up a jaas security domain with an identity and trust keystore in a file I created called default/deploy/ssl-domain-service.xml. The identity and trust keystore are located in the default/conf directory

      <server>
       <mbean code="org.jboss.security.plugins.JaasSecurityDomain" name="jboss.security:service=JaasSecurityDomain,domain=SSL">
       <constructor>
       <arg type="java.lang.String" value="SSL"/>
       </constructor>
       <attribute name="KeyStoreURL">resource:identity.jks</attribute>
       <attribute name="KeyStorePass">password</attribute>
       <attribute name="KeyStoreType">JKS</attribute>
       <attribute name="TrustStoreURL">resource:trust.jks</attribute>
       <attribute name="TrustStorePass">password</attribute>
       <attribute name="TrustStoreType">JKS</attribute>
       </mbean>
      </server>
      



      Set up an application policy in default/conf/login-config.xml to use the BaseCertLoginModule
      <application=policy name="SSL">
       <authentication>
       <login-module code="org.jboss.security.auth.spi.BaseCertLoginModule" flag="required">
       <module-option name="password-stacking">useFirstPass</module-option>
       <module-option name="securityDomain">java:/jaas/SSL</module-option>
       <module-option name="verifier">org.jboss.security.auth.certs.AnyCertVerifier</module-option>
       </login-module>
       <login-module code="org.jboss.security.auth.spi.UserRolesLoginModule" flag="required">
       <module-option name="password-stacking">useFirstPass</module-option>
       <module-option name="usersProperties">props/ssl-users.properties</module-option>
       <module-option name="rolesProperties">props/ssl-roles.properties</module-option>
       <module-option name="roleGroupSeperator">:</module-option>
       </login-module>
       </authentication>
      </application-policy>
      



      Set up a ssl UIL service in a file I created called ssl-uil2-service.xml in default/deploy/jms/ssl-uil2-service.xml
      <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>
       <attribute name="BindAddress">${jboss.bind.address}</attribute>
       <attribute name="ServerBindPort">8193</attribute>
       <attribute name="PingPeriod">60000</attribute>
       <attribute name="EnableTcpNoDelay">true</attribute>
       <attribute name="ReadTimeout">120000</attribute>
       <attribute name="ClientReadTimeout">120000</attribute>
       <attribute name="BufferSize">2048</attribute>
       <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>
      


      Set up the jbossmq security manager in default/deploy/jms/jbossmq-service.xml to only allow users with the jmsUser role to read/write/create destinations associated with the security manager.

      <mbean code="org.jboss.mq.security.SecurityManager" name="jboss.mq.service=SecurityManager">
       <attribute name="DefaultSecurityConfig">
       <security>
       <role name="jmsUser" read="true" write="true" create="true"/>
       </security>
       </attribute>
       <attribute name="SecurityDomain">java:/jaas/SSL</attribute>
       <depends optional-attribute-name="NextIntercepter">jboss.mq:service=DestinationManager</depends>
      </mbean>
      


      Setup a queue that uses the security manager in default/deploy/jms/jbossmq-destinations-service.xml
      <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=updateQueue">
       <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depepends>
       <depends optional-attribute-name="SecurityManager">jboss.mq:service=SecurityManager</depends>
      </mbean>
      



      Here is the code I run on the client to create the InitialContext and do a jndi lookup for the updateQueue
      Properties prop = new Properties();
      
      X509Certificate cert = getCertificate();
      prop.put(Context.PROVIDER_URL, "jnp://localhost:1099");
      prop.put(Context.SECURITY_PRINCIPAL, cert.getSubjectDN().toString());
      prop.put(Context.SECURITY_CREDENTIALS, cert);
      prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");
      InitialContext jndiContext = new InitialContext(prop);
      Object tmp = jndiContext.lookup("SSLUIL2ConnectionFactory");
      QueueConnectionFactory qcf = (QueueConnectionFactory)tmp;
      conn = qcf.createQueueConnection();
      que = (Queue)jndiContext.lookup("queue/updateQueue");
      session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
      conn.start();
      



      Here is the server output when I try to connect to the queue. I turned on TRACE logging and when the baseCertLoginModule is run it is unable to find the client certificate.
      TRACE [BaseCertLoginModule] initialize, instance=@6960936
      TRACE [BaseCertLoginModule] securityDomain=java:/jaas/SSL
      TRACE [BaseCertLoginModule] found domain:
      org.jboss.security.plugins.JaasSecurityDomain
      TRACE [BaseCertLoginModule] exit: initialize(Subject, CallbackHandler, Map, Map)
      TRACE [BaseCertLoginModule] enter: login()
      TRACE [BaseCertLoginModule] login
      TRACE [BaseCertLoginModule] enter: getAliasAndCert()
      TRACE [BaseCertLoginModule] exit: getAliasAndCert()
      TRACE [BaseCertLoginModule] Authenticating as unauthenticatedIdentity=null
      TRACE [BaseCertLoginModule] enter: validateCredentail(String, X509Certificate)
      TRACE [BaseCertLoginModule] Vaidating cert using: org.jboss.security.auth.certs.AnyCertVerifier@14b4735
      TRACE [BaseCertLoginModule] The supplied certificate matched the certificate in the keystore.
      TRACE [BaseCertLoginModule] exit: validateCredentail(String, X509Certificate)
      TRACE [BaseCertLoginModule] User 'null' authenticated, loginOk=true
      DEBUG [BaseCertLoginModule] exit: login()
      


      If i keep the same setup on the server but instead of doing a jndiLookup for a jms queue I do a look up for a session ejb it works fine.

        • 1. Re: jms client authentication with client certificates
          Adrian Brock Master

          The JMS api does NOT support client authentication via certificates.
          It only supports user/password, e.g.
          javax.jms.ConnectionFactory.createConnection(user, password);

          But you can still do certifcate authentication if you enable SSL at the transport layer
          that requires client trust. i.e. you require the server to not trust the client
          unless it provides a valid certificate.
          Without a valid certificate, it cannot establish the TCP/IP connection.

          How to do this is explained in the jboss security documentation somewhere.
          See also the SSL (ServerSocket[Factory]) docs in the main javadocs.

          • 2. Re: jms client authentication with client certificates
            Dan M Newbie

            Adrian, Thank you for your response. Although, I am still a little confused. Isn't the transport layer configuration for SSL done on the UILServerILService MBean by setting the ClientSocketFactory and ServerSocketFactory attributes? I looked at the javadoc for org.jboss.security.ssl.DomainServerSocketFactory and saw that there is a method called setNeedsClientAuth(boolean). Do I need to extend this class, set that method to true, and then set the ServerSocketFactory attribute to the derived class?

            Also in doing this can I still do role based authorization? The code I have above is slightly simplified from what we really are trying to implement in that instead of using the BaseCertLoginModule and UserRolesLoginModule we have a custom LoginModule that extends the BaseCertLoginModule and a custom verifier that connects to a remote server to verify the user's certificate and retrieve the roles the user has.

            • 3. Re: jms client authentication with client certificates
              Adrian Brock Master

              Subclassing would be one way to do, but there are other mechanisms if you
              read the docs.

              Certifcates are used for authentication.

              Role based security can only be done on the user passed to the connection factory.