使用 WSS API 发送自发出的 SAML 不记名令牌

您可以创建具有 bearer 主体集确认方法的自签发 SAML 令牌,随后使用 Java™ API for XML-Based Web Services (JAX-WS) 编程模型和 Web Service 安全 API (WSS API) 将这些令牌随 Web service 请求消息一起发送。

开始之前

本任务假设您熟悉 JAX-WS 编程模型、WSS API 接口、SAML 概念以及策略集的使用以配置和管理 Web service 设置。

关于此任务

您可以使用 Web service 安全编程接口构建 web service 客户机在 SOAP 请求消息中使用具有 bearer 主体集确认方法的 SAML 令牌。使用 Web service 客户机中的编程接口来指定使用具有 bearer 主体集确认方法的 SAML 令牌是使用策略集和绑定配置的备选方法。

您可以创建自签发 SAML 令牌,然后从 Web service 客户机在 Web service 请求消息中发送 SAML 令牌。在此任务中使用的 Web service 应用程序客户机是可供下载的 JaxWSServicesSamples 样本应用程序中包含的客户机代码的已修改版本。在过程部分中描述了来自样本的代码片段,且在示例部分中提供完整的准备使用的 Web service 客户机样本。

过程

  1. 识别并包含您要用于调用 Web service 提供程序的 Web service 客户机。

    使用此客户机来利用 WSS API 将 SAML 令牌以编程方式插入 SOAP 请求消息。

    在此过程中使用的 Web service 客户机是 JaxWSServicesSamples Web service 样本应用程序中包含的客户机代码的已修改版本。

    要获取并修改样本 Web service 客户机以添加 Web Service 安全 API 来利用 WSS API 以编程方式传递 SOAP 请求消息中的 SAML 令牌,请完成以下步骤:

    1. 下载 JaxWSServicesSamples 样本应用程序。 缺省情况下,未安装 JaxWSServicesSamples 样本。
    2. 获取 JaxWSServicesSamples 客户机代码。

      为了举例,此过程使用 JaxWSServicesSamples 样本中包含的 Echo 瘦客户机样本的修改版本。 Web service Echo 瘦客户机样本文件 SampleClient.java 位于 src\SampleClientSei\src\com\ibm\was\wssample\sei\cli 目录中。 样本类文件包含在 WSSampleClientSei.jar 文件中。

      JaxWSServicesSamples.ear 企业应用程序和支持 Java 归档 (JAR) 文件位于 JaxWSServicesSamples 样本应用程序内的 installableApps 目录中。

    3. JaxWSServicesSamples.ear 文件部署到应用程序服务器上。 在部署 JaxWSServicesSamples.ear 文件之后,您准备好针对样本应用程序测试样本 Web service 客户机代码。

    您可以选择添加代码片段以利用自己的 Web service 客户机应用程序中的 WSS API 用编程方式传递 SOAP 请求消息中的 SAML 令牌,而不是使用 Web service 客户机样本。此过程中的示例使用 JAX-WS web service 瘦客户机;但是,您还可以使用受管客户机。

  2. 将 SAML20 Bearer WSHTTPS default 策略集附加到 Web service 提供程序。 此策略集用于使用 HTTPS 传输来保护消息。阅读关于配置 SAML 不记名令牌的客户机和提供程序绑定的信息以了解如何将 SAML20 Bearer WSHTTPS default 策略集附加到 Web service 提供程序的详细信息。此过程中的示例使用自签发 SAML 令牌。配置该提供程序绑定时,信任库配置和证书必须匹配自签发令牌的签署密钥。
  3. 将 SAML Bearer 提供程序样本缺省常规绑定分配到样本 Web Service 提供程序。 阅读关于配置 SAML 不记名令牌的客户机和提供程序绑定的信息,以了解关于将 SAML Bearer 提供程序样本缺省常规绑定分配到 Web service 应用程序的详细信息。
  4. 创建自签发 SAML 令牌。 以下代码片段说明 SAML 令牌创建过程:
    // Create the SAML token.
    HashMap<Object, Object> map = new HashMap<Object, Object>();
    map.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
    map.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
    map.put(SamlConstants.SAML_NAME_IDENTIFIER, "Alice");
    map.put(SamlConstants.SIGNATURE_REQUIRED, "true");			
    SAMLGenerateCallbackHandler callbackHandler = new SAMLGenerateCallbackHandler(map);				            
    callbackHandler.setWSSGenerationContextForTrustClient(gencont);
    SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml");
    
    System.out.println("SAMLToken id = " + samlToken.getId());
    1. 使用 CallService() 方法来指定 Web service 安全配置参数,需要这些参数来使用自签发 SAML 令牌调用目标 Web service 提供程序。

      CallService() 方法通过 com.ibm.websphere.wssecurity.wssapi.WSSGenerationContext 定制属性来设置 Web service 安全运行时环境所需的配置参数以生成自签发 SAML 令牌。

      阅读关于创建令牌期间配置 SAML 令牌的信息以了解关于如何指定配置属性来控制如何配置令牌的更多信息。

    2. 将 JAX-WS JAR 文件的瘦客户机添加到类路径。app_server_root/runtimes/com.ibm.jaxws.thinclient_8.5.0.jar 文件添加到类路径。请参阅测试支持 Web Service 的客户机信息以了解关于将此 JAR 文件添加到类路径的更多信息。
    3. 使用 WSSFactory newSecurityToken 方法来指定如何创建 SAML 令牌。
      指定以下方法来创建 SAML 令牌:
      WSSFactory  newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml")
      创建 SAML 令牌会需要 Java 安全许可权 wssapi.SAMLTokenFactory.newSAMLToken。使用策略工具将以下策略语句添加到 Java 安全策略文件或应用程序客户机 was.policy 文件:
      permission java.security.SecurityPermission "wssapi.SAMLTokenFactory.newSAMLToken

      SAMLToken.class 参数指定要创建的安全性令牌的类型。

      callbackHandler 对象包含的参数定义所创建的 SAML 令牌的特征。该对象指向 SAMLGenerateCallbackHandler 对象,该对象指定在下表中描述的配置参数:
      表 1. SAMLGenerateCallbackHandler 属性. 该表描述使用 bearer 主体集确认方法的 SAMLGenerateCallbackHandler 对象的配置参数。
      属性 描述 必需
      SamlConstants.CONFIRMATION_METHOD 指定来使用 Bearer 确认方法。
      SamlConstants.TOKEN_TYPE

      使用常量值 WSSConstants.SAML.SAML20_VALUE_TYPE 来指定 SAML 2.0 令牌类型。

      Web Service 客户机具有策略集附件时,Web Service 安全运行时环境未使用该属性。在此场景中,按 tokenGenerator 绑定配置的 valueType 属性指定令牌值类型。

      该过程中的示例使用 SAML 2.0 令牌;但是,您还可以使用 WSSConstants.SAML.SAML11_VALUE_TYPE 值。

      SamlConstants.SAML_NAME_IDENTIFIER

      将某个用户身份(例如 myname)指定为 SAML 令牌中的 NameID 值。

      如果您没有在使用 JAX-WS 的瘦客户机时定义此参数,那么 NameID 值没有包含有用的信息。

      如果您在使用 Web service 受管客户机,让 Java Platform, Enterprise Edition (Java EE) 应用程序进行 Web service 请求调用,那么 Web service 安全运行时环境尝试从安全上下文抽取用户安全信息。类似地,如果您没有为受管 Web service 客户机定义该参数,那么 NameID 值包含未经认证的名称标识。

      如果您的 Web service 客户机具有策略集附件,那么没有使用该属性。阅读关于发送 SAML 令牌的信息以了解关于发送 SAML 令牌身份和属性的更多信息。

      SamlConstants.SIGNATURE_REQUIRED

      指定是否需要签发者以数字方式签署 SAML 令牌。

      true 值指定需要签发者来以数字方式签署 SAML 令牌。 此值是缺省值。

      system.wss.generate.saml 参数指定用于创建 SAML 令牌的 Java 认证和授权服务 (JAAS) 登录模块。您必须指定 JVM 属性以定义 JAAS 配置文件,其包含所需的 JAAS 登录配置;例如:
      -Djava.security.auth.login.config=profile_root/properties/wsjaas_client.conf 
      或者,您可以通过在样本客户机代码中设置 Java 系统属性来指定 JAAS 登录配置文件;例如:
      System.setProperty("java.security.auth.login.config", "profile_root/properties/wsjaas_client.conf ");
    4. 获取创建的 SAML 令牌的令牌标识。
      将以下语句用作对所创建的 SAML 令牌的简单测试:
      System.out.println("SAMLToken id = " + samlToken.getId())
  5. 将 SAML 令牌添加到 Web service 请求消息的 SOAP 安全头。
    1. 初始化 Web service 客户机并配置 SOAPAction 属性。 以下代码片段说明这些操作:
      // Initialize web services client
      EchoService12PortProxy echo = new EchoService12PortProxy();
      echo._getDescriptor().setEndpoint(endpointURL);
      
      // Configure SOAPAction properties
      BindingProvider bp = (BindingProvider) (echo._getDescriptor().getProxy());
      Map<String, Object> requestContext = bp.getRequestContext();
      requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
      requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY,	Boolean.TRUE);
      requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "echoOperation");
      			
    2. 初始化 WSSGenerationContext。 以下代码说明使用 WSSGenerationContext 接口来初始化生成上下文并使您可以将 SAMLToken 插入 Web service 请求消息:
      // Initialize WSSGenerationContext
      WSSGenerationContext gencont = factory.newWSSGenerationContext();
      gencont.add(samlToken);	
      gencont.add(samlToken) 方法调用专门指定来将 SAML 令牌置于请求消息中。使用策略工具将以下策略语句添加到 Java 安全策略文件或应用程序客户机 was.policy 文件:
       “permission javax.security.auth.AuthPermission "modifyPrivateCredentials"
    3. 在 SOAP 消息安全头中添加时间戳记元素。 SAML20 Bearer WSHTTPS default 策略集需要 Web service 请求和响应消息来承载 SOAP 消息安全头中的时间戳记元素。在以下代码片段中,factory.newWSSTimestamp() 方法调用生成时间戳记,而 gencont.add(timestamp) 方法调用指定要置于请求消息中的时间戳记:
      // Add a timestamp to the request message. 
      WSSTimestamp timestamp = factory.newWSSTimestamp();
      gencont.add(timestamp);
      	        
      gencont.process(requestContext);
    4. 将 WSSGenerationContext 对象附加到 Web service RequestContext 对象。 WSSGenerationContext 对象现在包含格式化请求消息所需的所有安全信息。gencont.process(requestContext) 方法调用将 WSSGenerationContext 对象附加到 web service RequestContext 对象以支持 Web Service 安全运行时环境来格式化所需的 SOAP 安全头;例如:
      // Attaches WSSGenerationContext object to the web services RequestContext object. 
      gencont.process(requestContext);
    5. 使用 JVM 属性来指定 SSL 传输级别消息保护。
      SAML20 Bearer WSHTTPS default 策略集要求使用 SSL 进行传输级别消息保护。使用以下 JVM 属性来指定 SSL 传输级别消息保护:
      -Dcom.ibm.SSL.ConfigURL=file:profile_root\properties\ssl.client.props
      或者,您可以使用样本客户机代码中的 Java 系统属性来定义 SSL 配置文件;例如:
      System.setProperty("com.ibm.SSL.ConfigURL", "file:profile_root/properties/ssl.client.props");

