WS-Trust 客户机 API

WS-Trust 客户机应用程序编程接口 (API) 包括 WSSTrustClient 类、WSSTrustClientValidateResult 类和其他配置实用程序类。 WSSTrustClient 类提供帮助程序函数,用于将 WS-Trust SOAP 请求发送到指定的外部安全性令牌服务 (STS),以便 STS 能够发出或验证一个或多个 SAML 断言和其他类型的安全性令牌。

概述

WebSphere® Application Server 包含通过 WSSTrustClient 类实现的 WS-Trust 客户机功能,用于将 WS-Trust SOAP 请求发送到指定的外部安全性令牌服务 (STS)。 使用信任请求,STS 可以发出一个或多个 SAML 断言或其他类型的安全性令牌。 WSSTrustClient 类支持 OASIS WS-Trust V1.3 规范,还支持 WS-Trust V1.2 规范。 此外,该函数还支持 SOAP V1.1 和 SOAP V1.2 规范。

下面的样本代码演示了 Web Service 客户机如何使用 WSSTrustClient API 来请求 SAML 不记名令牌。 在位于代码样本前面的解释性文本中,术语 SAML 令牌与术语 SAML 断言可互换使用。

WSSTrustClient 类

您可以将样本代码复制到组装工具应用程序 (例如 Rational® Application Developer) 中,并在完成配置步骤后开始使用代码。 将 WSSTrustClient 类与其他 SAML API 一起使用以构建有用的 SAML 函数。 请参阅 SAML API Javadoc 以获取更多信息。

WSSTrustClient 类是一个抽象类并具有两个具体实现:WS-Trust V1.3 实现和 WS-Trust V1.2 实现。 在代码样本的第 50 行,SAMLWSTrustClientExample Web Service 客户机代码调用 WSSTrustClient.getInstance(ProviderConfig) 方法以检索 WS-Trust V1.3 实现。 getInstance() 方法采用单个 ProviderConfig 对象,此对象指定与 SAML 令牌颁发者相关的配置数据。 在样本代码的第 32 行中,还实例化了一个 ProviderConfig 对象。 此客户机代码将 WS-Trust V1.3 请求消息发送给目标 STS 端点。 在该样本中,端点为 https://MyCompany/Trust/13/UsernameMixed。 要使用样本代码,请将此示例 STS 端点替换为您计划使用的特定 STS 端点。

注: 从 WebSphere Application Server Release 8 开始,您可以使用 Web Service 安全性 (WSS) 应用程序编程接口 (API) 中的 com.ibm.websphere.wssecurity.wssapi.token.SAMLToken 类。 不存在混淆问题时,我们使用术语 SAMLToken 来代替使用其完整的软件包名称。 您可以使用 WSS API 从外部安全性令牌服务 (STS) 请求 SAMLToken 处理、在 SOAP 请求消息中传播 SAMLToken,以及使用 SAMLToken 确定的对称或非对称密钥来保护 SOAP 消息。

WSS API SAML 支持对 com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactorycom.ibm.websphere.wssecurity.wssapi.trust.WSSTrustClient 接口进行了补充。 使用 com.ibm.websphere.wssecurity.wssapi.WSSFactory newSecurityToken() 方法生成的 SAMLToken 可由 SAMLTokenFactoryWSSTrustClient 编程接口处理。 相反,由 SAMLTokenFactory 生成或由 WSSTrustClient 返回的 SAMLToken 可以用在 WSS API 中。 确定要在应用程序中使用哪个 API 取决于您的具体需求。 就 Web service 客户机应用程序而言,WSS API SAML 支持可提供与 SAMLTokenFactoryWSSTrustClient 接口同等的功能,在这种意义上,该支持是完备的。 SAMLTokenFactory 接口具有更多功能,可验证 SAMLToken 以及创建表示已认证 SAMLToken 的 JAAS 主体。 此验证对于 Web service 提供者端十分有用。 当您开发应用程序以处理 SAMLToken 时,SAMLTokenFactory 编程接口更适合您。

