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: DiscoveryClient.java,v 1.5 2008/12/16 01:48:31 exu Exp $ 026 * 027 */ 028 029package com.sun.identity.liberty.ws.disco; 030 031import java.util.List; 032import java.util.ArrayList; 033import java.util.Iterator; 034 035import org.w3c.dom.Element; 036 037import com.sun.identity.liberty.ws.common.wsse.BinarySecurityToken; 038import com.sun.identity.liberty.ws.soapbinding.Message; 039import com.sun.identity.liberty.ws.soapbinding.ProviderHeader; 040import com.sun.identity.liberty.ws.soapbinding.Client; 041import com.sun.identity.liberty.ws.soapbinding.SOAPBindingConstants; 042import com.sun.identity.liberty.ws.soapbinding.SOAPBindingException; 043import com.sun.identity.liberty.ws.soapbinding.Utils; 044import com.sun.identity.liberty.ws.disco.common.*; 045import com.sun.identity.liberty.ws.security.*; 046import com.sun.identity.shared.configuration.SystemPropertiesManager; 047 048/** 049 * The class <code>DiscoveryClient</code> provides methods to send 050 * Discovery Service query and modify. 051 * Note: Current implementation uses <code>JAXB</code> objects and no wrapper 052 * classes are used. 053 * @supported.all.api 054 */ 055public class DiscoveryClient { 056 057 private String connectTo = null; 058 private int clientMech = Message.ANONYMOUS; 059 private ResourceID resID = null; 060 private EncryptedResourceID encResID = null; 061 private String certAlias = null; 062 private String providerID = null; 063 private boolean clientAuth = false; 064 private SecurityAssertion assertion = null; 065 private List assertions = null; 066 private BinarySecurityToken token = null; 067 private ResourceOffering offering = null; 068 private boolean processed = true; 069 private String soapAction = null; 070 private Object session = null; 071 private String wsfVersion = Utils.getDefaultWSFVersion(); 072 073 /** 074 * Constructor, connects to Discovery Service without web service security 075 * token. 076 * 077 * @param soapURI URI of the SOAP end point for this discovery 078 * service instance 079 * @param providerID ID of the web service client. 080 */ 081 public DiscoveryClient (String soapURI, String providerID) { 082 connectTo = soapURI; 083 this.providerID = providerID; 084 } 085 086 /** 087 * Constructor, connects to Discovery Service using <code>WSS</code> SAML 088 * Token. 089 * 090 * @param assertion <code>WSS</code> SAML Token 091 * @param soapURI URI of the SOAP end point for this discovery 092 * service instance 093 * @param providerID ID of the web service client. 094 */ 095 public DiscoveryClient (SecurityAssertion assertion, 096 String soapURI, 097 String providerID) 098 { 099 connectTo = soapURI; 100 if ((assertion != null) && (assertion.isBearer())) { 101 clientMech = Message.BEARER_TOKEN; 102 } else { 103 clientMech = Message.SAML_TOKEN; 104 } 105 this.assertion = assertion; 106 this.providerID = providerID; 107 } 108 109 /** 110 * Constructor, connects to Discovery Service using <code>WSS X509</code> 111 * Token. 112 * @param token <code>WSS X.509</code> Certificate Token 113 * @param soapURI URI of the SOAP end point for this discovery 114 * service instance. 115 * @param providerID ID of the web service client. 116 */ 117 public DiscoveryClient (BinarySecurityToken token, 118 String soapURI, 119 String providerID) 120 { 121 connectTo = soapURI; 122 clientMech = Message.X509_TOKEN; 123 this.token = token; 124 this.providerID = providerID; 125 } 126 127 /** 128 * Constructor, connects to Discovery Service specified by the resource 129 * offering, security mechanism/SOAP endpoint defined in the 130 * <code>ResourceOffering</code> will be used. 131 * 132 * @param resourceOffering resource offering for this 133 * discovery service instance 134 * @param session session of the <code>WSC</code> 135 * @param providerID ID of the web service client. 136 */ 137 public DiscoveryClient(ResourceOffering resourceOffering, 138 Object session, 139 String providerID) 140 { 141 offering = resourceOffering; 142 processed = false; 143 this.session = session; 144 this.providerID = providerID; 145 } 146 147 /** 148 * Constructor, connects to Discovery Service specified by the resource 149 * offering, security mechanism/SOAP endpoint defined in the 150 * <code>ResourceOffering</code> will be used. 151 * 152 * @param resourceOffering resource offering for this 153 * discovery service instance 154 * @param session session of the <code>WSC</code> 155 * @param providerID ID of the web service client. 156 * @param assertions List of assertions. 157 */ 158 public DiscoveryClient(ResourceOffering resourceOffering, 159 Object session, 160 String providerID, 161 List assertions) 162 { 163 offering = resourceOffering; 164 processed = false; 165 this.session = session; 166 this.providerID = providerID; 167 this.assertions = assertions; 168 } 169 170 private void processResourceOffering() throws DiscoveryException { 171 ServiceInstance instance = offering.getServiceInstance(); 172 if (!(instance.getServiceType().equals(DiscoConstants.DISCO_NS))) { 173 DiscoSDKUtils.debug.error("DiscoveryClient.processResourceOffering: " + 174 "ServiceType in ResourceOffering is not discovery service type."); 175 throw new DiscoveryException( 176 DiscoSDKUtils.bundle.getString("notDiscoServiceType")); 177 } 178 resID = offering.getResourceID(); 179 encResID = offering.getEncryptedResourceID(); 180 List descriptions = instance.getDescription(); 181 /* 182 * Iterate through supported security profiles until we find one 183 * that we support (and we should always do so if the spec is 184 * being complied with). They should be in decreasing order of 185 * preference... 186 */ 187 // TODO: support wsdl form 188 Iterator i = descriptions.iterator(); 189 while (i.hasNext()) { 190 Description desc = (Description) i.next(); 191 connectTo = desc.getEndpoint(); 192 soapAction = desc.getSoapAction(); 193 Iterator j = desc.getSecurityMechID().iterator(); 194 while (j.hasNext()) { 195 String mech = (String) j.next(); 196 if ((mech.equals(Message.NULL_NULL)) || 197 (mech.equals(Message.TLS_NULL)) || 198 (mech.equals(Message.CLIENT_TLS_NULL))) 199 { 200 clientMech = Message.ANONYMOUS; 201 DiscoSDKUtils.debug.message("DiscoClient: null"); 202 if (mech.equals(Message.CLIENT_TLS_NULL)) { 203 clientAuth = true; 204 DiscoSDKUtils.debug.message("DiscoClient: clientAuth on"); 205 } 206 return; 207 } else if ((mech.equals(Message.NULL_X509)) || 208 (mech.equals(Message.TLS_X509)) || 209 (mech.equals(Message.CLIENT_TLS_X509)) || 210 (mech.equals(Message.NULL_X509_WSF11)) || 211 (mech.equals(Message.TLS_X509_WSF11)) || 212 (mech.equals(Message.CLIENT_TLS_X509_WSF11))) 213 { 214 clientMech = Message.X509_TOKEN; 215 if (mech.equals(Message.NULL_X509) || 216 mech.equals(Message.TLS_X509) || 217 mech.equals(Message.CLIENT_TLS_X509)) { 218 wsfVersion = SOAPBindingConstants.WSF_10_VERSION; 219 } else { 220 wsfVersion = SOAPBindingConstants.WSF_11_VERSION; 221 } 222 DiscoSDKUtils.debug.message("DiscoClient: x509"); 223 try { 224 SecurityTokenManagerClient stm = 225 new SecurityTokenManagerClient(session); 226 if (certAlias == null) { 227 certAlias = SystemPropertiesManager.get( 228 "com.sun.identity.liberty.ws.wsc.certalias"); 229 } 230 stm.setCertAlias(certAlias); 231 token = stm.getX509CertificateToken(); 232 token.setWSFVersion(wsfVersion); 233 } catch (Exception e) { 234 DiscoSDKUtils.debug.error("DiscoveryClient.processResource" 235 + "Offering: couldn't generate X509 token: ", e); 236 throw new DiscoveryException(e.getMessage()); 237 } 238 if (mech.equals(Message.CLIENT_TLS_X509) || 239 mech.equals(Message.CLIENT_TLS_X509_WSF11)) { 240 clientAuth = true; 241 DiscoSDKUtils.debug.message("DiscoClient: clientAuth on"); 242 } 243 return; 244 } else if ((mech.equals(Message.NULL_SAML)) || 245 (mech.equals(Message.TLS_SAML)) || 246 (mech.equals(Message.CLIENT_TLS_SAML)) || 247 (mech.equals(Message.NULL_SAML_WSF11)) || 248 (mech.equals(Message.TLS_SAML_WSF11)) || 249 (mech.equals(Message.CLIENT_TLS_SAML_WSF11))) 250 { 251 clientMech = Message.SAML_TOKEN; 252 if (mech.equals(Message.NULL_SAML) || 253 mech.equals(Message.TLS_SAML) || 254 mech.equals(Message.CLIENT_TLS_SAML)) { 255 wsfVersion = SOAPBindingConstants.WSF_10_VERSION; 256 } else { 257 wsfVersion = SOAPBindingConstants.WSF_11_VERSION; 258 } 259 DiscoSDKUtils.debug.message("DiscoClient: saml token"); 260 List credRefs = desc.getCredentialRef(); 261 if ((credRefs == null) || (credRefs.size() == 0)) { 262 throw new DiscoveryException( 263 DiscoSDKUtils.bundle.getString("noCredential")); 264 } else { 265 String credID = (String) credRefs.get(0); 266 if (assertions == null) { 267 throw new DiscoveryException( 268 DiscoSDKUtils.bundle.getString("noCredential")); 269 } else { 270 Iterator iter1 = assertions.iterator(); 271 while (iter1.hasNext()) { 272 SecurityAssertion sassert = (SecurityAssertion) 273 iter1.next(); 274 if (credID.equals(sassert.getAssertionID())) { 275 assertion = sassert; 276 break; 277 } 278 } 279 if (assertion == null) { 280 throw new DiscoveryException( 281 DiscoSDKUtils.bundle.getString("noCredential")); 282 } 283 } 284 } 285 if (mech.equals(Message.CLIENT_TLS_SAML) || 286 mech.equals(Message.CLIENT_TLS_SAML_WSF11)) { 287 clientAuth = true; 288 DiscoSDKUtils.debug.message("DiscoClient: clientAuth on"); 289 } 290 return; 291 } else if ((mech.equals(Message.NULL_BEARER)) || 292 (mech.equals(Message.TLS_BEARER)) || 293 (mech.equals(Message.CLIENT_TLS_BEARER)) || 294 (mech.equals(Message.NULL_BEARER_WSF11)) || 295 (mech.equals(Message.TLS_BEARER_WSF11)) || 296 (mech.equals(Message.CLIENT_TLS_BEARER_WSF11))) 297 { 298 clientMech = Message.BEARER_TOKEN; 299 if (mech.equals(Message.NULL_BEARER) || 300 mech.equals(Message.TLS_BEARER) || 301 mech.equals(Message.CLIENT_TLS_BEARER)) { 302 wsfVersion = SOAPBindingConstants.WSF_10_VERSION; 303 } else { 304 wsfVersion = SOAPBindingConstants.WSF_11_VERSION; 305 } 306 DiscoSDKUtils.debug.message("DiscoClient: bearer token"); 307 List credRefs = desc.getCredentialRef(); 308 if ((credRefs == null) || (credRefs.size() == 0)) { 309 throw new DiscoveryException( 310 DiscoSDKUtils.bundle.getString("noCredential")); 311 } else { 312 String credID = (String) credRefs.get(0); 313 if (credID == null || assertions == null) { 314 throw new DiscoveryException( 315 DiscoSDKUtils.bundle.getString("noCredential")); 316 } else { 317 Iterator iter2 = assertions.iterator(); 318 while (iter2.hasNext()) { 319 SecurityAssertion sassert = (SecurityAssertion) 320 iter2.next(); 321 if (credID.equals(sassert.getAssertionID())) { 322 assertion = sassert; 323 break; 324 } 325 } 326 if (assertion == null) { 327 throw new DiscoveryException( 328 DiscoSDKUtils.bundle.getString("noCredential")); 329 } 330 } 331 } 332 if (mech.equals(Message.CLIENT_TLS_BEARER) || 333 mech.equals(Message.CLIENT_TLS_BEARER_WSF11)) { 334 clientAuth = true; 335 DiscoSDKUtils.debug.message("DiscoClient: clientAuth on"); 336 } 337 return; 338 } 339 } 340 } 341 // still here? couldn't find supported mech id 342 343 DiscoSDKUtils.debug.error("DiscoveryClient.processResourceOffering: " + 344 "Couldn't find supported SecurityMechID from ResourceOffering."); 345 throw new DiscoveryException( 346 DiscoSDKUtils.bundle.getString("noSupportedSecuMechID")); 347 } 348 349 /** 350 * Sets the alias for the client certificate. If none is set, a default 351 * client certificate will be used. 352 * @param certAlias certificate alias name 353 */ 354 public void setClientCert(String certAlias) { 355 this.certAlias = certAlias; 356 } 357 358 /** 359 * Sets flag to indicate whether the connection is SSL/TLS with client 360 * authentication. When this flag is set to true, the message will not be 361 * signed according to the spec. If you want to sign the message always, 362 * do not set this flag to true, even when the connection is SSL/TLS with 363 * client authentication. 364 * 365 * @param value The flag value to be set 366 */ 367 public void setClientAuthentication(boolean value) { 368 clientAuth = value; 369 } 370 371 /** 372 * Sets the resource ID to be accessed. 373 * @param resourceID resource ID 374 */ 375 public void setResourceID(String resourceID) { 376 resID = new ResourceID(resourceID); 377 } 378 379 /** 380 * Sets the encrypted resource ID to be accessed. 381 * 382 * @param resourceID encrypted resource ID. 383 */ 384 public void setResourceID(EncryptedResourceID resourceID) { 385 encResID = resourceID; 386 } 387 388 /** 389 * Sets the provider ID. 390 * 391 * @param providerID ID of the web service client. 392 */ 393 public void setProviderID(String providerID) { 394 this.providerID = providerID; 395 } 396 397 /** 398 * Queries discovery service for <code>ResourceOffering</code> given list of 399 * service types. 400 * 401 * @param serviceTypes List of <code>serviceTypes</code> as 402 * <code>java.lang.String</code> to be queried 403 * @return Query response Element corresponding to the query 404 * @exception DiscoveryException if error occurs 405 */ 406 public QueryResponse getResourceOffering(java.util.List serviceTypes) 407 throws DiscoveryException 408 { 409 if (!processed) { 410 processResourceOffering(); 411 processed = true; 412 } 413 Query query = null; 414 Iterator i = serviceTypes.iterator(); 415 List serviceList = new ArrayList(); 416 while (i.hasNext()) { 417 serviceList.add(new RequestedService(null, (String) i.next())); 418 } 419 if (resID != null) { 420 query = new Query(resID, serviceList); 421 } else { 422 query = new Query(encResID, serviceList); 423 } 424 425 return getResourceOffering(query); 426 } 427 428 /** 429 * Queries discovery service for resource offering. 430 * @param query discovery query object 431 * @return Query response Element corresponding to the query 432 * @exception DiscoveryException if error occurs 433 */ 434 public QueryResponse getResourceOffering(Query query) 435 throws DiscoveryException 436 { 437 Message req = createRequest(); 438 req.setSOAPBody(DiscoSDKUtils.parseXML(query.toString())); 439 return new QueryResponse(getResponse(req)); 440 } 441 442 443 private Message createRequest() throws DiscoveryException { 444 if (!processed) { 445 processResourceOffering(); 446 processed = true; 447 } 448 // create new Message according to different secuMechID 449 Message req = null; 450 ProviderHeader provH = null; 451 if (providerID != null) { 452 try { 453 provH = new ProviderHeader(providerID); 454 } catch (SOAPBindingException sbe) { 455 throw new DiscoveryException(sbe.getMessage()); 456 } 457 } 458 if (clientMech == Message.X509_TOKEN) { 459 DiscoSDKUtils.debug.message( 460 "DiscoveryClient.createRequest: mech=x509"); 461 try { 462 req = new Message(provH, token); 463 } catch (SOAPBindingException sbe) { 464 throw new DiscoveryException(sbe.getMessage()); 465 } 466 } else if ((clientMech == Message.SAML_TOKEN) || 467 (clientMech == Message.BEARER_TOKEN)) { 468 if (DiscoSDKUtils.debug.messageEnabled()) { 469 DiscoSDKUtils.debug.message("DiscoveryClient.createRequest: " 470 + "mech=saml or bearer"); 471 } 472 try { 473 req = new Message(provH, assertion); 474 } catch (SOAPBindingException sbe) { 475 throw new DiscoveryException(sbe.getMessage()); 476 } 477 } else { 478 if (DiscoSDKUtils.debug.messageEnabled()) { 479 DiscoSDKUtils.debug.message("DiscoveryClient.createRequest: " 480 + "mech=anon"); 481 } 482 try { 483 req = new Message(provH); 484 } catch (SOAPBindingException sbe) { 485 throw new DiscoveryException(sbe.getMessage()); 486 } 487 } 488 if (clientAuth) { 489 req.setClientAuthentication(clientAuth); 490 } 491 req.setWSFVersion(wsfVersion); 492 return req; 493 } 494 495 private Element getResponse(Message req) throws DiscoveryException { 496 Message resp = null; 497 try { 498 resp = Client.sendRequest(req, connectTo, certAlias, soapAction); 499 } catch (Exception e) { 500 DiscoSDKUtils.debug.error("DiscoveryClient.getResponse:", e); 501 throw new DiscoveryException(e.getMessage()); 502 } 503 List bodies = resp.getBodies(); 504 if (!(bodies.size() == 1)) { 505 DiscoSDKUtils.debug.error("DiscoveryClient.getResponse: SOAP Response " 506 + "didn't contain one SOAPBody."); 507 throw new DiscoveryException( 508 DiscoSDKUtils.bundle.getString("oneBody")); 509 } 510 return ((Element) bodies.iterator().next()); 511 512 } 513 514 /** 515 * Modifies discovery resource offering. 516 * @param modify List of Modify object 517 * @return List of <code>ModifyResponse</code> object 518 * @exception DiscoveryException if error occurs 519 */ 520 public ModifyResponse modify(Modify modify) 521 throws DiscoveryException 522 { 523 Message req = createRequest(); 524 req.setSOAPBody(DiscoSDKUtils.parseXML(modify.toString())); 525 526 return new ModifyResponse(getResponse(req)); 527 } 528 529 /** 530 * Sets the web services version. 531 * 532 * @param wsfVersion the web services version that should be used. 533 */ 534 public void setWSFVersion(String wsfVersion) { 535 this.wsfVersion = wsfVersion; 536 } 537}