+

Search Tips   |   Advanced Search

Sending self-issued SAML holder-of-key tokens with asymmetric key using WSS APIs

We can create self-issued SAML tokens with the holder-of-key subject confirmation method and use the JAX-WS programming model and Web Services Security APIs (WSS APIs) to send these tokens with web services request messages.

This task assumes that you are familiar with the JAX-WS programming model, the WSS API interfaces, SAML concepts, and the use of policy sets to configure and administer web services settings. Complete the following actions before you begin this task:

This task focuses on using the asymmetric key that is identified by SAML security tokens to generate a digital signature of selected SOAP message elements in order to satisfy holder-of-key subject confirmation method security requirements. The X.509 certificate of the sender is embedded in the SAML security token. The sender signs selected parts of request message elements by using its corresponding private key and encrypts the request message using the public key of the recipient. The recipient signs the selected elements of the response message using the private key of the recipient, and encrypts selected elements of the response message using the public key of the sender in SAML security tokens. The Web services security policy attached to the web services provider is provided for the reference.

  1. Create a SAML security token containing the holder-of-key subject confirmation method; for example:
    WSSFactory factory = WSSFactory.getInstance();
    // Initialize WSSGenerationContext
    com.ibm.websphere.wssecurity.wssapi.WSSGenerationContext gencont = factory.newWSSGenerationContext();
    // Initialize SAML issuer configuration via custom properties 
    HashMap<Object, Object> customProps = new HashMap<Object,Object>();
    customProps.put(SamlConstants.ISSUER_URI_PROP, "example.com");
    customProps.put(SamlConstants.TTL_PROP, "3600000");
    customProps.put(SamlConstants.KS_PATH_PROP, "keystores/saml-provider.jceks");
    customProps.put(SamlConstants.KS_TYPE_PROP, "JCEKS");
    customProps.put(SamlConstants.KS_PW_PROP, "{xor}LCswLTovPiws");
    customProps.put(SamlConstants.KEY_ALIAS_PROP, "samlissuer");
    customProps.put(SamlConstants.KEY_NAME_PROP, "CN=SAMLIssuer, O=EXAMPLE");
    customProps.put(SamlConstants.KEY_PW_PROP, "{xor}NDomLz4sLA==");
    customProps.put(SamlConstants.TS_PATH_PROP, "keystores/saml-provider.jceks");
    customProps.put(SamlConstants.TS_TYPE_PROP, "JCEKS");
    customProps.put(SamlConstants.TS_PW_PROP, "{xor}LCswLTovPiws");  
    gencont.add(customProps); //Add custom properties HashMap<Object, Object> map = new HashMap<Object, Object>();
    map.put(SamlConstants.CONFIRMATION_METHOD, "holder-of-key");
    map.put(SamlConstants.Token_REQUEST, "issue");
    map.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
    map.put(SamlConstants.SAML_NAME_IDENTIFIER, "Alice");
    map.put(SamlConstants.SIGNATURE_REQUIRED, "true");
    map.put(SamlConstants.KEY_TYPE, 
            "http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey");
    map.put(SamlConstants.SAML_APPLIES_TO, "http://localhost:9080/your_Web_service");
    map.put(SamlConstants.KEY_ALIAS, "soapinitiator" );
    map.put(SamlConstants.KEY_NAME, "CN=SOAPInitator, O=ACME");
    map.put(SamlConstants.KEY_PASSWORD, "keypass");
    map.put(SamlConstants.KEY_STORE_PATH, "keystores/initiator.jceks");
    map.put(SamlConstants.KEY_STORE_PASSWORD, "storepass");
    map.put(SamlConstants.KEY_STORE_TYPE, "jceks");
    SAMLGenerateCallbackHandler callbackHandler = new SAMLGenerateCallbackHandler(map); 
    SAMLToken samlToken = (SAMLToken) factory.newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml");

    The private key of the sender is specified by the SamlConstants.KEY_ALIAS property and is used to sign selected elements of the request message.

  2. Use the WSSGenerationContext object to prepare for request message security header processing; for example:
    gencon.add(samlToken); //this line of code can be omitted
    WSSTimestamp timestamp = factory.newWSSTimestamp();
    gencon.add(timestamp);
    WSSSignature sig = factory.newWSSSignature(samlToken);
    sig.setTokenReference(SecurityToken.REF_KEYID);
    //If the gencon.add(samlToken); line of code is omitted, //the above line of code must be replaced with //sig.setTokenReference(SecurityToken.REF_STR);
    
    sig.setSignatureMethod(WSSSignature.RSA_SHA1);
    sig.setCanonicalizationMethod(WSSSignature.EXC_C14N);
    sig.addSignPart(WSSSignature.BODY);
    sig.addSignPart(WSSSignature.TIMESTAMP);
    sig.addSignPart(WSSSignature.ADDRESSING_HEADERS);
    gencon.add(sig);
    X509GenerateCallbackHandler x509callbackHandler2 = new X509GenerateCallbackHandler(
            null, 
            "keystores/initiator.jceks", 
            "jceks", "storepass".toCharArray(), 
            "soaprecipient", null, 
            "", null);
    SecurityToken st2 = factory.newSecurityToken(X509Token.class, x509callbackHandler2);
    WSSEncryption enc = factory.newWSSEncryption(st2);    
    enc.addEncryptPart(WSSEncryption.BODY_CONTENT);
    enc.addEncryptPart(WSSEncryption.SIGNATURE);
    enc.setEncryptionMethod(WSSEncryption.AES256);
    enc.setKeyEncryptionMethod(WSSEncryption.KW_RSA_OAEP);
    gencon.add(enc);

    In this example, encryption uses a 256 bit key size so you must import the Java Cryptography Extension (JCE) policy file. For more information, read about using the unrestricted JCE policy files in the "Tuning Web Services Security applications" topic.

  3. Create the WSSConsumingContext object to prepare for response message security header processing; for example:
    WSSConsumingContext concont = factory.newWSSConsumingContext();
    
    HashMap<Object, Object> map = new HashMap<Object, Object>();
    
    SAMLConsumerCallbackHandler callbackHandler = new SAMLConsumerCallbackHandler(map); 
    WSSDecryption dec = factory.newWSSDecryption(SAMLToken.class, callbackHandler, "system.wss.consume.saml");
    dec.addAllowedEncryptionMethod(WSSDecryption.AES256);
    dec.addAllowedKeyEncryptionMethod(WSSDecryption.KW_RSA_OAEP);
    dec.encryptKey(false);
    dec.addRequiredDecryptPart(WSSDecryption.BODY_CONTENT); 
    concont.add(dec);
    X509ConsumeCallbackHandler verHandler = new X509ConsumeCallbackHandler(null, 
                "keystores/initiator.jceks", "jceks", "storepass".toCharArray(), "soaprecipient", null, null);
    WSSVerification ver = factory.newWSSVerification(X509Token.class, verHandler);
    ver.addRequiredVerifyPart(WSSVerification.BODY); 
    concont.add(ver);

  4. Use the JDK keytool utility to generate the saml-provider.jceks, initiator.jceks, and recipient.jceksfiles used to test the example code; for example:
    keytool -genkey -alias samlissuer -keystore saml-provider.jceks -dname "CN=SAMLIssuer, O=ACME" -storepass storepass -keypass keypass
     -storetype jceks -validity 5000 -keyalg RSA -keysize 2048
    
    keytool -genkey -alias soaprecipient -keystore recipient.jceks -dname "CN=SOAPRecipient, O=ACME" -storepass storepass -keypass keypass
     -storetype jceks -validity 5000 -keyalg RSA -keysize 2048
    
    keytool -genkey -alias soapinitiator -keystore initiator.jceks -dname "CN=SOAPInitator, O=ACME" -storepass storepass -keypass keypass
     -storetype jceks -validity 5000 -keyalg RSA -keysize 2048
    
    keytool -export -alias samlissuer -file issuerpub.cer -keystore saml-provider.jceks -storepass storepass -storetype jceks
    keytool -export -alias soaprecipient -file reciptpub.cer -keystore recipient.jceks -storepass storepass -storetype jceks
    keytool -export -alias soapinitiator -file initatpub.cer -keystore initiator.jceks -storepass storepass -storetype jceks
    
    keytool -import -alias samlissuer -file issuerpub.cer -keystore initiator.jceks -storepass storepass -storetype jceks -keypass keypass -noprompt
    keytool -import -alias soaprecipient -file reciptpub.cer -keystore initiator.jceks -storepass storepass -storetype jceks -keypass keypass -noprompt
    
    keytool -import -alias samlissuer -file issuerpub.cer -keystore recipient.jceks -storepass storepass -storetype jceks -keypass keypass -noprompt
    keytool -import -alias soapinitiator -file initatpub.cer -keystore recipient.jceks -storepass storepass -storetype jceks -keypass keypass -noprompt
    
    keytool -import -alias soapinitiator -file initatpub.cer -keystore saml-provider.jceks -storepass storepass -storetype jceks -keypass keypass -noprompt