示例:使用 WSSTrustClient 类的 Web Service 客户机代码

1.  package sample;
2.  
3.   import com.ibm.websphere.wssecurity.wssapi.WSSException;
4.   import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
5.   import com.ibm.websphere.wssecurity.wssapi.trust.WSSTrustClient;
6.   import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
7.   import com.ibm.websphere.wssecurity.wssapi.XMLStructure;
8.  
9.  
10.  import com.ibm.wsspi.wssecurity.core.token.config.RequesterConfiguration;
11.  import com.ibm.wsspi.wssecurity.core.token.config.WSSConstants.Namespace;
12.  import com.ibm.wsspi.wssecurity.core.token.config.WSSConstants.TokenType;
13.  import com.ibm.wsspi.wssecurity.core.token.config.WSSConstants.WST13;
14.  import com.ibm.wsspi.wssecurity.trust.config.ProviderConfig;
15.  import com.ibm.wsspi.wssecurity.trust.config.RequesterConfig;
16.  import com.ibm.wsspi.wssecurity.wssapi.OMStructure;
17.  
18.  import org.apache.axiom.om.OMElement;
19.  import org.apache.axis2.util.XMLPrettyPrinter;
20.  
21.  import java.util.List;
22.  import java.io.ByteArrayOutputStream;
23.  import java.io.InputStream;
24.  import java.io.BufferedReader; 
25.  import java.io.InputStreamReader; 
26.  import java.io.IOException; 
27.  
28.  public class WSSTrustClientExample {
29.  
30.    public static void main(String[] args) {
31.          try {
32.          ProviderConfig providerConfig = WSSTrustClient.newProviderConfig(Namespace.WST13, "https://MyCompany.com/Trust/13/UsernameMixed" );
33.        
34.          showProviderConfigDefaultValue(providerConfig);
35.        
36.          providerConfig.setPolicySetName("Username WSHTTPS default");
37.          providerConfig.setBindingName("SamlTCSample");
38.          providerConfig.setBindingScope("domain");
39.  
40.  
41.          RequesterConfig requesterConfig = WSSTrustClient.newRequesterConfig(Namespace.WST13);
42.          
43.          showRequestConfigDefaultValue(requesterConfig);
44.          
45.          requesterConfig.put(RequesterConfiguration.RSTT.APPLIESTO_ADDRESS, "https://user.MyCompany:9443/WSSampleSei/EchoService12");
46.          requesterConfig.put(RequesterConfiguration.RSTT.TOKENTYPE, TokenType.SAML11);
47.          requesterConfig.put(RequesterConfiguration.RSTT.KEYTYPE, WST13.KEYTYPE_BEARER);
48.          requesterConfig.setSOAPNamespace(Namespace.SOAP12);
49.          
50.          WSSTrustClient client = WSSTrustClient.getInstance(providerConfig);
51.          List<SecurityToken> securityTokens = client.issue(providerConfig, requesterConfig);
52.          
53.          // Process SAML token
54.          if (securityTokens != null && !securityTokens.isEmpty()) {
55.            System.out.println("Number of tokens returned = " + securityTokens.size());
56.            SecurityToken token = securityTokens.get(0);
57.            if (token instanceof SAMLToken) {            
58.              showSAMLToken((SAMLToken)token);
59.            } else {
60.              System.out.println("Returned token is not an SAMLToken");
61.            }
62.          } else {
63.            System.out.println("No securityToken obtained.");
64.          }
65.          
66.      } catch (SoapSecurityException ex) {
67.        System.out.println("Caught exception: " + ex.getMessage());
68.        ex.printStackTrace();
69.      }
70.    }
71.  
72.    private static void showProviderConfigDefaultValue(ProviderConfig providerConfig) {
73.      System.out.println("providerConfig.getApplicationName() = " + providerConfig.getApplicationName());
74.      System.out.println("providerConfig.getBindingName() = " + providerConfig.getBindingName());
75.      System.out.println("ProviderConfig.getBindingScope() = " + providerConfig.getBindingScope());
76.      System.out.println("providerConfig.getIssuerURI() = " + providerConfig.getIssuerURI());
77.  
78.      System.out.println("providerConfig.getPolicySetName() = " + providerConfig.getPolicySetName());
79.      System.out.println("ProviderConfig.getPortName() = " + providerConfig.getPortName());
80.      System.out.println("providerConfig.getProvider() = " + providerConfig.getProvider());
81.      System.out.println("ProviderConfig.getServiceName() = " + providerConfig.getServiceName());
82.      System.out.println("providerConfig.getWSTrustNamespace() = " + providerConfig.getWSTrustNamespace());
83.      System.out.println("ProviderConfig.toString() = " + providerConfig.toString());
84.    }
85.    
86.    private static void showRequestConfigDefaultValue(RequesterConfig requesterConfig) {
87.      System.out.println("requesterConfig.getRSTTProperties() = " + requesterConfig.getRSTTProperties());
88.      System.out.println("requesterConfig.getSecondaryParameters() = " + requesterConfig.getSecondaryParameters());
89.      System.out.println("requesterConfig.getSOAPNamespace() = " + requesterConfig.getSOAPNamespace());
90.      System.out.println("requesterConfig.getWSAddressingNamespace() = " + requesterConfig.getWSAddressingNamespace());
91.     
92.      System.out.println("requesterConfig.getMessageID() = " + requesterConfig.getMessageID());
93.      System.out.println("requesterConfig.toString() = " + requesterConfig.toString());
94.    }
95.    
96.    private static void showSAMLToken(SAMLToken samlToken){
97.      System.out.println("samlToken.getAssertionQName() = " + samlToken.getAssertionQName());
98.      System.out.println("samlToken.getAudienceRestriction() = " + samlToken.getAudienceRestriction());
99.      System.out.println("samlToken.getAuthenticationMethod() = " + samlToken.getAuthenticationMethod());
100.     System.out.println("samlToken.getConfirmationMethod() = " + samlToken.getConfirmationMethod());
101.     System.out.println("samlToken.getId() = " + samlToken.getId());
102.     System.out.println("samlToken.getKeyIdentifier() = " + samlToken.getKeyIdentifier());
103.     System.out.println("samlToken.getKeyIdentifierEncodingType() = " + samlToken.getKeyIdentifierEncodingType());
104.     System.out.println("samlToken.getKeyIdentifierValueType() = " + samlToken.getKeyIdentifierValueType());
105.     System.out.println("samlToken.getKeyName() = " + samlToken.getKeyName());
106.     System.out.println("samlToken.getPrincipal() = " + samlToken.getPrincipal());
107.     System.out.println("samlToken.getProperties() = " + samlToken.getProperties());
108.     System.out.println("samlToken.getReferenceURI() = " + samlToken.getReferenceURI());
109.     System.out.println("samlToken.getSAMLAttributes() = " + samlToken.getSAMLAttributes());
110.     System.out.println("samlToken.getSamlCreated() = " + samlToken.getSamlCreated());
111.     System.out.println("samlToken.getSamlExpires() = " + samlToken.getSamlExpires());
112.     System.out.println("samlToken.getSamlID() = " + samlToken.getSamlID());
113.     System.out.println("samlToken.getSAMLIssuerName() = " + samlToken.getSAMLIssuerName());
114.     System.out.println("samlToken.getSAMLNameID() = " + samlToken.getSAMLNameID());
115.     System.out.println("samlToken.getStringAttributes() = " + samlToken.getStringAttributes());
116.     System.out.println("samlToken.getSubjectDNS() = " + samlToken.getSubjectDNS());
117.     System.out.println("samlToken.getSubjectIPAddress() = " + samlToken.getSubjectIPAddress());
118.     System.out.println("samlToken.getThumbprint() = " + samlToken.getThumbprint());
119.     System.out.println("samlToken.getThumbprintEncodingType() = " + samlToken.getThumbprintEncodingType());
120.     System.out.println("samlToken.getThumbprintValueType() = " + samlToken.getThumbprintValueType());
121.     System.out.println("samlToken.getTokenQname() = " + samlToken.getTokenQname());
122.     System.out.println("samlToken.getValueType() = " + samlToken.getValueType());    
123.          
124.    XMLStructure samlXmlStructure = samlToken.getXML();
125.     if (samlXmlStructure != null && samlXmlStructure instanceof OMStructure) {
126.     OMStructure samlOMStructure = (OMStructure) samlXmlStructure;
127.     System.out.println("((OMStructure)samlToken.getXML()).getNode()formatted = " + formatXML(samlOMStructure.getNode()));
128.    }
129.      
130.    try {
131.      InputStream is = samlToken.getXMLInputStream();
132.      if (is != null) {
133.        try {
134.          BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
135.          StringBuilder sb = new StringBuilder();        
136.          String line = null;           
137.          while ((line = reader.readLine()) != null) {               
138.            sb.append(line + "\n");            
139.          } 
140.          System.out.println(sb.toString()); 
141.        } catch (Exception ex) {
142.          System.out.println("Caught exception reading from InputStream: " + ex.getMessage());
143.          ex.printStackTrace();
144.        } finally {        
145.          try {              
146.            is.close();            
147.          } catch (IOException e) {                
148.            e.printStackTrace(); 
149.          }  
150.        } 
151.      }
152.    } catch (WSSException wex) {
153.      System.out.println("Caught exception getXMLInputStream(): " + wex.getMessage());
154.      wex.printStackTrace();
155.    }
156.  }  
157.    
158.  private static String formatXML(OMElement omInput) {
159.    ByteArrayOutputStream out = new ByteArrayOutputStream();
160.    String output = "";
161.  
162.    try {
163.          XMLPrettyPrinter.prettify(omInput, out);
164.          output = out.toString();
165.    } catch (Throwable e) {
166.        try {
167.            output = omInput.toString();
168.        } catch (Throwable e2) {
169.                System.out.println("Caught exception: " + e2.getMessage());
170.        e2.printStackTrace();
171.        }
172.        }
173.    return output;
174.  }
175.  
176.  }

