JBossWS - WS-Security options

JBossWS implements WS-Security 1.0 specifications to provide users with message level security. The user guide explains how to configure WS-Security through declaration files and annotations; for this aim, a simple example shows how to sign (and require signature of) messages.

This page instead goes deeper into the JBossWS WS-Security configuration details, covering more advanced topics.

 

Username Token Authentication

The following configuration allows clients to authenticate through a Username Token (1). Thanks to the JAAS integration, the received token will automatically be verified against the configured JBoss JAAS Security Domain.

   <jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                         xsi:schemaLocation="http://www.jboss.com/ws-security/config 
                         http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
     <config>
(1)    <username/>
(2)    <timestamp ttl="300"/>
     </config>
   </jboss-ws-security>

Line (2) states that a timestamp element must be present in the message and that the message can not be older than 300 seconds; this is used to prevent replay attacks.

On the server side you should have:

  <jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.jboss.com/ws-security/config
                   http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
     <config>
          <timestamp ttl="300"/>
          <requires/>
     </config>
  </jboss-ws-security>

Please note that this way username and password appear as simple text in the SOAP header. Thus it is strongly suggested to use a JBossWS - Secure transport.

 

Password digest, nonces and timestamp

Since 3.0.1 (Native)

The afore mentioned configuration causes the password to be sent on the wire as a plain text. The Username Token Profile specification allows a digested passwords to be used, even if this doesn't offer real additional security.

Moreover nonces and creation timestamp can be used as salt to the password digest; this provides some countermeasures to prevent replay attacks.

To enable password digesting, you basically need to follow these steps:

  • use the digestPassword attribute in the client wsse configuration (3)
  • perhaps enable/disable use of nonces (useNonce attribute, default true) and creation timestamp (useCreated attribute, default true)
  • properly setup the login module of your security domain to use UsernameTokenCallback (4).

Here is an example of the modified client config:

<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.jboss.com/ws-security/config
    http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
  <config>
(3)     <username digestPassword="true" useNonce="true" useCreated="true"/>
       <timestamp ttl="300"/>
  </config>
</jboss-ws-security>

And here is a sample login-config.xml showing how to use the UsernameTokenCallback (4):

<application-policy name="JBossWSDigest">
  <authentication>
    <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
      <module-option name="usersProperties">META-INF/jbossws-users.properties</module-option>
      <module-option name="rolesProperties">META-INF/jbossws-roles.properties</module-option>
      <module-option name="hashAlgorithm">SHA</module-option>
      <module-option name="hashEncoding">BASE64</module-option>
      <module-option name="hashUserPassword">false</module-option>
      <module-option name="hashStorePassword">true</module-option>
      <module-option name="storeDigestCallback">org.jboss.ws.extensions.security.auth.callback.UsernameTokenCallback</module-option>
      <module-option name="unauthenticatedIdentity">anonymous</module-option>
    </login-module>
  </authentication>
</application-policy>

Of course you could want to use different login module; the provided UsernameTokenCallback simply adds the nonce and creation timestamp to the digest.

You can use your custom login module as long as you extend the org.jboss.security.auth.spi.UsernamePasswordLoginModule: then you just need to plug the UsernameTokenCallback into your module and set the hash attributes (hashAlgorithm, hashEncoding, hashUserPassword, hashStorePassword) the way shown above.

 

Advanced tuning: nonce factory

The way nonces are created and checked/stored on server side influences the overall security against replay attacks. In particular currently JBossWS ships with a basic implementation of a nonce store that doesn't cache the received tokens on server side. More complex implementation can be easily plugged in implementing the NonceFactory and NonceStore interfaces you can find in the org.jboss.ws.extensions.security.nonce package. Then you just need to specify you factory class through the nonce-factory-class element in the wsse server config. Future version of JBossWS might come with a nonce store implementation leveraging JBoss Cache or Hibernate to store received nonces.

 

Advanced tuning: timestamp verification

Since 3.0.2 (Native)

By default if a Timestamp is present in the wsse:Security header the verification of the header is very strict and does not allow for any tolerance in the time comparisons - if the message appears to have been created even slightly in the future or if the message has just expired then it will be rejected. A new element called 'timestamp-verification' is now available for the wsse configuration. Here is an example of the modified wsse configuration:

<jboss-ws-security xmlns='http://www.jboss.com/ws-security/config'
                   xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
                   xsi:schemaLocation='http://www.jboss.com/ws-security/config     
                   http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd'>
  <timestamp-verification createdTolerance="5" warnCreated="false" expiresTolerance="10" warnExpires="false" />
</jboss-ws-security>

The attributes allow you to specify the tolerance in seconds that is used when verifying the 'Created' or 'Expires' element of the 'Timestamp' header.

  • createdTolerance - The number of seconds in the future a message will be accepted.
  • expiresTolerance - The number of seconds a message must have been expired for before it will be rejected.

The default value for both of these is 0 which was the orignal behaviour.

It is also possible to log a warning if a message is accepted due to the configured tolerances that would normally have been rejected, this can then enable you to track down clients where their time is out of synch with the server without rejecting their messages.

  • warnCreated - log a warning if a message is accepted with a 'Created' value in the future.
  • warnExpires - log a warning if a message is accepted with an 'Expires' value in the past.

The default for both of these is true so if you do not require logging you will need to disable these.

Please be aware that the purpose of this tolerance is not to overcome differences relating to different timezones, according to the WSSE specification these times should be UTC - the time and date comparisons used by JBossWS are timezone aware.

 

X509 Certificate Token

Encryption

Using X509v3 certificates you can both sign and encrypt messages.

<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.jboss.com/ws-security/config
                   http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
(1) <key-store-file>WEB-INF/bob-sign_enc.jks</key-store-file>
    <key-store-password>password</key-store-password>
    <key-store-type>jks</key-store-type>
    <trust-store-file>WEB-INF/wsse10.truststore</trust-store-file>
    <trust-store-password>password</trust-store-password>

    <config>
     <timestamp ttl="300"/>
(2)     <sign type="x509v3" alias="1" includeTimestamp="true"/>
(3)     <encrypt type="x509v3"
              alias="alice"
              algorithm="aes-256"
              keyWrapAlgorithm="rsa_oaep"
              tokenReference="keyIdentifier" />
(4)         <requires>
            <signature/>
              <encryption/>      
           </requires>
    </config>
</jboss-ws-security>

The server configuration shown above includes:

  1. Keystore and truststore information: location, password and type.
  2. Signature configuration: you need to provide the certificate/key pair alias to use. includeTimestamp  specifies whether the timestamp is to be signed too to prevent tampering.
  3. Encryption configuration: you need to provide the certificate/key pair alias to use.
  4. Optional security requirements: incoming messages should be both signed and encrypted.

Client side configuration works the same way.

 

Algorithms

Asymmetric + symmetric encryption is performed whenever the encrypt element is found. Thus message data are encrypted using a generated symmetric secret key. This is written in the SOAP header after being encrypted (wrapped) with the receiver public key. You can set both the encryption and key wrap algorithms.

Supported encryption algorithms

 

  • AES 128 (aes-128) (default)
  • AES 192 (aes-192)
  • AES 256 (aes-256)
  • Triple DES (triple-des)
Supported key wrap algorithms

 

  • RSA v.1.5 (rsa_15) (default)
  • RSA OAEP (rsa_oaep)

The Unlimited Strength Java(TM) Cryptography Extension installation might be required to run some strong algorithms (like AES-256). Please note that your country might have limits on allowed crypto strength.

 

Dynamic encryption

Since 3.0.1 (Native)

When replying to multiple clients, a service provider has to encrypt a message using the right public key according to its destination. The JBossWS native implementation of WS-Security gets the right key to use from the signature received (and verified) in the incoming message. You just need to require signature (1) and do not specify any encryption alias on server side (2):

<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.jboss.com/ws-security/config
                   http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
    <key-store-file>WEB-INF/bob-sign_enc.jks</key-store-file>
    <key-store-password>password</key-store-password>
    <key-store-type>jks</key-store-type>
    <trust-store-file>WEB-INF/wsse10.truststore</trust-store-file>
    <trust-store-password>password</trust-store-password>

    <config>
     <timestamp ttl="300"/>
        <sign type="x509v3" alias="1" includeTimestamp="true"/>
(2)     <encrypt type="x509v3"
              algorithm="aes-256"
              keyWrapAlgorithm="rsa_oaep"
              tokenReference="keyIdentifier" />
            <requires>
(1)         <signature/>
              <encryption/>      
           </requires>
    </config>
</jboss-ws-security>

