SSLEJB2.1

Adding SSL to EJB 2.1 calls

 

 

JBoss AS 4.2.0 and EAP 4.2 and above now use the unified invoker to make remote calls.  Previous versions of the AS used detatched invokers to make the calls.  This wiki article describes how to enable SSL for ejb 2.1.  This wiki article does not address ssl + http(https), you can read that in the Unified Invoker Wiki Article.

 

 

 

 

This wiki article does not cover SSL for EJB3, which is a separate topic covered in the ejb3 transport docs.

 

 

 

 

A little history first. Prior to JBoss 4.2, all remote invocations were done with detached invokers.  Detatched Invokers had knowledge in them about what protocols they would speak.  There was an RMI invoker, a Pooled RMI invoker, an HTTP Invoker.  These invokers were the backbone for remote Method calls.  JBoss then developed a second generation product called Temoting.  Remoting is  a single package that can speak many different protocols.  After Remoting came out, EJB3 used it without the need for detached invokers.  In order to bring everything under the same RPC methodology, the unified invoker was developed.  The Unified invoker is a detached invoker that uses remoting as it's primary means for communication.  This now means that one invoker can be used for all detached invoker communications and the remoting configuration can be changed slightly to switch the communications protocol in which the unified invoker speaks.

 

 

Step 1: Generate the keystore

JBoss uses JSEE, the Java Secure Socket Extension (JSSE), for SSL. To get started with JSSE you need a public key/private key pair in the form of an X509 certificate for use by the SSL server sockets. For the purpose of this example we have created a self-signed certificate using the JDK keytool and included the resulting keystore file, example.keystore. It was created using the following command and input:

 

keytool -genkey -keystore example.keystore -storepass sslsocket -keypass sslsocket -keyalg RSA -alias example -validity 3650 -dname "cn=example,ou=admin book,dc=jboss,dc=org"

This produces a keystore file called example.keystore. A keystore is a database of security keys. If you would like there is also an ant task called GenKey to generate they keystore.

 

 

 

 

There are two different types of entries in a keystore:

  • key entries: each entry holds very sensitive cryptographic key information, which is stored in a protected format to prevent unauthorized access. Typically, a key stored in this type of entry is a secret key, or a private key accompanied by the certificate chain for the corresponding public key. The keytool and jarsigner tools only handle the later type of entry, that is private keys and their associated certificate chains.

  • trusted certificate entries: each entry contains a single public key certificate belonging to another party. It is called a trusted certificate because the keystore owner trusts that the public key in the certificate indeed belongs to the identity identified by the subject (owner) of the certificate. The issuer of the certificate vouches for this, by signing the certificate.

Listing the src/main/org/jboss/book/security/example.keystore examples file contents using the keytool shows one self-signed certificate:

 

[examples]$ keytool -list -v -keystore example.keystore
Enter keystore password:  sslsocket

Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: example
Creation date: Oct 31, 2006
Entry type: keyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=example, OU=admin book, DC=jboss, DC=org
Issuer: CN=example, OU=admin book, DC=jboss, DC=org
Serial number: 45481c1b
Valid from: Tue Oct 31 22:01:31 CST 2006 until: Fri Oct 28 23:01:31 CDT 2016
Certificate fingerprints:
         MD5:  C2:CA:CA:D3:00:71:3E:32:CB:B3:C8:A8:4E:68:9A:BB
         SHA1: A6:44:EF:66:2A:49:14:B0:A4:14:74:8B:64:61:E4:E6:AF:E3:70:41

 

 

Step 2 Add  The SSLSocketBuilder

This service is used to build the SSL Server socket factory. This will be where all the store/trust information will be set. If do not need to make any custom configurations, no extra attributes need to be set for the SSLSocketBuilder and just need to set the javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword system properties. This can be done by just adding something like the following to the run script for JBoss (this one is for run.bat):

 

set JAVA_OPTS=-Djavax.net.ssl.keyStore=example.keystore -Djavax.net.ssl.keyStorePassword=sslsocket %JAVA_OPTS% 

If you set your ssl keystore and password in your command line, you don't need to specify this mbean. At that point you will be using the  If you don't want to use the custom SSLSocket builder, you can skip to step 4.

 