WSSTrustClient 类支持策略集和绑定

WS-Trust 客户机函数同时支持特定于应用程序的绑定和常规绑定,以用于信任客户机策略集和绑定文档。 此外,如果应用程序在应用程序服务器环境中运行,那么还支持常规绑定和缺省绑定。 瘦客户机环境中支持常规绑定,但是不支持缺省绑定。

为 WS-Trust 客户机 API 管理策略集和绑定类似于为 Web service 客户机管理策略集和绑定。 但是,存在 WS-Trust 客户机所特有的差异。 一个区别是,WS-Trust 客户机不使用策略集附件。 相反,策略集名称和绑定名称是在 ProviderConfig 对象中指定,如样本代码的第 36 行和第 37 行中所示。

当 WS-Trust 客户机查找绑定时,客户机管理搜索作用域的方式与 Web Service 客户机不同。 如果您不为信任客户机绑定指定 wstrustClientBindingScope 属性,那么系统将首先使用您指定的绑定名称来搜索应用程序以查找特定于应用程序的绑定。 如果找到了绑定,那么该绑定将用于信任客户机请求。 如果没有找到特定于应用程序的绑定,那么系统将搜索可用的常规绑定以查找具有您指定的名称的绑定。 如果找到了常规绑定,那么该绑定将用于信任客户机请求。 如果找不到任何具有特定名称的绑定,那么缺省绑定将用于服务器环境中。 缺省绑定仅用于服务器环境中。 如果指定了绑定作用域,那么仅该作用域用于绑定搜索。

