Network Deployment (Distributed operating systems), v8.0 > Reference > Developer detailed usage information
WS-Trust client API
The WS-Trust client API includes the WSSTrustClient class, the WSSTrustClientValidateResult class, and other configuration utility classes. The WSSTrustClient class provides helper functions that send WS-Trust SOAP requests to the specified external Security Token Service (STS) so that the STS can issue or validate one or more SAML assertions and other types of security tokens.
Overview
WAS v7.0.0.7 and later includes WS-Trust client function, implemented through the WSSTrustClient class, that sends WS-Trust SOAP requests to a specified external Security Token Service (STS). Using the trust requests, the STS can issue one or more SAML assertions or other types of security tokens. The WSSTrustClient class supports the OASIS WS-Trust Version 1.3 specification, and also the WS-Trust v1.2 specification. In addition, the SOAP v1.1 and SOAP v1.2 specifications are supported by the function.
The sample code which follows demonstrates how a web services client uses the WSSTrustClient API to request a SAML bearer token. In the explanatory text which precedes the code sample, the term SAML token is used interchangeably with the term SAML assertion.
The WSSTrustClient class
We can copy the sample code into an assembly tool application, such as Rational Application Developer, and start using the code after completing the configuration steps. Use the WSSTrustClient class, together with other SAML APIs, to build useful SAML functions. Refer to the SAML API Javadoc for more information.
The WSSTrustClient class is an abstract class and has two concrete implementations: a WS-Trust v1.3 implementation and a WS-Trust v1.2 implementation. On line 50 of the code sample, the SAMLWSTrustClientExample web services client code invokes the WSSTrustClient.getInstance(ProviderConfig) method to retrieve the WS-Trust v1.3 implementation. The getInstance() method takes a single ProviderConfig object, which specifies configuration data that are relevant to the SAML token issuer. A ProviderConfig object is also instantiated in the sample code on line 32. The client code sends WS-Trust v1.3 request messages to a target STS endpoint. In the sample, the endpoint is https://MyCompany/Trust/13/UsernameMixed. To use the sample code, replace this example STS endpoint with the specific STS endpoint you plan to use.
New feature: New feature: Starting with WAS Release 8, you can use the com.ibm.websphere.wssecurity.wssapi.token.SAMLToken class in Web Services Security (WSS) API. When there is no concern of confusion we use the term SAMLToken instead of using its complete package name. We can use WSS API to request SAMLToken processing from an external Security Token Service (STS), to propagate SAMLTokens in SOAP request messages, and to use a symmetric or asymmetric key identified by SAMLTokens to protect SOAP messages.
The WSS API SAML support complements the com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactory and com.ibm.websphere.wssecurity.wssapi.trust.WSSTrustClient interfaces. SAMLTokens that are generated using the com.ibm.websphere.wssecurity.wssapi.WSSFactory newSecurityToken() method can be processed by the SAMLTokenFactory and WSSTrustClient programming interfaces. Conversely, SAMLTokens that are generated by SAMLTokenFactory or returned by WSSTrustClient can be used in WSS API. Deciding which API to use in the application depends on your specific needs. WSS API SAML support is self contained in the sense that it provides functionality equivalent to that of the SAMLTokenFactory and WSSTrustClient interfaces as far as web services client applications are concerned. The SAMLTokenFactory interface has additional functions to validate SAMLTokens and to create the JAAS Subject that represents authenticated SAMLTokens. This validation is useful for the Web services provider side. When you develop applications to consume SAMLTokens, the SAMLTokenFactory programming interface is more suitable for you. New feature:
Example: Web services client code that uses the WSSTrustClient class
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. .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. .println("Returned token is not an SAMLToken"); 61. } 62. } else { 63. .println("No securityToken obtained."); 64. } 65. 66. } catch (SoapSecurityException ex) { 67. .println("Caught exception: " + ex.getMessage()); 68. ex.printStackTrace(); 69. } 70. } 71. 72. private static void showProviderConfigDefaultValue(ProviderConfig providerConfig) { 73. .println("providerConfig.getApplicationName() = " + providerConfig.getApplicationName()); 74. .println("providerConfig.getBindingName() = " + providerConfig.getBindingName()); 75. .println("ProviderConfig.getBindingScope() = " + providerConfig.getBindingScope()); 76. .println("providerConfig.getIssuerURI() = " + providerConfig.getIssuerURI()); 77. 78. .println("providerConfig.getPolicySetName() = " + providerConfig.getPolicySetName()); 79. .println("ProviderConfig.getPortName() = " + providerConfig.getPortName()); 80. .println("providerConfig.getProvider() = " + providerConfig.getProvider()); 81. .println("ProviderConfig.getServiceName() = " + providerConfig.getServiceName()); 82. .println("providerConfig.getWSTrustNamespace() = " + providerConfig.getWSTrustNamespace()); 83. .println("ProviderConfig.toString() = " + providerConfig.toString()); 84. } 85. 86. private static void showRequestConfigDefaultValue(RequesterConfig requesterConfig) { 87. .println("requesterConfig.getRSTTProperties() = " + requesterConfig.getRSTTProperties()); 88. .println("requesterConfig.getSecondaryParameters() = " + requesterConfig.getSecondaryParameters()); 89. .println("requesterConfig.getSOAPNamespace() = " + requesterConfig.getSOAPNamespace()); 90. .println("requesterConfig.getWSAddressingNamespace() = " + requesterConfig.getWSAddressingNamespace()); 91. 92. .println("requesterConfig.getMessageID() = " + requesterConfig.getMessageID()); 93. .println("requesterConfig.toString() = " + requesterConfig.toString()); 94. } 95. 96. private static void showSAMLToken(SAMLToken samlToken){ 97. .println("samlToken.getAssertionQName() = " + samlToken.getAssertionQName()); 98. .println("samlToken.getAudienceRestriction() = " + samlToken.getAudienceRestriction()); 99. .println("samlToken.getAuthenticationMethod() = " + samlToken.getAuthenticationMethod()); 100. .println("samlToken.getConfirmationMethod() = " + samlToken.getConfirmationMethod()); 101. .println("samlToken.getId() = " + samlToken.getId()); 102. .println("samlToken.getKeyIdentifier() = " + samlToken.getKeyIdentifier()); 103. .println("samlToken.getKeyIdentifierEncodingType() = " + samlToken.getKeyIdentifierEncodingType()); 104. .println("samlToken.getKeyIdentifierValueType() = " + samlToken.getKeyIdentifierValueType()); 105. .println("samlToken.getKeyName() = " + samlToken.getKeyName()); 106. .println("samlToken.getPrincipal() = " + samlToken.getPrincipal()); 107. .println("samlToken.getProperties() = " + samlToken.getProperties()); 108. .println("samlToken.getReferenceURI() = " + samlToken.getReferenceURI()); 109. .println("samlToken.getSAMLAttributes() = " + samlToken.getSAMLAttributes()); 110. .println("samlToken.getSamlCreated() = " + samlToken.getSamlCreated()); 111. .println("samlToken.getSamlExpires() = " + samlToken.getSamlExpires()); 112. .println("samlToken.getSamlID() = " + samlToken.getSamlID()); 113. .println("samlToken.getSAMLIssuerName() = " + samlToken.getSAMLIssuerName()); 114. .println("samlToken.getSAMLNameID() = " + samlToken.getSAMLNameID()); 115. .println("samlToken.getStringAttributes() = " + samlToken.getStringAttributes()); 116. .println("samlToken.getSubjectDNS() = " + samlToken.getSubjectDNS()); 117. .println("samlToken.getSubjectIPAddress() = " + samlToken.getSubjectIPAddress()); 118. .println("samlToken.getThumbprint() = " + samlToken.getThumbprint()); 119. .println("samlToken.getThumbprintEncodingType() = " + samlToken.getThumbprintEncodingType()); 120. .println("samlToken.getThumbprintValueType() = " + samlToken.getThumbprintValueType()); 121. .println("samlToken.getTokenQname() = " + samlToken.getTokenQname()); 122. .println("samlToken.getValueType() = " + samlToken.getValueType()); 123. 124. XMLStructure samlXmlStructure = samlToken.getXML(); 125. if (samlXmlStructure != null && samlXmlStructure instanceof OMStructure) { 126. OMStructure samlOMStructure = (OMStructure) samlXmlStructure; 127. .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. .println(sb.toString()); 141. } catch (Exception ex) { 142. .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. .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. .println("Caught exception: " + e2.getMessage()); 170. e2.printStackTrace(); 171. } 172. } 173. return output; 174. } 175. 176. }
WSSTrustClient class support for policy sets and bindings
The WS-Trust client function supports both application-specific bindings and general bindings for use with the trust client.policy set and binding documents. In addition, general bindings and default bindings are supported if the application is running in the application server environment. General bindings are supported in the thin client environment, but default bindings are not.
Manage the policy set and bindings for the WS-Trust client API is similar to managing a policy set and bindings for a web services client. However, differences exist that are unique to the WS-Trust client. One difference is that the WS-Trust client does not use policy set attachments. Instead, the policy set name and binding name are specified in a ProviderConfig object, as shown in line 36 and line 37 of the sample code.
When the WS-Trust client looks for bindings, the way the client manages the search scope differs from the web services client. If you do not specify the wstrustClientBindingScope property for the trust client binding, the system first searches the application for an application-specific binding with the binding name specified. If a binding is found, it is used for the trust client request. If no application-specific binding is found, the system searches the available general bindings for a binding with the name specified. If a general binding is found, it is used for the trust client request. If no bindings with the specific name are found, then default bindings are used in a server environment. Default bindings are only used in a server environment. If the binding scope is specified, only that scope is used for the binding search.
Line 38 of the sample code, providerConfig.setBindingScope("domain"), indicates that the example uses general bindings. We can also set the binding scope to application to indicate that the sample code uses application-specific bindings. The example uses the general binding named SamlTCSample. Both application-specific and general bindings are supported in the application server and the thin client environment. For more information about configuring the SamlTCSample bindings when the application is installed on the application server, read about configuring policy sets and bindings to communicate with STS.
The showProviderConfigDefaultValue(providerConfig) code on line 34 of the sample code shows the default settings. The sample code includes a utility method that prints out the contents of providerConfig.
Line 51 of the sample code, List <SecurityToken> securityTokens = client.issue(providerConfig, requesterConfig), sends an issue WS-Trust request. The second parameter on this line specifies the RequesterConfig object, and this parameter determines the content of the issue request. The code on line 41, RequesterConfig requesterConfig = WSSTrustClient.newRequesterConfig(Namespace.WST13), instantiates a RequesterConfig object used to construct the trust request using the WS-Trust v1.3 namespace. A utility function is shown on line 43: showRequestConfigDefaultValue(requesterConfig). This function displays the default settings for the RequesterConfig object. The code between lines 45 and 48 initializes the RequesterConfig to request a v1.1 SAML bearer token. This token is used to access the service endpoint using the SOAP 1.2 namespace. In the example, the service endpoint is https://user.MyCompany.com:9443/WSSampleSei/EchoService12.
JVM arguments support
Before executing the sample code, set up several Java Virtual Machine (JVM) arguments. The sample code implements the Username WSHTTPS default policy set, which has two requirements: 1) a Username token is sent to the STS; and 2) messages are protected using Secure Sockets Layer (SSL).
To set up the environment to meet these requirements, first configure the ssl.client.props file to define a truststore. For step-by-step instructions, read about running an unmanaged web services JAX-WS client.
To meet the second requirement regarding SSL message protection, obtain a copy of the STS SSL X.509 certificate and inset it into the truststore.
To do this, follow the steps in the topic, Using the retrieveSigners command in SSL, to enable server-to-server trust. Alternately, you can accept the STS certificate when you send the first trust request to the STS if the com.ibm.ssl.enableSignerExchangePrompt property in the profile_home/properties/ssl.client.props file is set to true. For more information about this option, read about changing the signer auto-exchange prompt at the client.
In addition, specify the client JAAS configuration file so that the client runtime environment can locate the Username token LoginModule JAAS login configuration. Specify the parameter using this code: -Djava.security.auth.login.config="%WAS_HOME%\properties\wsjaas_client.conf. We must also include the thin client jar, for example com.ibm.jaxws.thinclient_8.0.0.jar, in the classpath. For more information, read about running an unmanaged web services JAX-WS client application.
Sample code execution
A prerequisite to executing the sample code is to set up an external STS endpoint to issue a SAML 1.1 bearer token for the specified web services as defined by the RequesterConfiguration.RSTT.APPLIESTO_ADDRESS property.
Executing the sample code generates a WS-Trust issue request message, as shown in the example:
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>To view the WS-Trust request message, enable a client-side trace. Set the following JVM properties:
- -DtraceSettingsFile=MyTraceSettings.properties
- -Djava.util.logging.manager=com.ibm.ws.bootstrap.WsLogManager
- -Djava.util.logging.configureByServer=true
For more information about these properties, read about enabling trace on client and stand-alone applications. In addition to setting the JVM properties, also specify the trace setting, com.ibm.ws.wssecurity.*=all=enabled, in the MyTraceSettings.properties file. Look for Trust Client outgoing request: in the trace log file.
SAML token return
The code on line 51 of the sample code, List <SecurityToken> securityTokens = client.issue(providerConfig, requesterConfig), returns a SAML token if the WS-Trust issue request is processed successfully. The code between lines 54 and 64 processes the returned SAML token. The utility function shown on line 58, showSAMLToken((SAMLToken)token), displays the content of the received SAML token. The showSAMLToken() routine shows the SAML token as an XML document. An example of this XML document is provided in line 196 to line 233 of the sample code.
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>
Assembly tools
Configure policy sets and bindings to communicate with STS
Run an unmanaged web services JAX-WS client
Use the retrieveSigners command in SSL to enable server to server trust
Change the signer auto-exchange prompt at the client
Run a Java thin client application on a client machine
Enable trace on client and stand-alone applications
Related
API documentation - Application programming interfaces (package: com.ibm.websphere.wssecurity.wssapi.trust)