JBoss Fuse, CXF, java.io.IOException: Could not load keystore resource

I was recently tasked with enabling TLS on a CXF webservice hosted on JBoss Fuse. Since it was the first time I actually needed to enable the TLS within JBoss Fuse (with CXF) I was looking at some pointers. Luckily Red Had provides an excellent tutorial in their Security guide documentation. Which can be found here: https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.2/html/Security_Guide/CamelCXF-SecureProxy.html

This is an excellent step by step tutorial for setting up a TLS secured webservice. However the example is using Spring, and I was required to using OSGi Blueprint. Not a problem, usually it is a matter of finding the right namespaces and some minor changes in the xml config which are quite simple using this site: http://cxf.apache.org/docs/schemas-and-namespaces.html

However I was getting some strange behavior when I tried loading the Java Keystore resource from the file system, which was another requirement, rather than the classpath. I kept getting the java.io.IOException: Could not load keystore resource

My Blueprint configuration was as follows:


<cxfcore:bus/>
  
<httpj:engine-factory bus="cxf">
  <httpj:engine port="${port}">
    <httpj:tlsServerParameters secureSocketProtocol="${ secureSocketProtocol}">
      <sec:keyManagers keyPassword="${key.password}">
        <sec:keyStore resource="${keystoreLocation}" password="${keystore.password}" type="JKS"/>
      </sec:keyManagers>
      <sec:trustManagers>
        <sec:keyStore resource="${truststoreLocation}" password="${truststore.password}" type="JKS"/>
      </sec:trustManagers>
      <sec:cipherSuitesFilter>
        <sec:include>.*_WITH_3DES_.*</sec:include>
        <sec:include>.*_WITH_DES_.*</sec:include>
        <sec:exclude>.*_WITH_NULL_.*</sec:exclude>
        <sec:exclude>.*_DH_anon_.*</sec:exclude>
      </sec:cipherSuitesFilter>
      <sec:clientAuthentication want="true" required="${clientAuthentication}"/>
    </httpj:tlsServerParameters>
  </httpj:engine>
</httpj:engine-factory>

I spent quite a few hours trying to figure out why it wasn’t loading the Keystore. Was the path and the filename correct? Where the file system access rights setup accordingly? Was there some bundle cache that needed to be flushed?

After a while I found the solution when browsing through the CXF security.xsd, which can be found here (and if setup correctly the url should be in the blueprint.xml file): http://cxf.apache.org/schemas/configuration/security.xsd

Especially the KeyStoreType:


<xs:complexType name="KeyStoreType">
  <xs:annotation>
    <xs:documentation>
    A KeyStoreType represents the information needed to load a collection
    of key and certificate material from a desired location.
    The "url", "file", and "resource" attributes are intended to be
    mutually exclusive, though this assumption is not encoded in schema.
    The precedence order observed by the runtime is
    1) "file", 2) "resource", and 3) "url".
    </xs:documentation>
  </xs:annotation>
    <xs:attribute name="type"     type="xs:string">
      <xs:annotation>
        <xs:documentation>
        This attribute specifies the type of the keystore.
        It is highly correlated to the provider. Most common examples
        are "jks" "pkcs12".
        </xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="password" type="xs:string">
      <xs:annotation>
        <xs:documentation>
        This attribute specifes the integrity password for the keystore.
        This is not the password that unlock keys within the keystore.
        </xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="provider" type="xs:string">
      <xs:annotation>
        <xs:documentation>
        This attribute specifies the keystore implementation provider.
        Most common examples are "SUN".
        </xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="url"      type="xs:string">
      <xs:annotation>
        <xs:documentation>
        This attribute specifies the URL location of the keystore.
        This element should be a properly accessible URL, such as
        "http://..." "file:///...", etc. Only one attribute of
        "url", "file", or "resource" is allowed.
        </xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="file"     type="xs:string">
      <xs:annotation>
        <xs:documentation>
        This attribute specifies the File location of the keystore.
        This element should be a properly accessible file from the
        working directory. Only one attribute of
        "url", "file", or "resource" is allowed.
        </xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="resource" type="xs:string">
      <xs:annotation>
        <xs:documentation>
        This attribute specifies the Resource location of the keystore.
        This element should be a properly accessible on the classpath.
        Only one attribute of
        "url", "file", or "resource" is allowed.
        </xs:documentation>
      </xs:annotation>
    </xs:attribute>
</xs:complexType>

When modifying the recource to file the keystore was loaded perfectly.

The final config was looking like this:


<cxfcore:bus/>
  
<httpj:engine-factory bus="cxf">
  <httpj:engine port="${port}">
    <httpj:tlsServerParameters secureSocketProtocol="${ secureSocketProtocol}">
      <sec:keyManagers keyPassword="${key.password}">
        <sec:keyStore file="${keystoreLocation}" password="${keystore.password}" type="JKS"/>
      </sec:keyManagers>
      <sec:trustManagers>
        <sec:keyStore file="${truststoreLocation}" password="${truststore.password}" type="JKS"/>
      </sec:trustManagers>
      <sec:cipherSuitesFilter>
        <sec:include>.*_WITH_3DES_.*</sec:include>
        <sec:include>.*_WITH_DES_.*</sec:include>
        <sec:exclude>.*_WITH_NULL_.*</sec:exclude>
        <sec:exclude>.*_DH_anon_.*</sec:exclude>
      </sec:cipherSuitesFilter>
      <sec:clientAuthentication want="true" required="${clientAuthentication}"/>
    </httpj:tlsServerParameters>
  </httpj:engine>
</httpj:engine-factory>

 

Anyway, I hope it saves someone the hasle.