使用 WSS API 和传输级别保护从外部 STS 请求 SAML 不记名令牌

您可以从外部安全性令牌服务 (STS) 请求具有 bearer 主体集确认方法的 SAML 令牌。在获取 SAML 不记名令牌之后,您随后可以使用 Java™ API for XML-Based Web Services (JAX-WS) 编程模型和 Web Service 安全 API (WSS API) 将这些令牌随 Web Service 请求消息一起发送。

开始之前

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

关于此任务

您可以从外部 STS 请求具有 bearer 主体集确认方法的 SAML 令牌,然后使用 WSS API 从 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 提供程序的详细信息。
  3. 将 SAML Bearer 提供程序样本缺省常规绑定分配到样本 Web Service 提供程序。 阅读关于配置 SAML 不记名令牌的客户机和提供程序绑定的信息,以了解关于将 SAML Bearer 提供程序样本缺省常规绑定分配到 Web service 应用程序的详细信息。
  4. 验证 trustStoreType、trustStorePassword 和 trustStorePath 定制属性是否对应于包含 STS 签署者证书的信任库。 使用管理控制台来完成以下步骤:
    1. 单击服务 > 策略集 > 常规提供程序策略集绑定 > SAML Bearer 提供程序样本 > WS-Security > 认证和保护
    2. 单击“认证令牌”表中的 gen_saml11token
    3. 单击回调处理程序
    4. 在“定制属性”部分中,确保 trustStoreType、trustStorePassword 和 trustStorePath 定制属性对应于包含 STS 签署者证书的信任库。
  5. 从外部 STS 请求 SAML 令牌。 以下代码片段说明如何请求 SAML 令牌并假设外部 STS 已配置来接受 UsernameToken 并在验证后发布 SAML 2.0 令牌:
    //Request the SAML Token from external STS
    WSSFactory factory = WSSFactory.getInstance();		
    String STS_URI  = "https://externalstsserverurl:port/TrustServerWST13/services/RequestSecurityToken";
    String ENDPOINT_URL = "http://localhost:9080/WSSampleSei/EchoService";
    WSSGenerationContext gencont1 = factory.newWSSGenerationContext();
    WSSConsumingContext concont1 = factory.newWSSConsumingContext(); 
    HashMap<Object, Object> cbackMap1 = new HashMap<Object, Object>();
    cbackMap1.put(SamlConstants.STS_ADDRESS, STS_URI);
    cbackMap1.put(SamlConstants.SAML_APPLIES_TO, ENDPOINT_URL);
    cbackMap1.put(SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE, "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
    cbackMap1.put(SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST, "false");
    cbackMap1.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
    cbackMap1.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
    
    SAMLGenerateCallbackHandler cbHandler1 = new SAMLGenerateCallbackHandler(cbackMap1);
    
    // Add UNT to trust request
    UNTGenerateCallbackHandler utCallbackHandler = new UNTGenerateCallbackHandler("testuser", "testuserpwd");
    SecurityToken ut = factory.newSecurityToken(UsernameToken.class, utCallbackHandler);
    
    gencont1.add(ut);
    
    cbHandler1.setWSSConsumingContextForTrustClient(concont1);
    cbHandler1.setWSSGenerationContextForTrustClient(gencont1);
    SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, cbHandler1, "system.wss.generate.saml");
    
    System.out.println("SAMLToken id = " + samlToken.getId());
    1. 将 JAX-WS JAR 文件的瘦客户机添加到类路径。app_server_root/runtimes/com.ibm.jaxws.thinclient_8.5.0.jar 文件添加到类路径。请参阅测试支持 Web Service 的客户机信息以了解关于将此 JAR 文件添加到类路径的更多信息。
    2. 使用 WSSFactory newSecurityToken 方法从外部 STS 请求 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 令牌的特征的参数,还包含访问 STS 和获取 SAML 令牌所需的其他参数。SAMLGenerateCallbackHandler 对象指定在下表中描述的配置参数:
      表 1. SAMLGenerateCallbackHandler 属性. 该表描述使用 bearer 主体集确认方法的 SAMLGenerateCallbackHandler 对象的配置参数。
      属性 描述 必需
      SamlConstants.CONFIRMATION_METHOD 指定来使用 Bearer 确认方法。
      SamlConstants.TOKEN_TYPE

      指定令牌类型。

      Web Service 客户机具有策略集附件时,Web Service 安全运行时环境未使用该属性。

      通过使用 tokenGenerator 绑定配置的 valueType 属性来指定令牌值类型。

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

      SamlConstants.STS_ADDRESS

      指定安全性令牌服务地址。

      对于此任务主题中使用的示例,该属性的值设置为 https 以指定使用 SSL 来保护 SAML 令牌请求。

      您必须设置 -Dcom.ibm.SSL.ConfigURL 属性以启用 SSL 来保护针对 STS 的 SAML 令牌请求。

      SamlConstants.SAML_APPLIES_TO 指定您要使用 SAML 令牌的目标 STS 地址。
      SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST 指定从 STS 请求包括在 RequestSecurityToken (RST) 元素中的单个令牌还是请求包括在单个 RequestSecurityTokenCollection (RSTC) 元素中的 RST 元素集合中的多个令牌。

      缺省行为是从 STS 请求包含在 RequestSecurityToken (RST) 元素中的单个令牌。

      为该属性指定 true 值将指示从 STS 请求包含在单个 RequestSecurityTokenCollection (RSTC) 元素中的 RST 元素集合中的多个令牌。

      SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE 指定包含在 WS 信任请求中的 WS 信任名称空间。

      WSSGenerationContext 实例和 WSSConsumingContext 实例也在 SAMLGenerateCallbackHandler 对象中设置。WSSGenerationContext 实例必须包含 UNTGenerateCallbackHandler 对象以及用于创建您要发送到 STS 的 UsernameToken 的信息。

      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");
    3. 获取创建的 SAML 令牌的令牌标识。
      将以下语句用作对所创建的 SAML 令牌的简单测试:
      System.out.println("SAMLToken id = " + samlToken.getId())
  6. 将 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 进行传输级别消息保护。此外,您可以使用此同一属性来支持使用 SSL 保护对 STS 的 SAML 令牌请求。使用以下 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");

