WS-Trust 客户机 API
WS-Trust 客户机应用程序编程接口 (API) 包括 WSSTrustClient 类、WSSTrustClientValidateResult 类和其他配置实用程序类。WSSTrustClient 类提供帮助程序函数,用于将 WS-Trust SOAP 请求发送到指定的外部安全性令牌服务 (STS),以便 STS 能够发出或验证一个或多个 SAML 断言和其他类型的安全性令牌。
概述
WebSphere® Application Server 包含 WS-Trust 客户机功能(通过 WSSTrustClient 类实现),用于将 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 端点。
WSS API SAML 支持对 com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactory 和 com.ibm.websphere.wssecurity.wssapi.trust.WSSTrustClient 接口进行了补充。使用 com.ibm.websphere.wssecurity.wssapi.WSSFactory newSecurityToken() 方法生成的 SAMLToken 可以由 SAMLTokenFactory 和 WSSTrustClient 编程接口处理。相反,由 SAMLTokenFactory 生成或由 WSSTrustClient 返回的 SAMLToken 可以用在 WSS API 中。确定要在应用程序中使用哪个 API 取决于您的具体需求。就 Web service 客户机应用程序而言,WSS API SAML 支持可提供与 SAMLTokenFactory 和 WSSTrustClient 接口同等的功能,在这种意义上,该支持是完备的。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 不记名令牌。
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>
- -DtraceSettingsFile=MyTraceSettings.properties
- -Djava.util.logging.manager=com.ibm.ws.bootstrap.WsLogManager
- -Djava.util.logging.configureByServer=true
SAML 令牌返回
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>