GateIn WSRP WS-Security Configuration on JBossAS7

Version 20

    Note: draft article, features will be available starting in version 3.5.0

    Article migrated to: https://docs.jboss.org/author/display/GTNPORTAL35/Securing+WSRP#SecuringWSRP-SampleConfigurationSecuringtheEndpointsusingEncryptionandSigning

    DO NOT EDIT THIS FILE. IT WILL BE DELETED once the migration has been confirmed as successful

    Introduction

    JBoss AS7 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 GateIn on JBossAS 7 has changed.

     

     

    Note: We only support one ws-security configuration option for the producer and for all of the consumers. We do not support creating separate, individual ws-security configuration options for different consumers. If you only need to configure ws-security for only a single consumer, then the ws-security checkbox should only be checked for that one particular consumer. The security constraints for the producer are applied to all the consumers accessing it. So if the producer is specified to require encryption, then all consumers accessing the producer must  use encryption.

    Overview

    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/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 InIntereceptor. 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.

     

    NOTE: when dealing with WS-Security, there are some things to consider here:

    1) 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.

    2) When dealing with things like encyption, you will most likely want to encrypt 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.

     

    Please see the CXF Documentation for more details on interceptors and their types: http://cxf.apache.org/docs/interceptors.html

     

    To support ws-security, GateIn uses CXF's WSS4J Interceptors which handle all ws-security related tasks. Please see the CXF Documentation for more details: http://cxf.apache.org/docs/ws-security.html

     

    WSS4J Interceptors and WSRP

    The WSS4J Interceptors are configured using properties, and as such can be configured using simple 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/gatein/wsrp/cxf/ws-security directory of your the JBoss AS 7 home directory. Consumer-specific files are in the consumer subdirectory while producer-specific files should be located in the producer subdirectory. To add and configure a WSS4J interceptor, you just need to 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.

     

    Putting things together, here are the files you need to add to configure each interceptor types for each WSRP side:

     

    SideInterceptor typeConfiguration file
    ConsumerIN

    standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JInInterceptor.properties

    OUTstandalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.properties
    ProducerINstandalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JInInterceptor.properties
    OUTstandalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JOutInterceptor.properties

     

    Please refer to the CXF or WSS4J documentation for instructions and options available for each type of interceptors.

    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 GateIn 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.

    Note: This requires some special options when configuring the producer and server.

    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.

    Note: just like in older versions of GateIn, you will still need to check the 'Enable WS-Security' checkbox on the WSRP Admin Portlet for the consumer configuration to take effect.

     

    Special GateIn Configuration Options for User Propagation

    In order to handle user propagation in GateIn across ws-security, a couple of special configuration options have been created which should be applied to the consumer's WSS4JOutInterceptor.

     

    Custom 'user' option:

    user=gtn.current.user

     

    What this option will do is it will set 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:

    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

    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.

    Special GateIn Configuration Options for User Propagation

     

    To properly propagate user information on the producer-side, you will need to use GTNSubjectCreatingInterceptor instead of a regular WSS4JInInterceptor. This GateIn-specific "in" interceptor is an extension of the traditional WSS4JInInterceptor and therefore can be configured similarly and accept the same configuration properties. To specify that you want to use the GTNSubjectCreatingInterceptor, please 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.

     

    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 unauthentcated users trying to access the producer.

     

    Sample Configuration using the UsernameToken and User Propagation

    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.

    Producer Setup

    1) create the following file:

    standalone/configuration/gatein/wsrp/cxf/ws-security/producer/GTNSubjectCreatingInterceptor.properties

    2) set the content of the GTNSubjectCreatingInterceptor.properties created in step 1 to:

    action=gtn.UsernameToken.ifAvailable

     

    3) start the producer server

     

    Consumer Setup

    1) create the following file:

     

    standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.properties

     

    2) set the content of the WSS4JOutInterceptor.properties created in step 1 to:

    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 in gatein) and verify that the authenticated user is the same as the one on the consumer

     

    Sample Configuration 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.

    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 things a bit as it means we can use just one password callback class for both the producer and consumer.

     

    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 GateIn Portal using the standard Java ServiceLoader infrastructure. As such, 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 your GateIn installation.

    You can see a working example of a CallbackHandler implentation at https://github.com/gatein/gatein-wsrp/tree/master/examples/wss-callback


    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

     

    6) Import the producer's public key into the consumer's keystore

     

    keytool -import -alias producerAlias  -file producerkey.rsa -keystore consumer.jks -storepass keyStorePassword

     

    7) Copy the producer.jks file to the configuration/gatein/wsrp/cxf/ws-security/producer directory on the producer

     

    8) Copy the consumer.jks file to the configuration/gatein/wsrp/cxf/ws-security/consumer directory on the consumer

     

    Configuring the Producer

    1) Create 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 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 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.

    Configuring the Consumer

     

    1) Create 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 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 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.

     

    Sample Configuration using UsernameToken, Encryption and Signing with User Propagation

    The following setps 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.

     

    Configure the Producer

     

    Follow the steps outlined in the Sample Configuration Securing the Endpoints using Encryption and Signing section 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

     

    Configure the Consumer

     

    Follow the steps outlined in the Sample Configuration 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 WSS4JInInterceptor.properties as:

     

    passwordType=PasswordText