结果

您使用传输级别保护从外部 STS 请求具有 bearer 主体集确认方法的 SAML 令牌。获取令牌之后,您使用 JAX-WS 编程模型和 WSS API 将令牌随 Web service 请求消息一起发送。

如果您希望使用消息级别保护从外部 STS 请求具有 bearer 主体集确认方法的 SAML 令牌,请参阅关于使用 WSS API 和消息级别保护从外部 STS 请求 SAML 发送者保证令牌的文档。要将消息级别保护用于具有 bearer 主体集确认方法的 SAML 令牌,在从外部 STS 请求 SAML 令牌的步骤中,指定确认方法 Bearer 来代替 sender-vouches;例如:
//Request the SAML Token from external STS
WSSFactory factory = WSSFactory.getInstance();		
String STS_URI  = "https://externalstsserverurl:port/TrustServerWST13/services/RequestSecurityToken";
String ENDPOINT_URL = "http://localhost:9080/WSSampleSei/EchoService";
WSSGenerationContext gencont1 = factory.newWSSGenerationContext();
WSSConsumingContext concont1 = factory.newWSSConsumingContext(); 
HashMap<Object, Object> cbackMap1 = new HashMap<Object, Object>();
cbackMap1.put(SamlConstants.STS_ADDRESS, STS_URI);
cbackMap1.put(SamlConstants.SAML_APPLIES_TO, ENDPOINT_URL);
cbackMap1.put(SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE, "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
cbackMap1.put(SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST, "false");
cbackMap1.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML11_VALUE_TYPE);
cbackMap1.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");

SAMLGenerateCallbackHandler cbHandler1 = new SAMLGenerateCallbackHandler(cbackMap1);

// Add UNT to trust request
UNTGenerateCallbackHandler utCallbackHandler = new UNTGenerateCallbackHandler("testuser", "testuserpwd");
SecurityToken ut = factory.newSecurityToken(UsernameToken.class, utCallbackHandler);

gencont1.add(ut);

cbHandler1.setWSSConsumingContextForTrustClient(concont1);
cbHandler1.setWSSGenerationContextForTrustClient(gencont1);
SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, cbHandler1, "system.wss.generate.saml");

System.out.println("SAMLToken id = " + samlToken.getId());
此外,如果是不记名令牌,那么用于配置响应消息中数字签名的验证的步骤是可选的。

示例

以下代码示例是一个 Web service 客户机应用程序,其演示如何从外部 STS 请求 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.callbackhandler.UNTGenerateCallbackHandler;
import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
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");

//Request the SAML Token from external STS
WSSFactory factory = WSSFactory.getInstance();		
String STS_URI  = "https://externalstsserverurl:port/TrustServerWST13/services/RequestSecurityToken";
String ENDPOINT_URL = "http://localhost:9080/WSSampleSei/EchoService";
WSSGenerationContext gencont1 = factory.newWSSGenerationContext();
WSSConsumingContext concont1 = factory.newWSSConsumingContext(); 
HashMap<Object, Object> cbackMap1 = new HashMap<Object, Object>();
cbackMap1.put(SamlConstants.STS_ADDRESS, STS_URI);
cbackMap1.put(SamlConstants.SAML_APPLIES_TO, ENDPOINT_URL);
cbackMap1.put(SamlConstants.TRUST_CLIENT_WSTRUST_NAMESPACE, "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
cbackMap1.put(SamlConstants.TRUST_CLIENT_COLLECTION_REQUEST, "false");
cbackMap1.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
cbackMap1.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");

SAMLGenerateCallbackHandler cbHandler1 = new SAMLGenerateCallbackHandler(cbackMap1);


// Add UNT to trust request
UNTGenerateCallbackHandler utCallbackHandler = new UNTGenerateCallbackHandler("testuser", "testuserpwd");
SecurityToken ut = factory.newSecurityToken(UsernameToken.class, utCallbackHandler);

gencont1.add(ut);

cbHandler1.setWSSConsumingContextForTrustClient(concont1);
cbHandler1.setWSSGenerationContextForTrustClient(gencont1);
SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, cbHandler1, "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");
			
			// Initialize WSSGenerationContext
			WSSGenerationContext gencont = factory.newWSSGenerationContext();
	        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_requeststs
文件名:twbs_configsamlbearer_requeststs.html