Results

You have learned key building blocks to create a web services client application to send a SAML security token in a SOAP message and to use the asymmetric key embedded in SAML security in message level protection.


Example

Example web services provider Web services security policy:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
  xmlns:spe="http://www.ibm.com/xmlns/prod/websphere/200605/ws-securitypolicy-ext">
    <wsp:Policy wsu:Id="response:app_encparts">
        <sp:EncryptedElements>
            <sp:XPath>/*[namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/'
             and local-name()='Envelope']/*[namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/'
             and local-name()='Header']/*[namespace-uri()='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
             and local-name()='Security']/*[namespace-uri()='http://www.w3.org/2000/09/xmldsig#' and local-name()='Signature']</sp:XPath>
            <sp:XPath>/*[namespace-uri()='http://www.w3.org/2003/05/soap-envelope'
             and local-name()='Envelope']/*[namespace-uri()='http://www.w3.org/2003/05/soap-envelope'
             and local-name()='Header']/*[namespace-uri()='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
             and local-name()='Security']/*[namespace-uri()='http://www.w3.org/2000/09/xmldsig#' and local-name()='Signature']</sp:XPath>
        </sp:EncryptedElements>
        <sp:EncryptedParts>
            <sp:Body/>
        </sp:EncryptedParts>
    </wsp:Policy>
    <wsp:Policy wsu:Id="request:req_enc">
        <sp:EncryptedParts>
            <sp:Body/>
        </sp:EncryptedParts>
    </wsp:Policy>
    <wsp:Policy wsu:Id="request:app_signparts">
        <sp:SignedParts>
            <sp:Body/>
            <sp:Header Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing"/>
            <sp:Header Namespace="http://www.w3.org/2005/08/addressing"/>
        </sp:SignedParts>
        <sp:SignedElements>
            <sp:XPath>/*[namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/'
             and local-name()='Envelope']/*[namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/'
             and local-name()='Header']/*[namespace-uri()='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
             and local-name()='Security']/*[namespace-uri()='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
             and local-name()='Timestamp']</sp:XPath>
            <sp:XPath>/*[namespace-uri()='http://www.w3.org/2003/05/soap-envelope'
            and local-name()='Envelope']/*[namespace-uri()='http://www.w3.org/2003/05/soap-envelope'
            and local-name()='Header']/*[namespace-uri()='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
            and local-name()='Security']/*[namespace-uri()='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
            and local-name()='Timestamp']</sp:XPath>
        </sp:SignedElements>
    </wsp:Policy>
    <wsp:Policy wsu:Id="response:resp_sig">
        <sp:SignedParts>
            <sp:Body/>
        </sp:SignedParts>
    </wsp:Policy>
    <sp:AsymmetricBinding>
        <wsp:Policy>
            <sp:InitiatorToken>
                <wsp:Policy>
                    <spe:CustomToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512/IncludeToken/Always"/>
                        <wsp:Policy>
                            <spe:WssCustomToken localname="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0"/>
                        </wsp:Policy>
                    </spe:CustomToken>
                </wsp:Policy>
            </sp:InitiatorToken>
            <sp:AlgorithmSuite>
                <wsp:Policy>
                    <sp:Basic256/>
                </wsp:Policy>
            </sp:AlgorithmSuite>
            <sp:IncludeTimestamp/>
            <sp:RecipientToken>
                <wsp:Policy>
                    <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512/IncludeToken/Always"/>
                        <wsp:Policy>
                            <sp:WssX509V3Token11/>
                        </wsp:Policy>
                    </sp:X509Token>
                <wsp:Policy>
            <sp:RecipientToken>
            <sp:Layout>
                <wsp:Policy>
                    <sp:Strict/>
                </wsp:Policy>
            </sp:Layout>
        <wsp:Policy>
    <sp:AsymmetricBinding>
</wsp:Policy>


Related concepts

  • SAML concepts


    Related tasks

  • Configure client and provider bindings for the SAML bearer token
  • Sending self-issued SAML bearer tokens using WSS APIs
  • Sending self-issued SAML holder-of-key tokens with symmetric key using WSS APIs
  • Tune Web Services Security for v8.5 applications
  • Manage self-issue SAML token configuration using wsadmin commands

  • Web Services Security APIs