结果

您使用 bearer 主体集确认方法创建自签发 SAML 令牌,然后使用 JAX-WS 编程模型和 WSS API 将此令牌随 Web service 请求消息一起发送。

示例

以下代码示例是一个 Web service 客户机应用程序,其演示如何创建自签发 SAML 令牌以及在 Web service 请求消息中发送该 SAML 令牌。如果您的使用方案需要 SAML 令牌,但是不要求您的应用程序使用 Web service 消息传递 SAML 令牌,那么您只需使用以下样本代码的第一部分,直到 // Initialize web services client 部分。

/**
 * The following source code is sample code created by IBM Corporation.
 * This sample code is provided to you solely for the purpose of assisting you in the
 * use of the technology.  The code is provided 'AS IS', without warranty or condition of
 * any kind.  IBM shall not be liable for any damages arising out of your use of the
 * sample code, even if IBM has been advised of the possibility of such damages.
 */

package com.ibm.was.wssample.sei.cli;

import com.ibm.was.wssample.sei.echo.EchoService12PortProxy;
import com.ibm.was.wssample.sei.echo.EchoStringInput;

import com.ibm.websphere.wssecurity.wssapi.WSSFactory;
import com.ibm.websphere.wssecurity.wssapi.WSSGenerationContext;
import com.ibm.websphere.wssecurity.wssapi.WSSConsumingContext;
import com.ibm.websphere.wssecurity.wssapi.WSSTimestamp;
import com.ibm.websphere.wssecurity.callbackhandler.SAMLGenerateCallbackHandler;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
import com.ibm.wsspi.wssecurity.core.token.config.WSSConstants;
import com.ibm.wsspi.wssecurity.saml.config.SamlConstants;