样本代码的第 38 行 providerConfig.setBindingScope("domain") 指示示例使用常规绑定。 您还可以将绑定作用域设置为 application 以指示样本代码使用特定于应用程序的绑定。 该示例使用名为 SamlTCSample 的常规绑定。 特定于应用程序的绑定和常规绑定在应用程序服务器和瘦客户机环境中均受支持。 有关在应用程序服务器上安装应用程序时配置 SamlTCSample 绑定的更多信息,请阅读有关配置策略集和绑定以与 STS 进行通信的信息。

样本代码第 34 行中的 showProviderConfigDefaultValue(providerConfig) 代码显示缺省设置。 样本代码包括用于打印 providerConfig 的内容的实用程序方法。

样本代码第 51 行 List<SecurityToken> securityTokens = client.issue(providerConfig, requesterConfig) 发送颁发 WS-Trust 请求。 此行的第二个参数指定 RequesterConfig 对象,并且此参数确定颁发请求的内容。 第 41 行中的代码 RequesterConfig requesterConfig = WSSTrustClient.newRequesterConfig(Namespace.WST13) 实例化 RequesterConfig 对象,该对象用于通过 WS-Trust V1.3 名称空间来构造信任请求。 实用程序函数显示在第 43 行中:showRequestConfigDefaultValue(requesterConfig)。 此函数显示 RequesterConfig 对象的缺省设置。 第 45 行和 48 行之间的代码用于初始化 RequesterConfig 以请求 V1.1 SAML 不记名令牌。 此令牌用于通过 SOAP 1.2 名称空间来访问服务端点。 在示例中,服务端点为 https://user.MyCompany.com:9443/WSSampleSei/EchoService12。

