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: SAMLClient.java,v 1.6 2008/08/19 19:11:11 veiming Exp $ 026 * 027 */ 028 029 030package com.sun.identity.saml; 031 032import java.io.*; 033import java.util.*; 034import java.net.URL; 035import javax.servlet.http.*; 036import com.sun.identity.common.SystemConfigurationUtil; 037import com.sun.identity.common.SystemConfigurationException; 038import com.sun.identity.plugin.session.SessionException; 039import com.sun.identity.plugin.session.SessionManager; 040import com.sun.identity.plugin.session.SessionProvider; 041import com.sun.identity.saml.common.*; 042import com.sun.identity.saml.assertion.*; 043import com.sun.identity.saml.protocol.*; 044import com.sun.identity.saml.servlet.SAMLSOAPReceiver; 045import com.sun.identity.shared.jaxrpc.SOAPClient; 046import com.sun.identity.shared.xml.XMLUtils; 047import org.w3c.dom.Document; 048import org.w3c.dom.Node; 049import org.w3c.dom.NodeList; 050import org.w3c.dom.Element; 051 052/** 053 * The class <code>SAMLClient</code> provides interfaces 054 * to do Web and POST profile as specified by SAML specification. It 055 * also provides methods to get Assertions based on Artifacts. 056 * @supported.api 057 */ 058 059public class SAMLClient { 060 /** 061 * This private method is designed to do the SAML Single-Sign-On. 062 * It is called internally by doWebArtifact and doWebPOST methods. 063 * @param request HTTP Servlet Request 064 * @param response HTTP Servlet Response 065 * @param target the target URL 066 * @param service the service name 067 * @exception IOException if an input or output exception occurs when 068 * redirecting to service <code>URL</code> 069 * @exception SAMLException if SAML error occurs during Single-Sign-On. 070 */ 071 private static void doSSO(HttpServletRequest request, 072 HttpServletResponse response, 073 String target, String service) 074 throws IOException, SAMLException { 075 if (request == null || response == null || target == null) { 076 SAMLUtils.debug.error("SAMLClient:Input parameter is null."); 077 throw new SAMLException(SAMLUtils.bundle.getString("nullInput")); 078 } 079 if ((!service.equals(SAMLConstants.SAML_AWARE_NAMING)) && 080 (!service.equals(SAMLConstants.SAML_POST_NAMING)) && 081 (!service.equals(SAMLConstants.SAML_SOAP_NAMING))) { 082 SAMLUtils.debug.error("SAMLClient:illegal naming service name."); 083 throw new SAMLException( 084 SAMLUtils.bundle.getString("illegalNamingService")); 085 } 086 Object ssoToken = null; 087 SessionProvider sessionProvider; 088 try { 089 sessionProvider = SessionManager.getProvider(); 090 ssoToken =sessionProvider.getSession(request); 091 if (ssoToken == null) { 092 SAMLUtils.debug.error("SAMLClient:SSOToken is null."); 093 throw new SAMLException( 094 SAMLUtils.bundle.getString("nullSSOToken")); 095 } 096 if (!sessionProvider.isValid(ssoToken)) { 097 SAMLUtils.debug.error("SAMLClient:Session is invalid."); 098 throw new SAMLException( 099 SAMLUtils.bundle.getString("invalidSSOToken")); 100 } 101 } catch (SessionException se) { 102 SAMLUtils.debug.error("SAMLClient", se); 103 throw new SAMLException("SAMLClient:doSSO:" + se.getMessage()); 104 } 105 URL weburl = null; 106 try { 107 URL serverurl = new URL(SAMLServiceManager.getServerURL()); 108 weburl = SystemConfigurationUtil.getServiceURL(service, 109 serverurl.getProtocol(), serverurl.getHost(), 110 serverurl.getPort(), serverurl.getPath()); 111 112 } catch(SystemConfigurationException ue) { 113 SAMLUtils.debug.error("SAMLClient", ue); 114 throw new SAMLException( 115 SAMLUtils.bundle.getString("URLNotFoundException")); 116 } 117 StringBuffer redirectedurl = new StringBuffer(200); 118 String tname = (String) SAMLServiceManager. 119 getAttribute(SAMLConstants.TARGET_SPECIFIER); 120 redirectedurl.append(weburl).append("?").append(tname).append("="). 121 append(target); 122 response.sendRedirect(redirectedurl.toString()); 123 } 124 125 /** 126 * This method is designed to do the SAML web-browser profile with 127 * Artifact. Once the browser (user) authenticated to OpenSSO, 128 * it can call this method to complete the single sign on to the 129 * target host and be redirected to the specified target site. 130 * @param request HTTP Servlet Request 131 * @param response HTTP Servlet Response 132 * @param target A String representing the target URL 133 * @exception IOException if an input or output exception occurs when 134 * redirecting to service <code>URL</code> 135 * @exception SAMLException if SAML error occurs during the process 136 * @supported.api 137 */ 138 public static void doWebArtifact(HttpServletRequest request, 139 HttpServletResponse response, 140 String target) 141 throws IOException, SAMLException { 142 doSSO(request, response, target, SAMLConstants.SAML_AWARE_NAMING); 143 } 144 145 /** 146 * This method is designed to do the SAML web-browser POST profile. 147 * Once the browser (user) authenticated to OpenSSO, 148 * it can call this method 149 * to complete the single sign on to the target host and be 150 * redirected to the target site. 151 * @param request HTTP Servlet Request 152 * @param response HTTP Servlet Response 153 * @param target A String representing the target URL 154 * @exception IOException if an input or output exception occurs when 155 * redirecting to service <code>URL</code> 156 * @exception SAMLException if SAML error occurs during the process 157 * @supported.api 158 */ 159 public static void doWebPOST(HttpServletRequest request, 160 HttpServletResponse response, 161 String target) 162 throws IOException, SAMLException { 163 doSSO(request, response, target, SAMLConstants.SAML_POST_NAMING); 164 } 165 166 /** 167 * This method returns the Assertion for the corresponding artifact. 168 * It sends an <code>ArtifactQuery</code> SAML message to the 169 * destination identified by the source ID in the artifact and 170 * returns the Assertion contained in the SAML response message. 171 * 172 * @param artifact An <code>AssertionArtifact</code> representing the 173 * artifact 174 * @return An Assertion corresponding to the artifact 175 * @exception IOException if an input or output exception occurs when 176 * connecting to SAML service <code>URL</code> 177 * @exception SAMLException if SAML error occurs during the process 178 * @supported.api 179 */ 180 public static Assertion getAssertionByArtifact(AssertionArtifact artifact) 181 throws IOException, SAMLException { 182 return getAssertionByArtifact(artifact.getAssertionArtifact()); 183 } 184 185 /** 186 * This method returns the Assertion for the corresponding artifact. 187 * It sends an <code>ArtifactQuery</code> SAML message to the destination 188 * identified by the source ID in the artifact and returns the Assertion 189 * contained in the SAML response message. 190 * 191 * @param artifact A String representing the artifact 192 * @return An Assertion corresponding to the artifact 193 * @exception IOException if an input or output exception occurs when 194 * connecting to SAML service <code>URL</code> 195 * @exception SAMLException if SAML error occurs during the process 196 * @supported.api 197 */ 198 public static Assertion getAssertionByArtifact(String artifact) 199 throws IOException, SAMLException { 200 if (artifact == null || artifact.length() == 0) { 201 if (SAMLUtils.debug.messageEnabled()) { 202 SAMLUtils.debug.message("SAMLClient: input is null."); 203 } 204 throw new SAMLException( 205 SAMLUtils.bundle.getString("nullInput")); 206 } 207 // first, check if the sourceid contained in the artifact has an entry 208 // in SAML config 209 AssertionArtifact aa = new AssertionArtifact(artifact); 210 String sid = aa.getSourceID(); 211 String ssurl = getSamlSoapUrl(sid); 212 // if not, query naming service to get the soap url in case of local 213 URL samlsoap = null; 214 try { 215 if (ssurl == null) { 216 Map instances= (Map) 217 SAMLServiceManager.getAttribute(SAMLConstants.INSTANCE_LIST); 218 if (instances == null || instances.size() == 0) { 219 throw new SAMLException( 220 SAMLUtils.bundle.getString("instancemapNull")); 221 } 222 String server= (String) instances.get(sid); 223 if (server == null || server.length() == 0) { 224 throw new SAMLException( 225 SAMLUtils.bundle.getString("instanceNotFound")); 226 } 227 URL serverurl = new URL(server); 228 samlsoap = SystemConfigurationUtil.getServiceURL( 229 SAMLConstants.SAML_SOAP_NAMING, 230 serverurl.getProtocol(), serverurl.getHost(), 231 serverurl.getPort(), serverurl.getPath()); 232 } else { 233 samlsoap = new URL(ssurl); 234 } 235 if (SAMLUtils.debug.messageEnabled()) { 236 SAMLUtils.debug.message("SAMLClient:SOAPUrl=" + 237 samlsoap.toString()); 238 } 239 } catch (SystemConfigurationException ue) { 240 SAMLUtils.debug.error("SAMLClient", ue); 241 throw new SAMLException( 242 SAMLUtils.bundle.getString("URLNotFoundException")); 243 } 244 if (!setLocalFlag(samlsoap)) { 245 throw new SAMLException( 246 SAMLUtils.bundle.getString("failSetLocalFlag")); 247 } 248 249 if (SAMLUtils.debug.messageEnabled()) { 250 SAMLUtils.debug.message("SAMLClient:getAssertionByArtifact: " + 251 "check localFlag : " + 252 SAMLServiceManager.localFlag); 253 } 254 String encodedSourceid = (String) SAMLServiceManager.getAttribute( 255 SAMLConstants.SITE_ID); 256 boolean isMySite = sid.equals(encodedSourceid.trim()); 257 if (SAMLServiceManager.localFlag && isMySite) { 258 // if the localFlag is true and the Artifact's source id is 259 // the same as my site_id, (means SAMLClient and AssertionManager 260 // in the same JVM, call AssertionManager directly. 261 if (SAMLUtils.debug.messageEnabled()) { 262 SAMLUtils.debug.message("SAMLClient:getAssertionByArtifact" + 263 ":call AssertionManager.getAssertion(" + 264 "AssertionArtifact)"); 265 } 266 AssertionManager assertManager = AssertionManager.getInstance(); 267 Assertion assertion = assertManager.getAssertion(aa); 268 return assertion; 269 } 270 String[] strarray = new String[1]; 271 strarray[0]= artifact; 272 List asserts = null; 273 if (isMySite && ssurl == null) { 274 asserts = artifactQueryHandler(strarray, samlsoap.toString()); 275 } else { 276 asserts = artifactQueryHandler(strarray, null); 277 } 278 if (asserts == null || asserts.isEmpty()) { 279 if (SAMLUtils.debug.messageEnabled()) { 280 SAMLUtils.debug.message("SAMLClient:getAssertionByArtifact" + 281 ":returned assertion list is null."); 282 } 283 return null; 284 } 285 return ((Assertion) asserts.get(0)); 286 } 287 288 private static String getSamlSoapUrl(String sourceid) { 289 String soapurl = null; 290 try { 291 Map partner = (Map) SAMLServiceManager.getAttribute( 292 SAMLConstants.PARTNER_URLS); 293 if (partner == null) { 294 SAMLUtils.debug.error("SAMLClient:Partner URL is null."); 295 return null; 296 } 297 SAMLServiceManager.SOAPEntry partnerdest = 298 (SAMLServiceManager.SOAPEntry) partner.get(sourceid); 299 if (partnerdest != null) { 300 soapurl = partnerdest.getSOAPUrl(); 301 } else { 302 if (SAMLUtils.debug.messageEnabled()) { 303 SAMLUtils.debug.message("SAMLClient: " + sourceid + 304 " is not on trusted site list."); 305 } 306 } 307 return soapurl; 308 } catch (Exception se) { 309 SAMLUtils.debug.error("SAMLClient: ", se); 310 return null; 311 } 312 } 313 314 public static boolean setLocalFlag(URL url) { 315 if (url == null) { 316 SAMLUtils.debug.error("SAMLClient:setLocalFlag has null input."); 317 return false; 318 } 319 try { 320 // Preload class SAMLSOAPReceiver since it wouldn't be included 321 // in the remote sdk. If the class SAMLSOAPReceiver isn't 322 // presented, we consider it is client application. 323 Class.forName("com.sun.identity.saml.servlet.SAMLSOAPReceiver"); 324 if (SAMLUtils.debug.messageEnabled()) { 325 SAMLUtils.debug.message("in setLocalFlag(), url : " + 326 url.toString()); 327 SAMLUtils.debug.message("SAMLSOAPReceiver.localSAMLServiceID : " 328 + SAMLSOAPReceiver.localSAMLServiceID); 329 } 330 if (SAMLSOAPReceiver.localSAMLServiceID != null) { 331 URL samlservice = 332 new URL(SAMLSOAPReceiver.localSAMLServiceID); 333 if ((url.getHost().equalsIgnoreCase(samlservice.getHost())) && 334 (url.getPort() == samlservice.getPort())) { 335 SAMLServiceManager.localFlag = true; 336 return true; 337 } 338 } 339 } catch (ClassNotFoundException cnfe) { 340 if (SAMLUtils.debug.messageEnabled()) { 341 SAMLUtils.debug.message("SAMLClient::setLocalFlag: ", 342 cnfe); 343 } 344 SAMLServiceManager.localFlag = false; 345 return true; 346 } catch (Exception e) { 347 SAMLUtils.debug.error("SAMLClient::setLocalFlag:: ", e); 348 return false; 349 } 350 SAMLServiceManager.localFlag = false; 351 return true; 352 } 353 354 /** 355 * This private method takes a SAML request object and returns a SOAPMessage 356 * wrapped around the request object. 357 * @param req A SAML request object 358 * @return a SOAPMessage 359 * @exception SAMLException 360 */ 361 private static String createSOAPMessage(Request req) 362 throws SAMLException { 363 if (req == null){ 364 throw new SAMLException(SAMLUtils.bundle.getString("nullInput")); 365 } 366 367 try { 368 StringBuffer envBegin = new StringBuffer(100); 369 envBegin.append("<").append(SAMLConstants.SOAP_ENV_PREFIX). 370 append(":Envelope").append(SAMLConstants.SPACE). 371 append("xmlns:").append(SAMLConstants.SOAP_ENV_PREFIX). 372 append("=\"").append(SAMLConstants.SOAP_URI).append("\">"). 373 append(SAMLConstants.NL).append("<"). 374 append(SAMLConstants.SOAP_ENV_PREFIX).append(":Body>"). 375 append(SAMLConstants.NL); 376 377 StringBuffer envEnd = new StringBuffer(100); 378 envEnd.append(SAMLConstants.START_END_ELEMENT). 379 append(SAMLConstants.SOAP_ENV_PREFIX).append(":Body>"). 380 append(SAMLConstants.NL). 381 append(SAMLConstants.START_END_ELEMENT). 382 append(SAMLConstants.SOAP_ENV_PREFIX). 383 append(":Envelope>").append(SAMLConstants.NL); 384 385 StringBuffer sb = new StringBuffer(300); 386 sb.append(envBegin).append(req.toString(true, true)).append(envEnd); 387 return(sb.toString()); 388 } catch (Exception e) { 389 throw new SAMLException(e.getMessage()); 390 } 391 } 392 393 /** 394 * This private method is designed to get the URLEndpoint which points to 395 * the partner's SOAP Receiver service, such as the URLEndpoint of 396 * SAMLSOAPReceiver servlet in OpenSSO context. 397 * @param destSite A object of 398 * com.sun.identity.saml.common.SAMLServiceManager.SOAPEntry 399 * @param to An URLEndpoint object 400 * @exception IOException if <code>URL</code> is invalid 401 * @exception SAMLException if SAML error occurs during the process 402 */ 403 private static String createSOAPReceiverUrl( 404 com.sun.identity.saml.common.SAMLServiceManager.SOAPEntry destSite, 405 String to) throws IOException, SAMLException { 406 if (destSite == null || to == null || to.length() == 0) { 407 throw new SAMLException(SAMLUtils.bundle.getString("nullInput")); 408 } 409 //get authentication type 410 String authtype = destSite.getAuthType(); 411 String urlEndpoint = null; 412 int idnx = -1; 413 if ((idnx = to.indexOf("//")) == -1) { 414 SAMLUtils.debug.error("SAMLClient:createSOAPReceiverUrl:" + 415 "Illegal format of input parameter."); 416 throw new SAMLException( 417 SAMLUtils.bundle.getString("illegalFormatSOAPUrl")); 418 } 419 String protocol = to.substring(0, idnx-1); 420 // check if the authentication type matches the protocol specified in 421 // input parameter "to". 422 if (authtype.equalsIgnoreCase(SAMLConstants.BASICAUTH) || 423 authtype.equalsIgnoreCase(SAMLConstants.NOAUTH)) { 424 if (!protocol.equals(SAMLConstants.HTTP)) { 425 if (SystemConfigurationUtil.isServerMode()) { 426 String[] data = {SAMLUtils.bundle.getString( 427 "mismatchAuthTypeandProtocol")}; 428 LogUtils.error(java.util.logging.Level.INFO, 429 LogUtils.AUTH_PROTOCOL_MISMATCH, data); 430 } 431 throw new SAMLException( 432 SAMLUtils.bundle.getString("mismatchAuthTypeandProtocol")); 433 } 434 } else if (authtype.equalsIgnoreCase(SAMLConstants.SSLWITHBASICAUTH) 435 || authtype.equalsIgnoreCase(SAMLConstants.SSL)) { 436 if (!protocol.equals(SAMLConstants.HTTPS)) { 437 if (SystemConfigurationUtil.isServerMode()) { 438 String[] data = {SAMLUtils.bundle.getString( 439 "mismatchAuthTypeandProtocol")}; 440 LogUtils.error(java.util.logging.Level.INFO, 441 LogUtils.AUTH_PROTOCOL_MISMATCH, data); 442 } 443 throw new SAMLException( 444 SAMLUtils.bundle.getString("mismatchAuthTypeandProtocol")); 445 } 446 } else { 447 if (SystemConfigurationUtil.isServerMode()) { 448 String[] data = {SAMLUtils.bundle.getString( 449 "wrongAuthType")}; 450 LogUtils.error(java.util.logging.Level.INFO, 451 LogUtils.INVALID_AUTH_TYPE, data); 452 } 453 throw new SAMLException( 454 SAMLUtils.bundle.getString("wrongAuthType")); 455 } 456 457 // If the authentication type is BASICAUTH or SSLWITHBASICAUTH, 458 // call ServiceManager to retrieve the partner's user name and password 459 // which protects the partner's SOAPReceiverURL. 460 if (authtype.equalsIgnoreCase(SAMLConstants.BASICAUTH) || 461 authtype.equalsIgnoreCase(SAMLConstants.SSLWITHBASICAUTH)) { 462 String username = destSite.getBasicAuthUserID(); 463 String password = destSite.getBasicAuthPassword(); 464 if (username == null || password == null) { 465 SAMLUtils.debug.error("SAMLClient:createSOAPReceiverUrl:" + 466 "PartnerSite required basic authentication. But the " + 467 "user name or password used for authentication is null."); 468 throw new SAMLException( 469 SAMLUtils.bundle.getString("wrongConfigBasicAuth")); 470 } 471 String toSOAP = to.substring(0, idnx+2) + username + ":" + 472 password + "@" + to.substring(idnx+2); 473 urlEndpoint = toSOAP; 474 } else { 475 urlEndpoint = to; 476 } 477 if (SAMLUtils.debug.messageEnabled()) { 478 SAMLUtils.debug.message("Sending message to URL: " + 479 urlEndpoint); 480 } 481 if (SystemConfigurationUtil.isServerMode()) { 482 String[] data = {SAMLUtils.bundle.getString("SOAPReceiverURL"), 483 urlEndpoint}; 484 LogUtils.access(java.util.logging.Level.FINE, 485 LogUtils.SOAP_RECEIVER_URL, data); 486 } 487 return urlEndpoint; 488 } 489 490 /** 491 * This private method is designed to get the SAML response object from 492 * a SOAPMessage string. 493 * @param xmlString A String representing a string of SOAPMessage 494 * @return a SAML Response object 495 * @exception IOException if an input or output exception occurs when 496 * connecting to SAML service <code>URL</code> 497 * @exception SAMLException if SAML error occurs during the process 498 */ 499 private static Response getSAMLResponse(String xmlString) 500 throws IOException, SAMLException { 501 if (xmlString == null || xmlString.length() == 0) { 502 throw new SAMLException(SAMLUtils.bundle.getString("nullInput")); 503 } 504 Response samlResp = null; 505 Document doc = XMLUtils.toDOMDocument(xmlString, SAMLUtils.debug); 506 Element root= doc.getDocumentElement(); 507 String rootName = root.getLocalName(); 508 if ((rootName == null) || (rootName.length() == 0)) { 509 SAMLUtils.debug.error("Missing Envelope tag."); 510 throw new SAMLException ( 511 SAMLUtils.bundle.getString("missingSOAPEnvTag")); 512 } 513 if (!(rootName.equals("Envelope")) || 514 (!(root.getNamespaceURI().equals(SAMLConstants.SOAP_URI)))) { 515 SAMLUtils.debug.error("Wrong Envelope tag or namespace."); 516 throw new SAMLException( 517 SAMLUtils.bundle.getString("serverError")); 518 } 519 //exam the child element of <SOAP-ENV:Envelope> 520 NodeList nodes = root.getChildNodes(); 521 int nodeCount = nodes.getLength(); 522 if (nodeCount <= 0) { 523 SAMLUtils.debug.error("Envelope does not contain a SOAP body."); 524 throw new SAMLException( 525 SAMLUtils.bundle.getString("missingSOAPBody")); 526 } 527 String tagName = null; 528 String ctagName = null; 529 Node currentNode = null; 530 Node cnode = null; 531 for (int i = 0; i < nodeCount; i++) { 532 currentNode = nodes.item(i); 533 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 534 tagName = currentNode.getLocalName(); 535 if ((tagName == null) || tagName.length() == 0) { 536 SAMLUtils.debug.error("Missing tag name of child element"); 537 throw new SAMLException( 538 SAMLUtils.bundle.getString("missingChildTagName")); 539 } 540 if (tagName.equals("Body")) { 541 NodeList cNodes = currentNode.getChildNodes(); 542 int cnodeCount = cNodes.getLength(); 543 for (int j = 0; j < cnodeCount; j++) { 544 cnode = cNodes.item(j); 545 if (cnode.getNodeType() == Node.ELEMENT_NODE){ 546 ctagName = cnode.getLocalName(); 547 if ((ctagName == null) || ctagName.length() == 0) { 548 SAMLUtils.debug.error("Missing tag name of " + 549 "child element of <SOAP-ENV:Body>"); 550 throw new SAMLException( 551 SAMLUtils.bundle.getString( 552 "missingChildTagName")); 553 } 554 if (ctagName.equals("Fault")) { 555 SAMLUtils.debug.error("SOAPFault error."); 556 throw new SAMLException( 557 XMLUtils.print(cnode)); 558 } else if (ctagName.equals("Response")) { 559 samlResp = new Response((Element) cnode); 560 if (SAMLUtils.debug.messageEnabled()) { 561 SAMLUtils.debug.message("SAML Response:" + 562 samlResp.toString()); 563 } 564 break; 565 } else { 566 SAMLUtils.debug.error("Wrong child element " + 567 "in SOAPBody"); 568 throw new SAMLException( 569 SAMLUtils.bundle.getString( 570 "wrongSOAPBody")); 571 } 572 } 573 } // end of for(int j=0; j <cnodeCount; j++) 574 } else if (tagName.equals("Header")) { 575 if (SAMLUtils.debug.messageEnabled()) { 576 SAMLUtils.debug.message("Inside SOAP Response:" + 577 " SOAP Header"); 578 } 579 } else { 580 SAMLUtils.debug.error("Wrong child element in Envelope"); 581 throw new SAMLException( 582 SAMLUtils.bundle.getString("wrongSOAPElement")); 583 } 584 } // end of if (currentNode.getNodeType() == Node.ELEMENT_NODE) 585 } // end of for (int i = 0; i < nodeCount; i++) 586 return samlResp; 587 } 588 589 /** 590 * This method is designed to get a list of assertion from the 591 * SAML Response. 592 * @param samlresponse A SAML Response object 593 * @param alist a List 594 * @return a List object representing a list of Assertion 595 * @exception SAMLException 596 */ 597 private static List getAssertionList(Response samlresponse, List alist) 598 throws SAMLException { 599 if (samlresponse == null || alist == null) { 600 throw new SAMLException(SAMLUtils.bundle.getString("nullInput")); 601 } 602 // get a list of SAML assertion 603 List assertions = new ArrayList(); 604 assertions = samlresponse.getAssertion(); 605 if (assertions == null || assertions.isEmpty()) { 606 if (SystemConfigurationUtil.isServerMode()) { 607 String[] data = {SAMLUtils.bundle.getString( 608 "noAssertioninResponse"), samlresponse.toString(true, true)}; 609 LogUtils.error(java.util.logging.Level.INFO, 610 LogUtils.NO_ASSERTION_IN_RESPONSE, data); 611 } 612 throw new SAMLException( 613 SAMLUtils.displayXML(samlresponse.getStatus().toString())); 614 } 615 if (assertions.size() != alist.size()) { 616 SAMLUtils.debug.error("The SAML response containing assertions !=" 617 + "the number of artifacts in SAML request"); 618 if (SystemConfigurationUtil.isServerMode()) { 619 String[] data = {SAMLUtils.bundle.getString( 620 "wrongNumberAssertions"), 621 samlresponse.toString(true, true)}; 622 LogUtils.error(java.util.logging.Level.INFO, 623 LogUtils.MISMATCHED_ASSERTION_AND_ARTIFACT, data); 624 } 625 throw new SAMLException( 626 SAMLUtils.bundle.getString("wrongNumberAssertions")); 627 } 628 return assertions; 629 } 630 631 /** 632 * This method is designed to get a list of assertion based on the input 633 * <code>AssertionArtifact</code>(s). 634 * 635 * @param arti An array of String 636 * @return a List object representing a list of Assertions 637 * @exception IOException if an input or output exception occurs when 638 * connecting to SAML service <code>URL</code> 639 * @exception SAMLException if SAML error occurs during the process 640 */ 641 public static List artifactQueryHandler(String[] arti, String connecto) 642 throws IOException, SAMLException { 643 if ((arti == null) || (arti.length == 0)) { 644 SAMLUtils.debug.message("artifactQueryHandler: null input."); 645 throw new SAMLException(SAMLUtils.bundle.getString("nullInput")); 646 } 647 648 String firstSourceID = null; 649 com.sun.identity.saml.common.SAMLServiceManager.SOAPEntry dest= null; 650 Response samlresponse = null; 651 List al = new ArrayList(); 652 List artl = new ArrayList(); 653 654 AssertionArtifact firstArtifact = new AssertionArtifact(arti[0]); 655 firstSourceID = firstArtifact.getSourceID(); 656 if (SystemConfigurationUtil.isServerMode()) { 657 String[] data = {SAMLUtils.bundle.getString("Artifact") + " " + 0, 658 arti[0]}; 659 LogUtils.access(java.util.logging.Level.INFO, 660 LogUtils.ARTIFACT_TO_SEND, data); 661 } 662 artl.add(firstArtifact); 663 al.add(arti[0]); 664 AssertionArtifact assertArtifact = null; 665 String destination = null; 666 for (int k = 1; k < arti.length; k++) { 667 // check if all Artifact come from the same source id 668 assertArtifact = new AssertionArtifact(arti[k]); 669 destination = assertArtifact.getSourceID(); 670 if (SAMLUtils.debug.messageEnabled()) { 671 SAMLUtils.debug.message("SourceID within the Artifact is " + 672 destination); 673 } 674 if (!destination.equals(firstSourceID)) { 675 if (SAMLUtils.debug.messageEnabled()) { 676 SAMLUtils.debug.message("Received multiple Artifacts " + 677 "have different source id."); 678 } 679 throw new SAMLException( 680 SAMLUtils.bundle.getString("sourceidDifferent")); 681 } 682 if (SystemConfigurationUtil.isServerMode()) { 683 String[] data = {SAMLUtils.bundle.getString("Artifact") + " " 684 + k, arti[k]}; 685 LogUtils.access(java.util.logging.Level.FINE, 686 LogUtils.ARTIFACT_TO_SEND, data); 687 } 688 artl.add(assertArtifact); 689 al.add(arti[k]); 690 } 691 692 try { 693 //Retrieve the soap-receiver-url using the sourceid inside of 694 //the AssertionArtifact 695 String to = null; 696 Map soaps = (Map) SAMLServiceManager.getAttribute( 697 SAMLConstants.PARTNER_URLS); 698 if (soaps == null) { 699 SAMLUtils.debug.error( 700 SAMLUtils.bundle.getString("nullPartnerUrl")); 701 throw new SAMLException( 702 SAMLUtils.bundle.getString("nullPartnerUrl")); 703 } 704 String urlEndpoint = null; 705 if (soaps.containsKey(firstSourceID)) { 706 dest = (SAMLServiceManager.SOAPEntry) soaps.get(firstSourceID); 707 to = dest.getSOAPUrl(); 708 if (to==null) { 709 if (connecto == null || connecto.length() == 0) { 710 if (SystemConfigurationUtil.isServerMode()) { 711 String[] data = {SAMLUtils.bundle.getString( 712 "wrongPartnerSOAPUrl")}; 713 LogUtils.error(java.util.logging.Level.INFO, 714 LogUtils.WRONG_SOAP_URL, data); 715 } 716 throw new SAMLException( 717 SAMLUtils.bundle.getString("wrongPartnerSOAPUrl")); 718 } else { 719 urlEndpoint = connecto; 720 } 721 } else { 722 urlEndpoint = createSOAPReceiverUrl(dest, to); 723 } 724 } else { 725 if (SAMLUtils.debug.messageEnabled()) { 726 SAMLUtils.debug.message("SAMLClient:artifactQueryHandler: " 727 + "Failed to locate SOAP-Receiver-URL " + 728 "using the source id from AssertionArtifact."); 729 } 730 if (connecto == null || connecto.length() == 0) { 731 throw new SAMLException( 732 SAMLUtils.bundle.getString("failedLocateSOAPUrl")); 733 } else { 734 urlEndpoint = connecto; 735 } 736 } 737 738 if (urlEndpoint == null) { 739 SAMLUtils.debug.error("SAMLClient:artifactQueryHandler:" + 740 "createSOAPReceiverURL Error!"); 741 if (SystemConfigurationUtil.isServerMode()) { 742 String[] data = {SAMLUtils.bundle.getString( 743 "wrongPartnerSOAPUrl")}; 744 LogUtils.error(java.util.logging.Level.INFO, 745 LogUtils.WRONG_SOAP_URL, data); 746 } 747 throw new SAMLException(SAMLUtils.bundle.getString( 748 "wrongPartnerSOAPUrl")); 749 } 750 //generate SAML Request 751 Request req = new Request(null, artl); 752 String ver = dest.getVersion(); 753 if (ver != null) { 754 StringTokenizer st = new StringTokenizer(ver,"."); 755 if (st.countTokens() == 2) { 756 req.setMajorVersion( 757 Integer.parseInt(st.nextToken().trim())); 758 req.setMinorVersion( 759 Integer.parseInt(st.nextToken().trim())); 760 } 761 } 762 763 if (((Boolean) SAMLServiceManager.getAttribute( 764 SAMLConstants.SIGN_REQUEST)).booleanValue()) 765 { 766 req.signXML(); 767 } 768 // SOAPMessage msg = createSOAPMessage(req); 769 String xmlString = createSOAPMessage(req); 770 771 // Send the message to the provider using the connection. 772 if (SAMLUtils.debug.messageEnabled()) { 773 SAMLUtils.debug.message("SENDING message: \n " + xmlString); 774 } 775 if (SystemConfigurationUtil.isServerMode()) { 776 String[] data = {SAMLUtils.bundle.getString( 777 "sendingSAMLRequest"), xmlString}; 778 LogUtils.access(java.util.logging.Level.FINE, 779 LogUtils.SAML_ARTIFACT_QUERY, data); 780 } 781 782 // SOAPMessage reply = con.call(msg, urlEndpoint); 783 String[] urls = { urlEndpoint }; 784 SOAPClient client = new SOAPClient(urls); 785 InputStream inbuf = client.call(xmlString, null, null); 786 StringBuffer reply = new StringBuffer(); 787 String line; 788 BufferedReader reader = new BufferedReader(new InputStreamReader( 789 inbuf, "UTF-8")); 790 while ((line = reader.readLine()) != null) { 791 reply.append(line).append("\n"); 792 } 793 794 //reply should contain SAML response 795 if (reply == null) { 796 if (SystemConfigurationUtil.isServerMode()) { 797 String[] data = {SAMLUtils.bundle.getString( 798 "noReplyfromSOAPReceiver")}; 799 LogUtils.error(java.util.logging.Level.INFO, 800 LogUtils.NO_REPLY_FROM_SOAP_RECEIVER, data); 801 } 802 throw new SAMLException( 803 SAMLUtils.bundle.getString("noReplyfromSOAPReceiver")); 804 } 805 806 // check the SOAP message for any SOAP related errors 807 // before passing control to SAML processor 808 xmlString = reply.toString(); 809 if (SAMLUtils.debug.messageEnabled()) { 810 SAMLUtils.debug.message("REPLIED message: \n " + xmlString); 811 } 812 if (SystemConfigurationUtil.isServerMode()) { 813 String[] data = {SAMLUtils.bundle.getString( 814 "repliedSOAPMessage"), xmlString}; 815 LogUtils.access(java.util.logging.Level.FINE, 816 LogUtils.REPLIED_SOAP_MESSAGE, data); 817 } 818 samlresponse = getSAMLResponse(xmlString); 819 if (samlresponse == null) { 820 SAMLUtils.debug.error("SAMLClient:artifactQueryHandler:"+ 821 "No SAML Response contained in SOAPMessage."); 822 if (SystemConfigurationUtil.isServerMode()) { 823 String[] data = {SAMLUtils.bundle.getString( 824 "noSAMLResponse")}; 825 LogUtils.error(java.util.logging.Level.INFO, 826 LogUtils.NULL_SAML_RESPONSE, data); 827 } 828 throw new SAMLException(SAMLUtils.bundle.getString( 829 "noSAMLResponse")); 830 } 831 } catch (Exception e) { 832 SAMLUtils.debug.error("SAMLClient:artifactQueryHandler", e); 833 throw new SAMLException(e.getMessage()); 834 } 835 if (SAMLUtils.debug.messageEnabled()) { 836 SAMLUtils.debug.message("Start to process SAML Response..."); 837 } 838 // Process saml Response 839 if (!samlresponse.isSignatureValid()) { 840 if (SystemConfigurationUtil.isServerMode()) { 841 String[] data = {SAMLUtils.bundle.getString( 842 "cannotVerifyResponse")}; 843 LogUtils.error(java.util.logging.Level.INFO, 844 LogUtils.INVALID_RESPONSE_SIGNATURE, data); 845 } 846 throw new SAMLException( 847 SAMLUtils.bundle.getString("cannotVerifyResponse")); 848 } 849 try { 850 String statuscode= samlresponse.getStatus().getStatusCode(). 851 getValue(); 852 int idex=0; 853 if ((idex=statuscode.indexOf(":")) == -1) { 854 throw new SAMLException( 855 SAMLUtils.bundle.getString("wrongformatStatusCode")); 856 } 857 if (!(statuscode.substring(idex).equals(":Success"))) { 858 SAMLUtils.debug.error("Error:SAML StatusCode is not Success"); 859 throw new SAMLException( 860 SAMLUtils.displayXML(samlresponse.getStatus().toString())); 861 } 862 } catch (Exception e) { 863 if (SystemConfigurationUtil.isServerMode()) { 864 String[] data = {SAMLUtils.bundle.getString( 865 "errorSAMLStatusCode")}; 866 LogUtils.error(java.util.logging.Level.INFO, 867 LogUtils.ERROR_RESPONSE_STATUS, data); 868 } 869 throw new SAMLException(e.getMessage()); 870 } 871 // retrieve SAML Assertion 872 List asserts = new ArrayList(); 873 asserts = getAssertionList(samlresponse, al); 874 return asserts; 875 } 876}
Copyright © 2010-2017, ForgeRock All Rights Reserved.