Of course you'll have to add every new client's public key to the server side keystore, but no change to the descriptors and service implementation is required.

 

Token references

For interoperability reason you might want to configure the type of reference to encryption token to be used. For instance, Microsoft Indigo doesn't support direct reference to local binary security tokens that is the JBossWS default reference type choice. Allowed values for tokenReference attribute are:

  • directReference (default)
  • keyIdentifier
  • x509IssuerSerial

Please refer to the X.509 Token Profile 1.0 specification for further details on token references.

 

Targets configuration

JBossWS gives you a fine grained control over the elements that have to be signed or encrypted.

This allows you to encrypt important data only (like credit card numbers) without waisting time on other information exchanged by the same service (email addresses, for example). To configure this, you just need to specify the QName of the SOAP elements to encrypt. The default behavior is to encrypt the whole SOAP body.

<encrypt type="x509v3" alias="alice">
  <targets>
    <target type="qname">{http://www.my-company.com/cc}CardNumber</target>
    <target type="qname">{http://www.my-company.com/cc}CardExpiration</target>
    <target type="qname" contentOnly="true">{http://www.my-company.com/cc}CustomerData</target>
  </targets>
</encrypt>

The contentOnly attribute states whether the content of the element is to be encrypted as opposed to the entire element (default behavior). Target can be specified also for requirements upon message receipt.

 

Miscellanea

Signature and carriage returns

Since 3.0.4 (Native)

Exchanging signed messages whose payload contains carriage returns can lead to signature verification errors. That's because of the way the \r special character is handled by xml parsers. To prevent this kind of issue, besides custom encoding the payload before sending it, users can either also encrypt the message or force JBossWS to perform canonical normalization of messages. This can be triggered setting the org.jboss.ws.DOMContentCanonicalNormalization property to true in the MessageContext just before the invocation on client side and in the endpoint implementation. Please note there's a convenient constant for this in org.jboss.ws.Constants; also see the org.jboss.test.ws.jaxws.jbws2011.CRLFTestCase for an example.

 

JAAS integration

Since 3.0.2 (Native)

The WS-Security implementation allows users to achieve J2EE declarative security through JAAS integration. The calling user's identity and credential are derived from the wsse headers of the incoming message according to the parameters provided in the server wsse configuration file. Authentication and authorization are then achieved delegating to the JAAS login modules configured for the specified security domain.

 

Username token

Username Token Profile provides a mean of specifying the caller's username and password. The wsse server configuration file can be used to have those information used when performing authentication and authorization through configured login module.

<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jboss.com/ws-security/config
                      http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
  <config>
    <username/>
    <authenticate>
      <usernameAuth/>
    </authenticate>
  </config>
</jboss-ws-security>

Prior to JBossWs 3.0.2 Native the username token was always used to set principal and credential of the caller whenever specified. This means that for backward compatibility reasons, this behavior is obtained also when no authenticate tag at all is specified and the username token is used.

 

X.509 certificate token

Whenever a WS-Security message containing X.509 certificates is received, every certificate is validated against the truststore specified in the wsse configuration file. After this validation process, one of the X.509 certificate token can be chosen to extract the caller's principal and perform authentication and authorization using it as credential.

The current implementation allows the certificate token referenced by the signature token to be used for this purpose (1):

<jboss-ws-security xmlns="http://www.jboss.com/ws-security/config"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jboss.com/ws-security/config
                      http://www.jboss.com/ws-security/schema/jboss-ws-security_1_0.xsd">
  <key-store-file>META-INF/bob-sign.jks</key-store-file>
  <key-store-password>password</key-store-password>
  <key-store-type>jks</key-store-type>
  <trust-store-file>META-INF/wsse10.truststore</trust-store-file>
  <trust-store-password>password</trust-store-password>
  <config>
    <sign type="x509v3" alias="1" includeTimestamp="false"/>
    <requires>
      <signature/>
    </requires>
    <authenticate>
(1)   <signatureCertAuth certificatePrincipal="org.jboss.security.auth.certs.SubjectCNMapping"/>
    </authenticate>
  </config>
</jboss-ws-security>

The optional certificatePrincipal attributes specifies the class to be used to get the principal from the X509 certificate's attributes; it has to implement CertificatePrincipal and the default one used when no attribute is specified is org.jboss.security.auth.certs.SubjectDNMapping.

The configured security domain needs at least a BaseCertLoginModule to be set up. Here is an example of a security domain with a CertRolesLoginModule, which also enables authorization (using the specified jbossws-roles.properties file):

<application-policy name="JBossWSCert">
  <authentication>
    <login-module code="org.jboss.security.auth.spi.CertRolesLoginModule" flag="required">
      <module-option name="rolesProperties">jbossws-roles.properties</module-option>
      <module-option name="unauthenticatedIdentity">anonymous</module-option>
      <module-option name="securityDomain">java:/jaas/JBossWSCert</module-option>
    </login-module>
  </authentication>
</application-policy>

Finally, the BaseCertLoginModule of course uses a central keystore to perform user validation. This store is configured through the org.jboss.security.plugins.JaasSecurityDomain MBean as shown in the following jboss-service.xml configuration fragment:

<mbean code="org.jboss.security.plugins.JaasSecurityDomain"
       name="jboss.security:service=SecurityDomain">
  <constructor>
    <arg type="java.lang.String" value="JBossWSCert"/>
  </constructor>
  <attribute name="KeyStoreURL">resource:META-INF/keystore.jks</attribute>
  <attribute name="KeyStorePass">password</attribute>
  <depends>jboss.security:service=JaasSecurityManager</depends>
</mbean>

The JBoss security code will access the keystore with the principal that JBossWS got from the wsse header using the specified CertificatePrincipal mapping class. If a certificate is found and is the same of the one specified in the wsse header, the user is logged in.

For a working sample of X509 certificate authentication you may want to take a look at the org.jboss.test.ws.jaxws.jbws2116.CertAuthTestCase.

 

POJO Endpoint - Authentication and Authorization

Since 3.1.0 (Native)

In general the credentials obtained by WS-Security are only used for EJB endpoints or for POJO endpoints when they make a call to another secured resource, it is now possible to enable authentication and authorization checking for POJO endpoints. (This should not be enabled for EJB based endpoints as the EJB container will still take care of the security requirements of the deployed bean).

These instructions assume WS-Security has already been enabled, these instructions describe the additional configuration required to enable authentication and authorization for POJO endpoints

The first stage is that the war containing the POJO endpoint needs to have a security domain defined, this is achieved by defining a <security-domain> in the jboss-web deployment descriptor within the WEB-INF folder.

<jboss-web>
  <security-domain>java:/jaas/JBossWS</security-domain>
</jboss-web>

The remainder of the configuration to enable authentication and authorization is within the jboss-wsse-server.xml deployment descriptor.

To enable the POJO authentication and authorization first a new <authorization> element needs to be added to the appropriate <config> element within the descriptor: -

<jboss-ws-security>
  
  <config>
    <authorize>
      <!-- Must contain either <unchecked/> or one or more <role>RoleName</role> definitions. -->
    </authorize>
  </config>
  
</jboss-ws-security>

The config element can be defined globally, be port specific or even be operation specific.

The authorize element must contain either the <unchecked/> element or one or more <role>RoleName</role> elements.

<jboss-ws-security>
  
  <config>
    <authorize>      
      <unchecked/>
    </authorize>
  </config>
  
</jboss-ws-security>

This first example had <unchecked/> defined, this means that the authentication step will be performed to validate the users username and credential but no further role checking will take place. If the users username and credential are invalid then the request will be rejected otherwise the request will be allowed to proceed.

<jboss-ws-security>
  
  <config>
    <authorize>      
      <role>friend</role>
      <role>family</role>
    </authorize>
  </config>
  
</jboss-ws-security>

This second example has two roles defined, as before the user will be authenticated using their username and credential and they will then be checked to ensure that they have been assigned at least one of the roles 'friend' or 'family'.

It should be noted that the authentication and authorization still proceeds even if no username and password or certificate was provided in the request message, in this scenario authentication may proceed if the login module of the security domain has been configured with an anonymous identity.

 

Further information

  • The complete wsse configuration is specified in the src/main/resources/schema/jboss-ws-security_1_0.xsd schema that is available in the source code base.
  • The advanced examples described above are covered by the interoperability scenarios available in the org.jboss.test.ws.interop package.
  • If you have doubts on the keystore/truststore content requirements for signing/encrypting messages, read here. Moreover you can find a text file in the sources showing the store configuration used for the interoperability tests (src/test/resources/interop/nov2007/wsse/shared/META-INF/readme.txt).