Chapter 30. Credentials for Web Services Security

When the consumer sends the user credentials to the producer, it is sending the credentials for the currently authenticated user in the consumer. This makes signing in to remote portlets transparent to end users, but also requires that the producer and consumer use the same credentials. This means that the user name and password must be the same and valid on both servers.
The recommended approach for this situation would be to use a common LDAP configuration. See the LDAP Integration chapter in the Administration and Configuration Guide to correctly configure LDAP on the portal.

30.1. About Web Services Security Configuration

JBoss Enterprise Application Platform 6 uses a different web service implementation than the previous versions: it is now uses the JBossWS CXF Stack instead of the JBossWS Native Stack. Due to these changes, the way we configure WS-Security for WSRP with the portal on JBoss Enterprise Application Platform 6 has changed.
CXF uses interceptors to extend and configure its behavior. There are two main types of interceptors: inInterceptors and outInterceptors. InInterceptors are invoked for communication coming into the client or server, while outInterceptors are invoked when the client or server sends a message.
So for the WSRP case, the communication from the consumer to the producer is governed by the consumer's OutInterceptor and the producer's InInterceptors. The communication from the producer to the consumer is governed by the producer's OutInterceptor and the consumer's InInterceptor. This may mean having to configure 4 Interceptors.
When dealing with user propagation, only the consumer sends the user credentials to the producer. So Username Tokens only need to be configured for the consumer's OutInterceptor and the producer's InInterceptor.
Consider encrypting the message from the consumer to the producer and also the message from the producer to the consumer. This means that encryption properties must be configured for all 4 interceptors.
See the CXF Documentation for more details on interceptors and their types: http://cxf.apache.org/docs/interceptors.html
To support ws-security, the portal uses CXF's WSS4J Interceptors which handle all ws-security related tasks. See the CXF Documentation for more details: http://cxf.apache.org/docs/ws-security.html

Note

We only support one ws-security configuration option for the producer. All consumers accessing the producer will have to conform to this security constraint. This means if the producer requires encryption, all consumers will be required to encrypt their messages when accessing the producer.
We only support one ws-security configuration option to be used by all the consumers. A consumer has the option to enable or disable ws-security, which allows for one or more consumers to use ws-security while the others do not.

30.2. WSS4J Interceptors and WSRP

The WSS4J Interceptors are configured using property files. WSRP looks for specific property files to know whether or not in/out interceptors must be added and configured for either consumers or producer.
Theses files are located in the standalone/configuration/jpp/wsrp/cxf/ws-security directory.
Consumer-specific files are in the consumer subdirectory while producer-specific files are located in the producer subdirectory. To add and configure a WSS4J interceptor, add the proper configuration file in the proper directory. If no configuration file is found for a specific interceptor type, then no such interceptor will be added.
In interceptors are configured using WSS4JInInterceptor.properties files while out interceptors are configured using WSS4JOutInterceptor.properties files.

Table 30.1. Files needed to configure interceptor for WSRP

Side Interceptor Type Configuration File
Consumer IN standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JInInterceptor.properties
  OUT standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.properties
Producer IN standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JInInterceptor.properties
  OUT standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JOutInterceptor.properties
See the CXF or WSS4J documentation for instructions and options available for each type of interceptor.

30.2.1. User Propagation