JVM 自变量支持

在执行样本代码之前,必须设置多个 Java™ 虚拟机 (JVM) 参数。 样本代码实现 Username WSHTTPS 缺省策略集,该策略集有两个需求:1) Username 令牌发送到 STS;2) 使用安全套接字层 (SSL) 来保护消息。 要设置环境以满足这些需求,请首先配置 ssl.client.props 文件来定义信任库。 有关逐步指示信息,请阅读有关运行非受管 Web service JAX-WS 客户机的信息。

为了满足第二个有关 SSL 消息保护的需求,请获取 SSL STS X.509 证书的副本并将其插入到信任库中。 为此,请遵循主题“在 SSL 使用 retrieveSigners 命令来启用服务器到服务器的信任”中的步骤。 或者,如果 profile_home/properties/ssl.client.props 文件中的 com.ibm.ssl.enableSignerExchangePrompt 属性设置为 true,那么在向 STS 发送第一个信任请求时,可以接受 STS 证书。 有关此选项的更多信息,请阅读有关在客户机更改签署者自动交换提示的信息。

此外,您还必须指定客户机 JAAS 配置文件,以便客户机运行时环境能够找到 Username 令牌 LoginModule JAAS 登录配置。 使用以下代码来指定参数:-Djava.security.auth.login.config="%WAS_HOME%\properties\wsjaas_client.conf。 您必须还要在类路径中包括瘦客户机 jar,例如 com.ibm.jaxws.thinclient_9.0.jar。 有关更多信息,请参阅有关运行非受管 Web Service JAX-WS 客户机应用程序的信息。

样本代码执行

执行样本代码的先决条件是设置一个外部 STS 端点以便为 RequesterConfiguration.RSTT.APPLIESTO_ADDRESS 属性定义的指定 Web Service 发出 SAML 1.1 不记名令牌。

