001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: Client.java,v 1.6 2008/10/10 00:15:09 hengming Exp $ 026 * 027 * Portions Copyrighted 2014 ForgeRock AS 028 */ 029package com.sun.identity.liberty.ws.soapbinding; 030 031import com.sun.identity.common.HttpURLConnectionManager; 032import com.sun.identity.common.SystemConfigurationUtil; 033import com.sun.identity.shared.configuration.SystemPropertiesManager; 034 035import com.sun.identity.liberty.ws.security.SecurityUtils; 036import com.sun.identity.saml.xmlsig.JKSKeyProvider; 037 038import com.sun.identity.shared.xml.XMLUtils; 039import java.io.InputStream; 040import java.io.IOException; 041import java.io.OutputStream; 042 043import java.net.URL; 044import java.net.URLConnection; 045 046import java.security.KeyStore; 047import java.security.NoSuchAlgorithmException; 048import java.security.KeyStoreException; 049import java.security.Provider; 050import java.security.Security; 051 052import javax.net.ssl.HttpsURLConnection; 053import javax.net.ssl.KeyManager; 054import javax.net.ssl.KeyManagerFactory; 055import javax.net.ssl.SSLContext; 056import javax.net.ssl.TrustManager; 057import javax.net.ssl.TrustManagerFactory; 058import javax.net.ssl.X509KeyManager; 059 060import javax.xml.transform.dom.DOMSource; 061import javax.xml.transform.stream.StreamResult; 062import javax.xml.transform.Transformer; 063 064import org.w3c.dom.Document; 065import org.w3c.dom.Element; 066 067/** 068 * The <code>Client</code> class provides web service clients with a method to 069 * send requests using SOAP connection to web service servers. 070 * 071 * @supported.all.api 072 */ 073public class Client { 074 075 private static KeyManager[] kms = null; 076 private static TrustManager[] tms = null; 077 private static X509KeyManager defaultX509km = null; 078 private static String defaultCertAlias = null; 079 private final static String SOAP_KEYSTORE_FILE_PROP = 080 "com.sun.identity.liberty.ws.soap.truststore"; 081 private final static String SOAP_KEYSTORE_PASS_FILE_PROP = 082 "com.sun.identity.liberty.ws.soap.storepass"; 083 private final static String SOAP_KEYSTORE_TYPE_PROP = 084 "com.sun.identity.liberty.ws.soap.storetype"; 085 private final static String SOAP_PRIVATE_KEY_PASS_FILE_PROP = 086 "com.sun.identity.liberty.ws.soap.keypass"; 087 private final static String SOAP_TRUST_MNGR_PROP = 088 "com.sun.identity.liberty.ws.soap.trustmanager"; 089 private final static String SOAP_TRUST_SECMNGR_ALGO_PROP = 090 "com.sun.identity.liberty.ws.soap.securitymanager.algorithm"; 091 092 static { 093 defaultCertAlias = SystemPropertiesManager.get( 094 "com.sun.identity.liberty.ws.soap.certalias"); 095 } 096 097 private Client() {} 098 099 /** 100 * Sends a request to a SOAP endpoint and returns the response. The server 101 * only contains one servlet for different web services. So the SOAP 102 * endpoint URL has format 'servlet_URL/key' 103 * 104 * @param req the request 105 * @param connectTo the SOAP endpoint URL 106 * @return a response from the SOAP endpoint 107 * @throws SOAPBindingException if an error occurs while sending the 108 * message 109 * @throws SOAPFaultException if the response is a SOAP Fault 110 */ 111 public static Message sendRequest(Message req,String connectTo) 112 throws SOAPBindingException, SOAPFaultException { 113 return sendRequest(req, connectTo, null, null); 114 } 115 116 /** 117 * Sends a request to a SOAP endpoint and returns the response. The server 118 * only contains one servlet for different web services. So the SOAP 119 * endpoint URL has format 'servlet_URL/key'. 120 * 121 * @param req the request message. 122 * @param connectTo the SOAP endpoint URL 123 * @param certAlias the cert alias of a client certificate being used in 124 * SSL 125 * @return a response from the SOAP endpoint 126 * @throws SOAPBindingException if an error occurs while sending the 127 * message 128 * @throws SOAPFaultException if the response is a SOAP Fault 129 */ 130 public static Message sendRequest(Message req,String connectTo, 131 String certAlias) throws SOAPBindingException, SOAPFaultException { 132 return sendRequest(req, connectTo, certAlias, null); 133 } 134 135 /** 136 * Sends a request to a SOAP endpoint and returns the response. The server 137 * only contains one servlet for different web services. So the SOAP 138 * endpoint URL has format 'servlet_URL/key'. 139 * 140 * @param req the request message. 141 * @param connectTo the SOAP endpoint URL 142 * @param certAlias the cert alias of a client certificate 143 * @param soapAction the SOAPAction header 144 * @return a response from the SOAP endpoint 145 * @throws SOAPFaultException if a SOAP Fault occurs 146 * @throws SOAPBindingException if a error occurs while processing, 147 * sending or receiving Message 148 */ 149 public static Message sendRequest(Message req,String connectTo, 150 String certAlias,String soapAction) 151 throws SOAPBindingException, SOAPFaultException { 152 URLConnection con = null; 153 154 try { 155 con = getConnection(connectTo, certAlias); 156 } catch (Exception e) { 157 Utils.debug.error("Client:sendRequest", e); 158 throw new SOAPBindingException(e.getMessage()); 159 } 160 161 if(soapAction == null || soapAction.length() == 0) { 162 soapAction = ""; 163 } 164 165 con.setRequestProperty(SOAPBindingConstants.SOAP_ACTION_HEADER, 166 soapAction); 167 168 169 Document doc = null; 170 int securityProfileType = req.getSecurityProfileType(); 171 if (securityProfileType == Message.ANONYMOUS || 172 securityProfileType == Message.BEARER_TOKEN) { 173 doc = req.toDocument(true); 174 } else { 175 176 Element sigElem = SecurityUtils.signMessage(req); 177 if (sigElem == null) { 178 String msg = Utils.bundle.getString("cannotSignRequest"); 179 Utils.debug.error("Client.sendRequest: " + msg); 180 throw new SOAPBindingException(msg); 181 } 182 doc = sigElem.getOwnerDocument(); 183 } 184 if (Utils.debug.messageEnabled()) { 185 Utils.debug.message("Client.sendRequest: signed request\n" + req); 186 } 187 188 OutputStream os = null; 189 try { 190 os = con.getOutputStream(); 191 Transformer transformer = XMLUtils.getTransformerFactory().newTransformer(); 192 transformer.setOutputProperty("omit-xml-declaration", "yes"); 193 transformer.transform(new DOMSource(doc.getDocumentElement()), 194 new StreamResult(os)); 195 } catch (Exception e) { 196 Utils.debug.error("Client:sendRequest", e); 197 throw new SOAPBindingException(e.getMessage()); 198 } finally { 199 if (os != null) { 200 try { 201 os.close(); 202 } catch (Exception e) { 203 Utils.debug.error("Client:sendRequest", e); 204 } 205 } 206 } 207 208 Message resp = null; 209 InputStream is = null; 210 try { 211 is = con.getInputStream(); 212 resp = new Message(is); 213 if (resp.getSOAPFault() != null) { 214 throw new SOAPFaultException(resp); 215 } 216 Utils.enforceProcessingRules(resp, 217 req.getCorrelationHeader().getMessageID(), false); 218 } catch (IOException e) { 219 Utils.debug.error("Client:sendRequest", e); 220 throw new SOAPBindingException(e.getMessage()); 221 } finally { 222 if (is != null) { 223 try { 224 is.close(); 225 } catch (Exception e) { 226 Utils.debug.error("Client:sendRequest", e); 227 } 228 } 229 } 230 231 resp.setProtocol(con.getURL().getProtocol()); 232 if (resp.getSecurityProfileType() != Message.ANONYMOUS && 233 !SecurityUtils.verifyMessage(resp)) { 234 235 String msg = Utils.bundle.getString("cannotVerifySignature"); 236 Utils.debug.error("Client.sendRequest: " + msg); 237 throw new SOAPBindingException(msg); 238 } 239 return resp; 240 } 241 242 /** 243 * Gets URLConnection associated with the endpoint. If it is a SSL 244 * connection, the certAlias will be used to get the client certificate. 245 * 246 * @param endpoint the url of the SOAP receiver 247 * @param certAlias the cert alias of a client certificate 248 * @return a URLConnection object 249 * @throws Exception if an error occurs while connecting to server 250 */ 251 private static URLConnection getConnection(String endpoint,String certAlias) 252 throws Exception { 253 URL url = new URL(endpoint); 254 URLConnection con = HttpURLConnectionManager.getConnection(url); 255 256 if (Utils.debug.messageEnabled()) { 257 Utils.debug.message("Client.getConnection: con class = " + 258 con.getClass()); 259 } 260 261 if (con instanceof HttpsURLConnection) { 262 if (kms == null) { 263 initializeJSSE(); 264 } 265 if (certAlias != null) { 266 kms[0] = new WSX509KeyManager(defaultX509km, certAlias); 267 } else { 268 kms[0] = new WSX509KeyManager(defaultX509km, defaultCertAlias); 269 } 270 271 SSLContext ctx = SSLContext.getInstance("TLS"); 272 ctx.init(kms, tms, null); 273 HttpsURLConnection scon = (HttpsURLConnection) con; 274 scon.setSSLSocketFactory(ctx.getSocketFactory()); 275 } else { 276 if (Utils.debug.warningEnabled()) { 277 Utils.debug.warning("Client.getConnection: not instance of " + 278 "HttpsURLConnection, client cert not selected."); 279 } 280 } 281 282 con.setDoInput(true); 283 con.setDoOutput(true); 284 con.setRequestProperty("content-type", "text/xml"); 285 286 return con; 287 } 288 289 290 291 292 /** 293 * Initializes JSSE enviroment. 294 * 295 * @throws Exception if an error occurs while initializing JSSE 296 */ 297 private static void initializeJSSE() throws Exception { 298 // put SunJSSE at fisrt place, so that JSSE will work 299 Provider provider = Security.getProvider("SunJSSE"); 300 if (provider != null) { 301 Security.removeProvider("SunJSSE"); 302 Security.insertProviderAt(provider, 1); 303 } 304 305 String algorithm = SystemPropertiesManager.get( 306 SOAP_TRUST_SECMNGR_ALGO_PROP); 307 if(algorithm == null || algorithm.length() <= 0) { 308 algorithm = "SunX509"; 309 } 310 JKSKeyProvider jkskp = createKeyProvider() ; 311 KeyStore trustStore = jkskp.getKeyStore(); 312 KeyManagerFactory kf = KeyManagerFactory.getInstance(algorithm); 313 kf.init(trustStore,jkskp.getPrivateKeyPass().toCharArray() ); 314 315 kms = kf.getKeyManagers(); 316 defaultX509km = (X509KeyManager)kms[0]; 317 318 defineTrustManager(trustStore, algorithm); 319 320 } 321 322 /** 323 * Define a Trust manager 324 * 325 * @param trustStore the keystore used to store certificates 326 * @param algorithm the algorithm to user 327 * @throws Exception if an error occurs while instantiating the custom 328 * class or using the keystore 329 */ 330 private static void defineTrustManager(KeyStore trustStore, 331 String algorithm) 332 throws SOAPBindingException{ 333 boolean error = false ; 334 try{ 335 TrustManagerFactory tf = 336 TrustManagerFactory.getInstance(algorithm); 337 tf.init(trustStore); 338 TrustManager[] defaultTrustManagers = tf.getTrustManagers(); 339 String trustManagerDefinition = SystemPropertiesManager.get( 340 SOAP_TRUST_MNGR_PROP); 341 if(trustManagerDefinition != null 342 && trustManagerDefinition.length() > 0) { 343 tms = new TrustManager[defaultTrustManagers.length + 1]; 344 tms[0] = (TrustManager) 345 Class.forName(trustManagerDefinition).newInstance(); 346 for(int i = 0; i < defaultTrustManagers.length; i++) { 347 tms[i + 1 ] = defaultTrustManagers[i]; 348 } 349 } else { 350 tms = defaultTrustManagers; 351 } 352 }catch(ClassNotFoundException cnfe){ 353 Utils.debug.error( 354 "Client.defineTrustManager class not found: " ,cnfe); 355 error = true ; 356 }catch(InstantiationException ie){ 357 Utils.debug.error( 358 "Client.defineTrustManager cannot instantiate: " , ie); 359 error = true ; 360 }catch(NoSuchAlgorithmException nsae){ 361 Utils.debug.error( 362 "Client.defineTrustManager no algorithm: " , nsae); 363 error = true ; 364 }catch(IllegalAccessException iae){ 365 Utils.debug.error( 366 "Client.defineTrustManager illegal access: " , iae); 367 error = true ; 368 }catch(KeyStoreException kse){ 369 Utils.debug.error( 370 "Client.defineTrustManager keystore: " , kse); 371 error = true ; 372 } 373 if(error ){ 374 String msg = Utils.bundle.getString("cannotDefineTrustManager"); 375 throw new SOAPBindingException(msg); 376 } 377 378 } 379 380 381 382 383 /** 384 * Checks if Trust Keystore properties are defined 385 * @return true if a specific trust store is to be used 386 **/ 387 388 private static boolean useSpecificTrustStore(){ 389 return( 390 (SystemConfigurationUtil.getProperty(SOAP_KEYSTORE_FILE_PROP)!= null)&& 391 (SystemConfigurationUtil.getProperty(SOAP_KEYSTORE_PASS_FILE_PROP)!= null)&& 392 (SystemConfigurationUtil.getProperty(SOAP_KEYSTORE_TYPE_PROP)!= null)&& 393 (SystemConfigurationUtil.getProperty(SOAP_PRIVATE_KEY_PASS_FILE_PROP)!= null)); 394 } 395 396 /** 397 * Create a JKSKeyProvider using either default properties or specific properties 398 * @return the JKSKeyProvider 399 **/ 400 401 private static JKSKeyProvider createKeyProvider() { 402 JKSKeyProvider jksKp ; 403 if (useSpecificTrustStore()) { 404 jksKp = new JKSKeyProvider( 405 SOAP_KEYSTORE_FILE_PROP,SOAP_KEYSTORE_PASS_FILE_PROP, 406 SOAP_KEYSTORE_TYPE_PROP, SOAP_PRIVATE_KEY_PASS_FILE_PROP); 407 } else { 408 jksKp = new JKSKeyProvider(); 409 } 410 return jksKp ; 411 } 412 413 414 415 416}
Copyright © 2010-2017, ForgeRock All Rights Reserved.