Otherwise if you want to customize the SSLSocketBuilder, you need to add this to your server/$/conf/jboss-service.xml

  <!-- This section is for custom (SSL) server socket factory  -->
   <mbean code="org.jboss.remoting.security.SSLSocketBuilder"
      name="jboss.remoting:service=SocketBuilder,type=SSL"
      display-name="SSL Server Socket Factory Builder">
      <!-- IMPORTANT - If making ANY customizations, this MUST be set to false. -->
      <!-- Otherwise, will used default settings and the following attributes will be ignored. -->
      <attribute name="UseSSLServerSocketFactory">false</attribute>
      <!-- This is the url string to the key store to use -->
      <attribute name="KeyStoreURL">example.keystore</attribute>
      <!-- The password for the key store -->
      <attribute name="KeyStorePassword">sslsocket</attribute>
      <!-- The password for the keys (will use KeystorePassword if this is not set explicitly. -->
      <attribute name="KeyPassword">sslsocket</attribute>
      <!-- The protocol for the SSLContext.  Default is TLS. -->
      <attribute name="SecureSocketProtocol">TLS</attribute>
      <!-- The algorithm for the key manager factory.  Default is SunX509. -->
      <attribute name="KeyStoreAlgorithm">SunX509</attribute>
      <!-- The type to be used for the key store. -->
      <!-- Defaults to JKS.  Some acceptable values are JKS (Java Keystore - Sun's keystore format), -->
      <!-- JCEKS (Java Cryptography Extension keystore - More secure version of JKS), and -->
      <!-- PKCS12 (Public-Key Cryptography Standards #12 keystore - RSA's Personal Information Exchange Syntax Standard). -->
      <!-- These are not case sensitive. -->
      <attribute name="KeyStoreType">JKS</attribute>
   </mbean>

Step 3 Add the SSLServerSocketFactoryService

Add the following to the server/$/conf/jboss-service.xml file.  If you are customizing the SSLSocketBuilder(see note in step 2), you need to also add this line.  If you aren't then you can skip this step.

 <mbean code="org.jboss.remoting.security.SSLServerSocketFactoryService"
     name="jboss.remoting:service=ServerSocketFactory,type=SSL"
     display-name="SSL Server Socket Factory">
     <depends optional-attribute-name="SSLSocketBuilder"
        proxy-type="attribute">jboss.remoting:service=SocketBuilder,type=SSL</depends>
  </mbean>

 

Step 4 Replace the current remoting configuration with the one for SSL

There is already a connector that is specified for the unified invoker in the server/$/conf/jboss-service.xml file.  We need to replace the default socket transport with the sslsocket transport.

 

Comment Out the following

<mbean code="org.jboss.remoting.transport.Connector"
          name="jboss.remoting:service=Connector,transport=socket"
          display-name="Socket transport Connector">

       <!-- Can either just specify the InvokerLocator attribute and not the invoker element in the -->
       <!-- Configuration attribute, or do the full invoker configuration in the in invoker element -->
       <!-- of the Configuration attribute. -->

       <!-- Remember that if you do use more than one param on the uri, will have to include as a CDATA, -->
       <!-- otherwise, parser will complain. -->
       <!-- <attribute name="InvokerLocator"><![CDATA[socket://${jboss.bind.address}:4446/?datatype=invocation\]\]\></attribute> -->

      <attribute name="Configuration">
         <!-- Using the following <invoker> element instead of the InvokerLocator above because specific attributes needed. -->
         <!-- If wanted to use any of the parameters below, can just add them as parameters to the url above if wanted use the InvokerLocator attribute. -->
         <config>
            <!-- Other than transport type and handler, none of these configurations are required (will just use defaults). -->
            <invoker transport="socket">
               <attribute name="dataType" isParam="true">invocation</attribute>
               <attribute name="marshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationMarshaller</attribute>
               <attribute name="unmarshaller" isParam="true">org.jboss.invocation.unified.marshall.InvocationUnMarshaller</attribute>
               <!-- This will be port on which the marshall loader port runs on.  -->
               <!-- <attribute name="loaderport" isParam="true">4447</attribute> -->
               <!-- The following are specific to socket invoker -->
               <!-- <attribute name="numAcceptThreads">1</attribute>-->
               <!-- <attribute name="maxPoolSize">303</attribute>-->
               <!-- <attribute name="clientMaxPoolSize" isParam="true">304</attribute>-->
               <attribute name="socketTimeout" isParam="true">600000</attribute>
               <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
               <attribute name="serverBindPort">4446</attribute>
               <!-- <attribute name="clientConnectAddress">216.23.33.2</attribute> -->
               <!-- <attribute name="clientConnectPort">7777</attribute> -->
               <attribute name="enableTcpNoDelay" isParam="true">true</attribute>
               <!-- <attribute name="backlog">200</attribute>-->
               <!-- The following is for callback configuration and is independant of invoker type -->
               <!-- <attribute name="callbackMemCeiling">30</attribute>-->
               <!-- indicates callback store by fully qualified class name -->
               <!-- <attribute name="callbackStore">org.jboss.remoting.CallbackStore</attribute>-->
               <!-- indicates callback store by object name -->
               <!-- <attribute name="callbackStore">jboss.remoting:service=CallbackStore,type=Serializable</attribute> -->
               <!-- config params for callback store.  if were declaring callback store via object name, -->
               <!-- could have specified these config params there. -->
               <!-- StoreFilePath indicates to which directory to write the callback objects. -->
               <!-- The default value is the property value of 'jboss.server.data.dir' and if this is not set, -->
               <!-- then will be 'data'. Will then append 'remoting' and the callback client's session id. -->
               <!-- An example would be 'data\remoting\5c4o05l-9jijyx-e5b6xyph-1-e5b6xyph-2'. -->
               <!-- <attribute name="StoreFilePath">callback</attribute>-->
               <!-- StoreFileSuffix indicates the file suffix to use for the callback objects written to disk. -->
               <!-- The default value for file suffix is 'ser'. -->
               <!-- <attribute name="StoreFileSuffix">cst</attribute>-->
            </invoker>

            <!-- At least one handler is required by the connector.  If have more than one, must decalre -->
            <!-- different subsystem values.  Otherwise, all invocations will be routed to the only one -->
            <!-- that is declared. -->
            <handlers>
               <!-- can also specify handler by fully qualified classname -->
               <handler subsystem="invoker">jboss:service=invoker,type=unified</handler>
            </handlers>
         </config>
      </attribute>
      <depends>jboss.remoting:service=NetworkRegistry</depends>
   </mbean>

 

ADD the following in it's place

 

  <mbean code="org.jboss.remoting.transport.Connector"
         name="jboss.remoting:service=Connector,transport=socket" 
         display-name="SSL Socket transport Connector">

     <attribute name="Configuration">
        <config>
            <invoker transport="sslsocket">
              <attribute name="serverSocketFactory">jboss.remoting:service=ServerSocketFactory,type=SSL</attribute>
              <attribute name="serverBindAddress">${jboss.bind.address}</attribute>
              <attribute name="serverBindPort">3843</attribute>
           </invoker>
           <handlers>
              <handler subsystem="invoker">jboss:service=invoker,type=unified</handler>           
           </handlers>
        </config>
     </attribute>
     <!--If you specify the keystore and password in the command line and you're not using the custom ServerSocketFactory, you should take out the following line-->
     <depends>jboss.remoting:service=ServerSocketFactory,type=SSL</depends>
     <depends>jboss.remoting:service=NetworkRegistry</depends>
  </mbean>

 

 

Step 5 Run with your truststore in your client

 

 

java -Djavax.net.ssl.trustStore=$/example.keystore -Djavax.net.ssl.trustStorePassword=sslsocket com.acme.RunClient

 

 

 

 

 

 

References:

 

{FOOTNOTE DEF 1 1} http://wki.jboss.org/wiki/Wiki.jsp?page=Unified_Invoker_configuration

 

{FOOTNOTE DEF 2 2} http://docs.jboss.org/ejb3/app-server/reference/build/reference/en/html/transport.html

 

{FOOTNOTE DEF 3 3} http://labs.jboss.com/jbossremoting/docs/guide/ch05.html

 

{FOOTNOTE DEF 4 4} http://www.camunda.com/bernd_rucker/ssl_mit_ejb3_im_jboss.html

 

{FOOTNOTE DEF 5 5} http://wiki.jboss.org/wiki/Wiki.jsp?page=Remoting_example_service_xml