执行样本代码会生成一个 WS-Trust 颁发请求消息,如以下示例中所示:
177.  <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
178.      <soapenv:Header>
179.          <wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing">https://user.MyCompany.com/Trust/13/UsernameMixed</wsa:To>
180.          <wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">urn:uuid:4951B6775950CAC92A1252458259166</wsa:MessageID>
181.          <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</wsa:Action>
182.      </soapenv:Header>
183.      <soapenv:Body>
184.          <wst:RequestSecurityToken xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
185.              <wst:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1</wst:TokenType>
186.              <wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType>
187.              <wst:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</wst:KeyType>
188.              <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
189.                  <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
190.                      <wsa:Address>https://user.MyCompany.com:9443/WSSampleSei/EchoService12</wsa:Address>
191.                  </wsa:EndpointReference>
192.              </wsp:AppliesTo>
193.          </wst:RequestSecurityToken>
194.      </soapenv:Body>
195.  </soapenv:Envelope>
要查看 WS-Trust 请求消息,您必须启用客户端跟踪: 设置以下 JVM 属性:
  • -DtraceSettingsFile=MyTraceSettings.properties
  • -Djava.util.logging.manager=com.ibm.ws.bootstrap.WsLogManager
  • -Djava.util.logging.configureByServer=true
有关这些属性的更多信息,请阅读有关在客户机和独立应用程序上启用跟踪的信息。 除了设置 JVM 属性外,还必须在 MyTraceSettings.properties 文件中指定跟踪设置 com.ibm.ws.wssecurity.*=all=enabled。 在跟踪日志文件中查找 Trust Client outgoing request:

SAML 令牌返回

如果成功处理了 WS-Trust 问题请求,那么样本代码 List<SecurityToken> securityTokens = client.issue(providerConfig, requesterConfig)的第 51 行上的代码将返回 SAML 令牌。 第 54 行和第 64 行之间的代码处理返回的 SAML 令牌。 第 58 行上显示的实用程序函数 showSAMLToken((SAMLToken)token) 显示收到的 SAML 令牌的内容。 showSAMLToken() 例程将 SAML 令牌显示为 XML 文档。 此 XML 文档的示例在样本代码的 196 行到 233 行中提供。
196.  <?xml version="1.0" encoding="UTF-8"?>
197.  <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" 
198.   AssertionID="_f7f65d28-fbb1-4e10-8ddf-f4b6ed0c8277" Issuer="http://MyCompany.com/Trust" 
199.   IssueInstant="2009-09-09T01:04:41.144Z">
200.      <saml:Conditions NotBefore="2009-09-09T01:04:41.141Z" NotOnOrAfter="2009-09-09T11:04:41.141Z">
201.          <saml:AudienceRestrictionCondition>
202.              <saml:Audience>https://user.MyCompany.com:9443/WSSampleSei/EchoService12</saml:Audience>
203.          </saml:AudienceRestrictionCondition>
204.      </saml:Conditions>
205.      <saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" 
206.       AuthenticationInstant="2009-09-09T01:04:41.131Z">
207.          <saml:Subject>
208.              <saml:SubjectConfirmation>
209.                  <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
210.              </saml:SubjectConfirmation>
211.          </saml:Subject>
212.      </saml:AuthenticationStatement>
213.      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
214.          <ds:SignedInfo>
215.              <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
216.              <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
217.              <ds:Reference URI="#_f7f65d28-fbb1-4e10-8ddf-f4b6ed0c8277">
218.                  <ds:Transforms>
219.                      <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
220.                      <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
221.                  </ds:Transforms>
222.                  <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
223.                  <ds:DigestValue>AQ6e7YQqKgcg/B/ebBj8/DF+uWg=</ds:DigestValue>
224.              </ds:Reference>
225.          </ds:SignedInfo>
226.          <ds:SignatureValue>SuccIOniR . . . . yjTh9iQs=</ds:SignatureValue>
227.          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
228.              <X509Data>
229.                  <X509Certificate>MIIB3zCCAUi . . . . itzymqg3</X509Certificate>
230.              </X509Data>
231.          </KeyInfo>
232.      </ds:Signature>
233.  </saml:Assertion>