import java.util.Map;
import java.util.HashMap;

import javax.xml.ws.BindingProvider;

/**
 * SampleClient
 * main entry point for thin client JAR sample
 * and worker class to communicate with the services
 */
public class SampleClient {

  private String urlHost = "localhost";
  private String urlPort = "9443";
  private static final String CONTEXT_BASE = "/WSSampleSei/";
  private static final String ECHO_CONTEXT12 = CONTEXT_BASE+"EchoService12";
  private String message = "HELLO";
  private String uriString = "https://" + urlHost + ":" + urlPort;
  private String endpointURL = uriString + ECHO_CONTEXT12;
  private String input = message;

  /**
   * main()
   * 
   * see printusage() for command-line arguments
   * 
   * @param args
   */
  public static void main(String[] args) {
    SampleClient sample = new SampleClient();
    sample.CallService();
  }

  /**
   * CallService Parms were already read. Now call the service proxy classes
   * 
   */
  void CallService() {
    String response = "ERROR!:";
    try {
      System.setProperty("java.security.auth.login.config", "profile_root/properties/wsjaas_client.conf ");
      System.setProperty("com.ibm.SSL.ConfigURL", "file:profile_root/properties/ssl.client.props");

      // Initialize WSSFactory object
      WSSFactory factory = WSSFactory.getInstance();
      // Initialize WSSGenerationContext
      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

      // Create SAMLToken
      HashMap<Object, Object> map = new HashMap<Object, Object>();
      map.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
      map.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
      map.put(SamlConstants.SAML_NAME_IDENTIFIER, "Alice");
      map.put(SamlConstants.SIGNATURE_REQUIRED, "true");
      SAMLGenerateCallbackHandler callbackHandler = new SAMLGenerateCallbackHandler(map);

      SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml");

      System.out.println("SAMLToken id = " + samlToken.getId());

      // Initialize web services client
      EchoService12PortProxy echo = new EchoService12PortProxy();
      echo._getDescriptor().setEndpoint(endpointURL);

      // Configure SOAPAction properties
      BindingProvider bp = (BindingProvider) (echo._getDescriptor().getProxy());
      Map<String, Object> requestContext = bp.getRequestContext();
      requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
      requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
      requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "echoOperation");

      gencont.add(samlToken);

      // Add timestamp
      WSSTimestamp timestamp = factory.newWSSTimestamp();
      gencont.add(timestamp);

      gencont.process(requestContext);

      // Build the input object
      EchoStringInput echoParm = 
        new com.ibm.was.wssample.sei.echo.ObjectFactory().createEchoStringInput();
      echoParm.setEchoInput(input);
      System.out.println(">> CLIENT: SEI Echo to " + endpointURL);

      // Prepare to consume timestamp in response message.
      WSSConsumingContext concont = factory.newWSSConsumingContext();
      concont.add(WSSConsumingContext.TIMESTAMP); 
      concont.process(requestContext);

      // Call the service
      response = echo.echoOperation(echoParm).getEchoResponse();

      System.out.println(">> CLIENT: SEI Echo invocation complete.");
      System.out.println(">> CLIENT: SEI Echo response is: " + response);
    } catch (Exception e) {
      System.out.println(">> CLIENT: ERROR: SEI Echo EXCEPTION.");
      e.printStackTrace();
    }
  }
}
此 Web service 客户机应用程序样本正确运行时,您收到如下的消息:
SAMLToken id = _191EBC44865015D9AB1270745072344
Retrieving document at 'file:profile_root/.../wsdl/'.
>> CLIENT: SEI Echo to https://localhost:9443/WSSampleSei/EchoService12
>> CLIENT: SEI Echo invocation complete.
>> CLIENT: SEI Echo response is: SOAP12==>>HELLO

指示主题类型的图标 任务主题



时间戳记图标 最近一次更新时间: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=twbs_configsamlbearer_usingwssapi
文件名:twbs_configsamlbearer_usingwssapi.html