User propagation can be configured to be used over WSRP with ws-security. What this means is that a user logged into a consumer can have their credentials propagated over to the producer. This allows the producer to authenticate the user and any portlet on the producer (a remote portlet from the consumer's perspective) will view the user as being properly authenticated. This allows for remote portlets to access things like user information.

Note

This only works if the user's credentials on the producer and consumer are the same. This may require using a common authentication mechanism, such as LDAP.
This requires some special options when configuring the producer and server.

30.3. WS-Security Consumer Configuration

In order to configure ws-security on the consumer side, you will have to configure the WSS4J Interceptors as seen above. This will require having to configure the WSS4JInInterceptor and/or WSS4JOutInterceptor. You will also need to check the 'Enable WS-Security' checkbox on the WSRP Admin Portlet for the consumer configuration to take effect.
WSRP Consumers Configuration

Figure 30.1. WSRP Consumers Configuration

30.3.1. Portal-specific Configuration Options for User Propagation

In order to handle portal user propagation across ws-security, a number of configuration options have been created, which are recommended for the consumer's WSS4JOutInterceptor.

Custom user option
user=gtn.current.user
This option sets the user property to the currently authenticated user on the consumer.
Custom action option
action=gtn.UsernameToken.ifCurrentUserAuthenticated
If a user is currently authenticated, it will replace the gtn.UsernameToken.ifCurrentUserAuthenticated with UsernameToken. If the current user is an unauthenticated user, gtn.UsernameToken.ifCurrentUserAuthenticated will be removed from the action list. If no other actions are specified, then the WSS4J interceptor will not be added to the consumer. This allows you to only use ws-security when dealing with authenticated users, and not for anonymous users.

Note

This requires that the user option is set to 'gtn.current.user'
Custom PasswordCallbackClass
action=gtn.UsernameToken.ifCurrentUserAuthenticated
To set the password for the username token, we need to specify the password in a callback class. See the cxf ws-security documentation for more details http://cxf.apache.org/docs/ws-security.html
A special callback class has already been created which handles this for you: CurrentUserPasswordCallback. This class will retrieve the currently authenticated user's password and set this as the password in the callback object.
passwordCallbackClass=org.gatein.wsrp.wss.cxf.consumer.CurrentUserPasswordCallback

30.4. Producer Configuration

The configuration of the producer is similar to that of the consumer. It also requires having to configure the WSS4JInInterceptor and/or WSS4JOutInterceptor.

30.4.1. Special Configuration Options for User Propagation

To correctly propagate user information on the producer-side, use GTNSubjectCreatingInterceptor instead of a regular WSS4JInInterceptor. This portal-specific "in" interceptor is an extension of the traditional WSS4JInInterceptor and therefore can be configured similarly and accept the same configuration properties. To use the GTNSubjectCreatingInterceptor, create a property file at standalone/configuration/gatein/wsrp/cxf/ws-security/producer/GTNSubjectCreatingInterceptor.properties instead of the regular WSS4JInInterceptor.properties file.
This Interceptor will handle the ws-security headers and retrieve the users credentials. It will then use these credentials to perform a login on the producer site, thus authenticating the user on the producer and makes the user available to remote portlets.

Note

This class also extends org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingInterceptor and can accept the same properties this class normally accepts. See the JBossWS documentation for options and more information.

30.4.2. Custom 'action' option

action=gtn.UsernameToken.ifAvailable
When this option is activated, the interceptor will set the action to 'UsernameToken' when the received SOAP message contains ws-security headers. If no ws-security header is included in the message, then no action is taken and the interceptor is not run. This is useful for dealing with authenticated and unauthenticated users trying to access the producer.

30.5. Configuring WSRP using the User name Token and User Propagation

30.5.1. Producer Setup

  1. create the following file: standalone/configuration/gatein/wsrp/cxf/ws-security/producer/GTNSubjectCreatingInterceptor.properties
  2. set the content of GTNSubjectCreatingInterceptor.properties created in step 1 to:
    action=gtn.UsernameToken.ifAvailable
  3. start the producer server

Warning

This example configuration does not encrypt the message. This means the username and password will be sent between the producer and consumer in plain text. This is a security concern and is only being shown as a simple example. It is up to administrators to properly configure the WSS4J Interceptors to encrypt messages or to only use https communication between the producer and consumer.

30.5.2. Consumer Setup

Procedure 30.1. Configuring a Consumer

  1. Create the following file: standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.properties
  2. Set the content of the WSS4JOutInterceptor.properties to the following parameters:
    passwordType=PasswordText
    user=gtn.current.user
    action=gtn.UsernameToken.ifCurrentUserAuthenticated
    passwordCallbackClass=org.gatein.wsrp.wss.cxf.consumer.CurrentUserPasswordCallback
  3. Start the consumer server.
  4. In the WSRP admin portlet, click the 'enable ws-security' checkbox
  5. Access a remote portlet (for example, the user identity portlet included as an example portlet) and verify that the authenticated user is the same as the one on the consumer.

30.6. Securing WSRP Endpoints using Encryption and Signing

30.6.1. Sample Configuration for securing the Endpoints using Encryption and Signing

The following steps outline how to configure the producer and consumer to encrypt and sign SOAP messages passed between the producer and consumer. This example only deals with SOAP messages being sent between the producer and consumer, and not with user propagation.

Note

Some of the configuration options specified here are based on the content at http://cxf.apache.org/docs/ws-security.html and http://www.jroller.com/gmazza/entry/cxf_x509_profile More information may be available at these sites.

30.6.2. Password Callback Class

WSS4J uses a Java class to specify the password when performing any security related actions. For the purpose of these encryption and signing examples, we will use the same password for the producer's and consumer's keystore (wsrpAliasPassword). This simplifies configuration because one password callback class can be used for both the producer and consumer.

Example 30.1. Example test.TestCallbackHandler Class



package test;
 
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
 
import org.apache.ws.security.WSPasswordCallback;
import org.gatein.wsrp.wss.cxf.consumer.CurrentUserPasswordCallback;
 
public class TestCallbackHandler implements CallbackHandler
{
 
    @Override
    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException
    {
 
        //First check if we have any user name token call backs to add.
        //NOTE: only needed if using username tokens, and you want the currently authenticated users password added
        CurrentUserPasswordCallback currentUserPasswordCallback = new CurrentUserPasswordCallback();
        currentUserPasswordCallback.handle(callbacks);
 
        for (Callback callback: callbacks)
        {
            if (callback instanceof WSPasswordCallback)
            {
                WSPasswordCallback wsPWCallback = (WSPasswordCallback)callback;
                // since the CurrentUserPasswordCallback already handles the USERNAME_TOKEN case, we don't want to set it in this case
                if (wsPWCallback.getUsage() != WSPasswordCallback.USERNAME_TOKEN)
                {
                    wsPWCallback.setPassword("wsrpAliasPassword");
                }
            }
        }
    }
}

Note

CallbackHandler implementations are provided to the portal using the standard Java ServiceLoader infrastructure. CallbackHandler implementations need to be bundled in a jar containing a file META-INF/services/javax.security.auth.callback.CallbackHandler specifying the fully qualified name of the CallbackHandler implementation class. This jar then needs to be put in the gatein/extensions directory of the portal installation.
A working example of a CallbackHandler implementation is available from https://github.com/gatein/gatein-wsrp/tree/master/examples/wss-callback

30.6.3. Configuring the Keystores

Note

In this example we are making it a bit easier by specifying the same keystore password for both the producer and consumer, as they can use the same password callback class.
  1. Generate the producer's private encryption keys
     keytool -genkey -alias producerAlias -keypass wsrpAliasPassword -keystore producer.jks -storepass keyStorePassword -dname "cn=producerAlias" -keyalg RSA 
  2. Export the producer's public key
     keytool -export -alias producerAlias -file producerkey.rsa -keystore producer.jks -storepass keyStorePassword 
  3. Generate the consumer's private encryption keys
     keytool -genkey -alias consumerAlias -keypass wsrpAliasPassword -keystore consumer.jks -storepass keyStorePassword -dname "cn=consumerAlias" -keyalg RSA 
  4. Export the consumer's public key
     keytool -export -alias consumerAlias -file consumerkey.rsa -keystore consumer.jks -storepass keyStorePassword 
  5. Import the consumer's public key into the producer's keystore
     keytool -import -alias consumerAlias  -file consumerkey.rsa -keystore producer.jks -storepass keyStorePassword -noprompt 
  6. Import the producer's public key into the consumer's keystore
     keytool -import -alias producerAlias  -file producerkey.rsa -keystore consumer.jks -storepass keyStorePassword -noprompt 
  7. Copy the producer.jks file to the standalone/configuration/gatein/wsrp/cxf/ws-security/producer directory on the producer
  8. Copy the consumer.jks file to the standalone/configuration/gatein/wsrp/cxf/ws-security/consumer directory on the consumer

30.6.4. Configuring the Producer

  1. Create standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JInInterceptor.properties with the following content. This will configure the incoming message between the producer and the consumer
    action=Signature Encrypt Timestamp
    signaturePropFile=producer-security.properties
    decryptionPropFile=producer-security.properties
    passwordCallbackClass=test.TestCallbackHandler
  2. Create standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JOutInterceptor.properties with the following content. This will configure the outgoing message between the producer and the consumer
    action=Signature Encrypt Timestamp
    signaturePropFile=producer-security.properties
    encryptionPropFile=producer-security.properties
    passwordCallbackClass=test.TestCallbackHandler
    user=producerAlias
    encryptionUser=consumerAlias
    signatureUser=producerAlias
  3. Create standalone/configuration/gatein/wsrp/cxf/ws-security/producer/producer-security.properties with the following content:
    org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.password=keyStorePassword
    org.apache.ws.security.crypto.merlin.file=producer.jks
  4. The passwordCallbackClass property in these configuration files needs to match the fully qualified name of your CallbackHandler implementation class. In our case, it is test.TestCallbackHandler .

30.6.5. Configuring the Consumer

  1. Create standalone/ configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.properties with the following content. This will configure the outgoing message between the consumer and the producer
    action=Signature Encrypt Timestamp
    signaturePropFile=consumer-security.properties
    encryptionPropFile=consumer-security.properties
    passwordCallbackClass=test.TestCallbackHandler
    user=consumerAlias
    encryptionUser=producerAlias
    signatureUser=consumerAlias
  2. Create standalone/ configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JInInterceptor.properties with the following content. This will configure the incoming message between the consumer and the producer
    action=Signature Encrypt Timestamp
    signaturePropFile=consumer-security.properties
    decryptionPropFile=consumer-security.properties
    passwordCallbackClass=test.TestCallbackHandler
  3. Create standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/consumer-security.properties with the following content:
    org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.password=keyStorePassword
    org.apache.ws.security.crypto.merlin.file=consumer.jks
  4. The passwordCallbackClass property in these configuration files needs to match the fully qualified name of your CallbackHandler implementation class. In our case, it is test.TestCallbackHandler .

30.7. Configuring WSRP using User name Token, Encryption and Signing with User Propagation

30.7.1. Sample Configuration using User name Token, Encryption and Signing with User Propagation

This section outline how to configure the producer and consumer to encrypt and sign the soap message as well as use user propagation between the producer and consumer.

30.7.2. Configure the Producer

Follow the steps outlined in the Section 30.6.1, “Sample Configuration for securing the Endpoints using Encryption and Signing” but make the following changes:
  1. rename the WSS4JInInterceptor.properties file to GTNSubjectCreatingInterceptor.properties
  2. set the action property in GTNSubjectCreatingInterceptor.properties as:
    action= gtn.UsernameToken.ifAvailable Signature Encrypt Timestamp
  3. set the passwordType in GTNSubjectCreatingInterceptor.properties as:
    passwordType=PasswordText

30.7.3. Configure the Consumer

Follow the steps outlined in the Section 30.6.1, “Sample Configuration for securing the Endpoints using Encryption and Signing” section but make the following changes:
  1. set the action property in WSS4JOutInterceptor.properties as:
    action=gtn.UsernameToken.ifCurrentUserAuthenticated Signature Encrypt Timestamp
  2. set the user in the WSS4JOutInterceptor.properties as:
    user=gtn.current.user
  3. set the passwordType in the WSS4JOutInterceptor.properties as:
    passwordType=PasswordText