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: FSLogoutResponse.java,v 1.4 2008/06/25 05:46:44 qcheng Exp $ 026 * 027 */ 028 029package com.sun.identity.federation.message; 030 031import com.sun.identity.shared.encode.Base64; 032import com.sun.identity.shared.encode.URLEncDec; 033import com.sun.identity.shared.xml.XMLUtils; 034 035import com.sun.identity.shared.DateUtils; 036 037import com.sun.identity.federation.message.common.FSMsgException; 038import com.sun.identity.federation.common.FSUtils; 039import com.sun.identity.federation.common.IFSConstants; 040 041import com.sun.identity.saml.common.SAMLConstants; 042import com.sun.identity.saml.common.SAMLException; 043import com.sun.identity.saml.common.SAMLResponderException; 044import com.sun.identity.saml.common.SAMLVersionMismatchException; 045 046import com.sun.identity.saml.xmlsig.XMLSignatureManager; 047 048import com.sun.identity.saml.protocol.AbstractResponse; 049import com.sun.identity.saml.protocol.Status; 050import com.sun.identity.saml.protocol.StatusCode; 051 052import java.io.IOException; 053 054import java.text.ParseException; 055 056import java.util.Date; 057import java.util.List; 058 059import javax.servlet.http.HttpServletRequest; 060 061import org.w3c.dom.Element; 062import org.w3c.dom.Node; 063import org.w3c.dom.NodeList; 064import org.w3c.dom.Document; 065 066/** 067 * This class has methods to create a Liberty <code>LogoutResponse</code>. 068 * 069 * @supported.all.api 070 */ 071 072public class FSLogoutResponse extends AbstractResponse { 073 private String providerId; 074 private String relayState; 075 private Status status; 076 protected String xmlString; 077 protected String signatureString; 078 protected String id; 079 private String inResponseTo; 080 081 /** 082 * Default Constructor. 083 */ 084 public FSLogoutResponse() { 085 try { 086 setIssueInstant(new Date()); 087 providerId = new String(); 088 StatusCode statusCode = new StatusCode(IFSConstants.SAML_SUCCESS); 089 status = new Status(statusCode); 090 relayState = new String(); 091 } catch (SAMLException e){ 092 FSUtils.debug.error("FSLogoutResponse.constructor:", e); 093 } 094 095 } 096 097 /** 098 * Constructor creates <code>FSLogoutResponse</code> object. 099 * 100 * @param responseID the value of <code>ResponseID</code> attribute. 101 * @param inResponseTo the value of <code>inResponseTo</code> attribute. 102 * @param status the Logout <code>Status</code> object. 103 * @param providerId the value of <code>ProviderID</code> attribute. 104 * @param relayState the value of <code>RelayState</code> attribute. 105 * @throws <code>FSMsgException</code> if this object cannot be created. 106 */ 107 public FSLogoutResponse(String responseID, 108 String inResponseTo, 109 Status status, 110 String providerId, 111 String relayState) 112 throws FSMsgException { 113 if ((responseID == null) || (responseID.length() == 0)) { 114 this.responseID = FSUtils.generateID(); 115 if (this.responseID == null) { 116 throw new FSMsgException("errorGenerateID",null); 117 } 118 } else { 119 this.responseID = responseID; 120 } 121 122 if (inResponseTo == null) { 123 FSUtils.debug.message("Response: inResponseTo is null."); 124 throw new FSMsgException("nullInput",null); 125 } 126 this.inResponseTo = inResponseTo; 127 if (status == null) { 128 FSUtils.debug.message("Response: missing <Status>."); 129 throw new FSMsgException("missingElement",null); 130 } 131 this.status = status; 132 this.providerId = providerId; 133 this.relayState = relayState; 134 setIssueInstant(new Date()); 135 } 136 137 /** 138 * Constructor creates <code>FSLogoutResponse</code> object from 139 * a Document element. 140 * 141 * @param root the Document element object. 142 * @throws FSMsgException if this object cannot be created. 143 * @throws SAMLException if there is an error. 144 */ 145 public FSLogoutResponse(Element root) throws FSMsgException, SAMLException { 146 if (root == null) { 147 FSUtils.debug.message("FSLogoutResponse.parseXML: null input."); 148 throw new FSMsgException("nullInput",null); 149 } 150 String tag = null; 151 if (((tag = root.getLocalName()) == null) || 152 (!tag.equals(IFSConstants.LOGOUT_RESPONSE))) { 153 FSUtils.debug.message("FSLogoutResponse.parseXML: wrong input."); 154 throw new FSMsgException("wrongInput",null); 155 } 156 157 id = root.getAttribute(IFSConstants.ID); 158 159 // Attribute ResponseID 160 responseID = root.getAttribute(IFSConstants.RESPONSE_ID); 161 if ((responseID == null) || (responseID.length() == 0)) { 162 if (FSUtils.debug.messageEnabled()) { 163 FSUtils.debug.message("FSLogoutResponse.parseXML: " 164 + "Reponse doesn't have ResponseID."); 165 } 166 String[] args = { IFSConstants.RESPONSE_ID }; 167 throw new FSMsgException("missingAttribute",args); 168 } 169 parseMajorVersion(root.getAttribute(IFSConstants.MAJOR_VERSION)); 170 parseMinorVersion(root.getAttribute(IFSConstants.MINOR_VERSION)); 171 // Attribute InResponseTo 172 inResponseTo = root.getAttribute(IFSConstants.IN_RESPONSE_TO); 173 if (inResponseTo == null) { 174 if (FSUtils.debug.messageEnabled()) { 175 FSUtils.debug.message("FSLogoutResponse.parseXML: " 176 + "Response doesn't have InResponseTo."); 177 } 178 String[] args = { IFSConstants.IN_RESPONSE_TO }; 179 throw new FSMsgException("missingAttribute",args); 180 } 181 // Attribute IssueInstant 182 String instantString = root.getAttribute(IFSConstants.ISSUE_INSTANT); 183 if ((instantString == null) || (instantString.length() == 0)) { 184 FSUtils.debug.message("FSLogoutResponse(Element): " 185 + "missing IssueInstant"); 186 String[] args = { IFSConstants.ISSUE_INSTANT }; 187 throw new FSMsgException("missingAttribute",args); 188 } else { 189 try { 190 issueInstant = DateUtils.stringToDate(instantString); 191 } catch (ParseException e) { 192 if (FSUtils.debug.messageEnabled()) { 193 FSUtils.debug.message( 194 "FSLogoutResponse(Element): could not " + 195 "parse IssueInstant", e); 196 } 197 throw new FSMsgException("wrongInput", null); 198 } 199 } 200 201 NodeList nl = root.getChildNodes(); 202 Node child; 203 String childName; 204 int length = nl.getLength(); 205 for (int i = 0; i < length; i++) { 206 child = nl.item(i); 207 if ((childName = child.getLocalName()) != null) { 208 if (childName.equals(IFSConstants.STATUS)) { 209 if (status != null) { 210 if (FSUtils.debug.messageEnabled()) { 211 FSUtils.debug.message( 212 "FSLogoutResponse: included more" 213 + " than one <Status>"); 214 } 215 throw new FSMsgException("moreElement",null); 216 } 217 status = new Status((Element) child); 218 } else if (childName.equals(IFSConstants.SIGNATURE)) { 219 } else if (childName.equals(IFSConstants.PROVIDER_ID)) { 220 if (providerId != null) { 221 if (FSUtils.debug.messageEnabled()) { 222 FSUtils.debug.message( 223 "FSLogoutResponse: included more" 224 + " than one providerId"); 225 } 226 throw new FSMsgException("moreElement",null); 227 } 228 providerId = XMLUtils.getElementValue((Element) child); 229 } else if (childName.equals(IFSConstants.RELAY_STATE)) { 230 relayState = XMLUtils.getElementValue((Element) child); 231 } else { 232 if (FSUtils.debug.messageEnabled()) { 233 FSUtils.debug.message("FSLogoutResponse: included wrong" 234 + " element:" + childName); 235 } 236 throw new FSMsgException("wrongInput",null); 237 } 238 } // end if childName != null 239 } // end for loop 240 241 if (status == null) { 242 FSUtils.debug.message("FSLogoutResponse:missing element <Status>."); 243 throw new FSMsgException("oneElement",null); 244 } 245 246 if (providerId == null) { 247 FSUtils.debug.message( 248 "FSLogoutResponse: missing element providerId."); 249 throw new FSMsgException("oneElement",null); 250 } 251 252 //check for signature 253 List signs = XMLUtils.getElementsByTagNameNS1(root, 254 SAMLConstants.XMLSIG_NAMESPACE_URI, 255 SAMLConstants.XMLSIG_ELEMENT_NAME); 256 int signsSize = signs.size(); 257 if (signsSize == 1) { 258 Element elem = (Element)signs.get(0); 259 setSignature(elem); 260 xmlString = XMLUtils.print(root); 261 signed = true; 262 } else if (signsSize != 0) { 263 if (FSUtils.debug.messageEnabled()) { 264 FSUtils.debug.message( 265 "FSLogoutResponse(Element): included more than" 266 + " one Signature element."); 267 } 268 throw new FSMsgException("moreElement",null); 269 } 270 } 271 272 /** 273 * Returns the value of <code>RelayState</code> attribute. 274 * 275 * @return the value of <code>RelayState</code> attribute. 276 * @see #setRelayState(String) 277 */ 278 public String getRelayState(){ 279 return relayState; 280 } 281 282 /** 283 * Set the value of <code>RelayState</code> attribute. 284 * 285 * @param relayState the value of <code>RelayState</code> attribute. 286 * @see #getRelayState() 287 */ 288 public void setRelayState(String relayState){ 289 this.relayState = relayState; 290 } 291 292 /** 293 * Returns the value of <code>InResponseTo</code> attribute. 294 * 295 * @return the value of <code>InResponseTo</code> attribute. 296 * @see #setResponseTo(String) 297 */ 298 public String getResponseTo(){ 299 return inResponseTo; 300 } 301 302 /** 303 * Sets the value of <code>InResponseTo</code> attribute. 304 * 305 * @param inResponseTo the value of <code>InResponseTo</code> attribute. 306 * @see #getResponseTo 307 */ 308 public void setResponseTo(String inResponseTo){ 309 this.inResponseTo = inResponseTo; 310 } 311 312 /** 313 * Returns the value of <code>id</code> attribute. 314 * 315 * @return the value of <code>id</code> attribute. 316 * @see #setID(String) 317 */ 318 public String getID(){ 319 return id; 320 } 321 322 /** 323 * Sets the value of <code>id</code> attribute. 324 * 325 * @param id the value of <code>id</code> attribute. 326 * @see #getID() 327 */ 328 public void setID(String id){ 329 this.id = id; 330 } 331 332 /** 333 * Returns the value of <code>ProviderID</code> attribute. 334 * 335 * @return the value of <code>ProviderID</code> attribute. 336 * @see #setProviderId(String). 337 */ 338 339 public String getProviderId(){ 340 return providerId; 341 } 342 343 /** 344 * Sets the value of <code>ProviderID</code> attribute. 345 * 346 * @param providerId the value of <code>ProviderID</code> attribute. 347 * @see #getProviderId() 348 */ 349 public void setProviderId(String providerId){ 350 this.providerId = providerId; 351 } 352 353 /** 354 * Returns the Signed <code>LogoutResponse</code> string. 355 * 356 * @return signatureString the Signed <code>LogoutResponse</code> string. 357 */ 358 public String getSignatureString(){ 359 return signatureString; 360 } 361 362 /** 363 * Returns the value of <code>MinorVersion</code> attribute. 364 * 365 * @return the value of <code>MinorVersion</code> attribute. 366 * @see #setMinorVersion(int) 367 */ 368 public int getMinorVersion() { 369 return minorVersion; 370 } 371 372 /** 373 * Sets the value of <code>MinorVersion</code> attribute. 374 * 375 * @param version thevalue of <code>MinorVersion</code> attribute. 376 * @see #getMinorVersion() 377 */ 378 public void setMinorVersion(int version) { 379 minorVersion = version; 380 } 381 382 /** 383 * Returns the Logout <code>Status</code>. 384 * 385 * @return the Logout <code>Status</code>. 386 * @see #setStatus(String) 387 * @see #setStatus(Status) 388 */ 389 public Status getStatus() { 390 return status; 391 } 392 393 /** 394 * Sets the Logout <code>Status</code>. 395 * 396 * @param status the Logout <code>Status</code code. 397 * @see #getStatus 398 */ 399 public void setStatus(String status) { 400 try { 401 StatusCode statusCode = new StatusCode(status); 402 this.status = new Status(statusCode); 403 } catch (Exception e) { 404 if (FSUtils.debug.messageEnabled()) { 405 FSUtils.debug.message("FSLogoutResponse(Element): could not " 406 + "set attribute:", e); 407 } 408 } 409 } 410 411 /** 412 * Sets the Logout <code>Status</code>. 413 * 414 * @param status the Logout <code>Status</code object. 415 * @see #getStatus 416 */ 417 public void setStatus(Status status) { 418 this.status=status; 419 } 420 421 /** 422 * Sets the <code>MajorVersion</code> by parsing the version string. 423 * 424 * @param majorVer a String representing the <code>MajorVersion</code> to 425 * be set. 426 * @throws FSMsgException on error. 427 * @throws SAMLException when the version mismatchs. 428 */ 429 private void parseMajorVersion(String majorVer) 430 throws FSMsgException, SAMLException { 431 try { 432 majorVersion = Integer.parseInt(majorVer); 433 } catch (NumberFormatException e) { 434 if (FSUtils.debug.messageEnabled()) { 435 FSUtils.debug.message("Response(Element): invalid " 436 + "MajorVersion", e); 437 } 438 throw new FSMsgException("wrongInput",null); 439 } 440 441 if (majorVersion != SAMLConstants.PROTOCOL_MAJOR_VERSION) { 442 if (majorVersion > SAMLConstants.PROTOCOL_MAJOR_VERSION) { 443 if (FSUtils.debug.messageEnabled()) { 444 FSUtils.debug.message("Response(Element):MajorVersion of" 445 + " the Response is too high."); 446 } 447 throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME, 448 "responseVersionTooHigh",null); 449 } else { 450 if (FSUtils.debug.messageEnabled()) { 451 FSUtils.debug.message("Response(Element):MajorVersion of" 452 + " the Response is too low."); 453 } 454 throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME, 455 "responseVersionTooLow",null); 456 } 457 } 458 } 459 460 /** 461 * Sets the <code>MinorVersion</code> by parsing the version string. 462 * 463 * @param minorVer a String representing the <code>MinorVersion</code> to 464 * be set. 465 * @throws SAMLException when the version mismatchs. 466 */ 467 private void parseMinorVersion(String minorVer) 468 throws FSMsgException, SAMLException { 469 try { 470 minorVersion = Integer.parseInt(minorVer); 471 } catch (NumberFormatException e) { 472 if (FSUtils.debug.messageEnabled()) { 473 FSUtils.debug.message("Response(Element): invalid " 474 + "MinorVersion", e); 475 } 476 throw new FSMsgException("wrongInput",null); 477 } 478 if (minorVersion > IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { 479 FSUtils.debug.error("Response(Element):MinorVersion of" 480 + " the Response is too high."); 481 throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME, 482 "responseVersionTooHigh",null); 483 } else if (minorVersion < IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) { 484 FSUtils.debug.error("Response(Element):MinorVersion of" 485 + " the Response is too low."); 486 throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME, 487 "responseVersionTooLow",null); 488 } 489 } 490 491 /** 492 * Returns the <code>FSLogoutResponse</code> object. 493 * 494 * @param xml the XML string to be parsed. 495 * @return <code>FSLogoutResponse</code> object created from the XML string. 496 * @throws FSMsgException if there is 497 * error creating the object. 498 */ 499 500 public static FSLogoutResponse parseXML(String xml) throws FSMsgException { 501 FSLogoutResponse logoutResponse = null; 502 try{ 503 Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug); 504 Element root = doc.getDocumentElement(); 505 logoutResponse = new FSLogoutResponse(root); 506 }catch(SAMLException ex){ 507 if (FSUtils.debug.messageEnabled()) { 508 FSUtils.debug.message("FSLogoutResponse.parseXML: " 509 + "Error while parsing input xml string"); 510 } 511 throw new FSMsgException("parseError",null, ex); 512 } 513 return logoutResponse; 514 } 515 516 /** 517 * Returns a String representation of the <code>LogoutResponse</code> 518 * object. This method translates the response to an XML string. 519 * 520 * @return An XML String representing the logout response. 521 */ 522 public String toXMLString() throws FSMsgException { 523 return this.toXMLString(true, true); 524 } 525 526 /** 527 * Returns a String representation of the <code>LogoutResponse</code> 528 * object. 529 * 530 * @return An XML String representing the logout response. 531 * @throws FSMsgException if there is an error converting 532 * this object ot a string. 533 */ 534 public String toXMLString(boolean includeNS, boolean declareNS) 535 throws FSMsgException { 536 return toXMLString(includeNS, declareNS, false); 537 } 538 539 /** 540 * Returns a String representation of the <code>LogoutResponse</code> 541 * object. 542 * 543 * @param includeNS Determines whether or not the namespace qualifier 544 * is prepended to the Element when converted 545 * @param declareNS Determines whether or not the namespace is declared 546 * within the Element. 547 * @param includeHeader Determines whether the output include the xml 548 * declaration header. 549 * @return a string containing the valid XML for this element 550 * @throws FSMsgException if there is an error converting 551 * this object ot a string. 552 */ 553 554 public String toXMLString(boolean includeNS, boolean declareNS, 555 boolean includeHeader) throws FSMsgException { 556 StringBuffer xml = new StringBuffer(300); 557 if (includeHeader) { 558 xml.append(IFSConstants.XML_PREFIX) 559 .append(SAMLConstants.DEFAULT_ENCODING) 560 .append(IFSConstants.QUOTE) 561 .append(IFSConstants.SPACE) 562 .append(IFSConstants.QUESTION_MARK) 563 .append(IFSConstants.RIGHT_ANGLE) 564 .append(IFSConstants.NL); 565 } 566 String prefixLIB = ""; 567 String uriLIB = ""; 568 if (includeNS) { 569 prefixLIB = IFSConstants.LIB_PREFIX; 570 } 571 572 if (declareNS) { 573 if(minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { 574 uriLIB = IFSConstants.LIB_12_NAMESPACE_STRING; 575 } else { 576 uriLIB = IFSConstants.LIB_NAMESPACE_STRING; 577 } 578 } 579 580 String instantString = DateUtils.toUTCDateFormat(issueInstant); 581 582 if((providerId == null) || (providerId.length() == 0)){ 583 FSUtils.debug.error("FSLogoutResponse.toXMLString: " 584 + "providerId is null in the response with responseId:" 585 + responseID); 586 String[] args = { responseID }; 587 throw new FSMsgException("nullProviderIdWResponseId",args); 588 } 589 590 xml.append(IFSConstants.LEFT_ANGLE) 591 .append(prefixLIB) 592 .append(IFSConstants.LOGOUT_RESPONSE) 593 .append(uriLIB) 594 .append(IFSConstants.SPACE); 595 596 if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION && 597 id != null && !(id.length() == 0)) { 598 xml.append(IFSConstants.ID) 599 .append(IFSConstants.EQUAL_TO) 600 .append(IFSConstants.QUOTE) 601 .append(id) 602 .append(IFSConstants.QUOTE) 603 .append(IFSConstants.SPACE) 604 .append(IFSConstants.SPACE); 605 } 606 607 if (responseID != null) { 608 xml.append(IFSConstants.RESPONSE_ID) 609 .append(IFSConstants.EQUAL_TO) 610 .append(IFSConstants.QUOTE) 611 .append(responseID) 612 .append(IFSConstants.QUOTE) 613 .append(IFSConstants.SPACE) 614 .append(IFSConstants.SPACE); 615 } 616 617 if (inResponseTo != null) { 618 xml.append(IFSConstants.IN_RESPONSE_TO) 619 .append(IFSConstants.EQUAL_TO) 620 .append(IFSConstants.QUOTE) 621 .append(inResponseTo) 622 .append(IFSConstants.QUOTE) 623 .append(IFSConstants.SPACE) 624 .append(IFSConstants.SPACE); 625 } 626 627 xml.append(IFSConstants.MAJOR_VERSION) 628 .append(IFSConstants.EQUAL_TO) 629 .append(IFSConstants.QUOTE) 630 .append(majorVersion) 631 .append(IFSConstants.QUOTE) 632 .append(IFSConstants.SPACE) 633 .append(IFSConstants.SPACE) 634 .append(IFSConstants.MINOR_VERSION) 635 .append(IFSConstants.EQUAL_TO) 636 .append(IFSConstants.QUOTE) 637 .append(minorVersion) 638 .append(IFSConstants.QUOTE) 639 .append(IFSConstants.SPACE) 640 .append(IFSConstants.SPACE) 641 .append(IFSConstants.ISSUE_INSTANT) 642 .append(IFSConstants.EQUAL_TO) 643 .append(IFSConstants.QUOTE) 644 .append(instantString) 645 .append(IFSConstants.QUOTE) 646 .append(IFSConstants.RIGHT_ANGLE); 647 648 if (signed) { 649 if (signatureString != null) { 650 xml.append(signatureString); 651 } else if (signature != null) { 652 signatureString = XMLUtils.print(signature); 653 xml.append(signatureString); 654 } 655 } 656 657 if (providerId != null) { 658 xml.append(IFSConstants.LEFT_ANGLE) 659 .append(prefixLIB) 660 .append(IFSConstants.PROVIDER_ID) 661 .append(IFSConstants.RIGHT_ANGLE) 662 .append(providerId) 663 .append(IFSConstants.START_END_ELEMENT) 664 .append(prefixLIB) 665 .append(IFSConstants.PROVIDER_ID) 666 .append(IFSConstants.RIGHT_ANGLE); 667 } 668 669 if (status != null) { 670 xml.append(status.toString(includeNS, true)); 671 } 672 673 if (relayState != null) { 674 xml.append(IFSConstants.LEFT_ANGLE) 675 .append(prefixLIB) 676 .append(IFSConstants.RELAY_STATE) 677 .append(IFSConstants.RIGHT_ANGLE) 678 .append(relayState) 679 .append(IFSConstants.START_END_ELEMENT) 680 .append(prefixLIB) 681 .append(IFSConstants.RELAY_STATE) 682 .append(IFSConstants.RIGHT_ANGLE); 683 } 684 685 xml.append(IFSConstants.START_END_ELEMENT) 686 .append(prefixLIB) 687 .append(IFSConstants.LOGOUT_RESPONSE) 688 .append(IFSConstants.RIGHT_ANGLE); 689 690 return xml.toString(); 691 } 692 693 /** 694 * Returns <code>FSLogoutResponse</code> object. The object 695 * is created by parsing an Base64 encode authentication 696 * request String. 697 * 698 * @param encodedRes the encode string 699 * @throws FSMsgException if there is an error creating this object. 700 * @throws SAMLException if there is an error creating this object. 701 */ 702 public static FSLogoutResponse parseBASE64EncodedString(String encodedRes) 703 throws FSMsgException, SAMLException { 704 if (encodedRes != null){ 705 String decodedNameRegRes = new String(Base64.decode(encodedRes)); 706 if (FSUtils.debug.messageEnabled()) { 707 FSUtils.debug.message("FSLogoutResponse." 708 + "parseBASE64EncodedString: decoded input string: " 709 + decodedNameRegRes); 710 } 711 return parseXML(decodedNameRegRes); 712 } else { 713 if (FSUtils.debug.messageEnabled()) { 714 FSUtils.debug.message( 715 "FSLogoutResponse.parseBASE64EncodedString" 716 + ": null String passed in as argument."); 717 } 718 throw new FSMsgException("nullInput",null); 719 } 720 } 721 722 /** 723 * Returns a Base64 Encoded String. 724 * 725 * @return a Base64 Encoded String. 726 * @throws FSMsgException if there is an error encoding the string. 727 */ 728 public String toBASE64EncodedString() throws FSMsgException { 729 if ((responseID == null) || (responseID.length() == 0)){ 730 responseID = FSUtils.generateID(); 731 if (responseID == null) { 732 FSUtils.debug.error("FSLogoutResponse.toBASE64EncodedString: " 733 + "couldn't generate ResponseID."); 734 throw new FSMsgException("errorGenerateID",null); 735 } 736 } 737 return Base64.encode(this.toXMLString().getBytes()); 738 } 739 740 /** 741 * Unsupported operation. 742 */ 743 public void signXML() { 744 } 745 746 /** 747 * Signs the <code>LogoutResponse</code>. 748 * 749 * @param certAlias the Certificate Alias. 750 * @throws XMLSignatureException if this object cannot be signed. 751 */ 752 public void signXML(String certAlias) throws SAMLException { 753 FSUtils.debug.message("FSLogoutResponse.signXML: Called"); 754 if (signed) { 755 if (FSUtils.debug.messageEnabled()) { 756 FSUtils.debug.message("FSLogoutResponse.signXML: " 757 + "the assertion is already signed."); 758 } 759 throw new SAMLResponderException(FSUtils.BUNDLE_NAME, 760 "alreadySigned",null); 761 } 762 if (certAlias == null || certAlias.length() == 0) { 763 throw new SAMLResponderException(FSUtils.BUNDLE_NAME, 764 "cannotFindCertAlias",null); 765 } 766 try{ 767 XMLSignatureManager manager = XMLSignatureManager.getInstance(); 768 if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) { 769 signatureString = manager.signXML(this.toXMLString(true, true), 770 certAlias, 771 IFSConstants.DEF_SIG_ALGO, 772 IFSConstants.ID, 773 this.id, false); 774 } else if (minorVersion == 775 IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { 776 signatureString = 777 manager.signXML(this.toXMLString(true, true), 778 certAlias, IFSConstants.DEF_SIG_ALGO, 779 IFSConstants.RESPONSE_ID, 780 this.getResponseID(), false); 781 } else { 782 if (FSUtils.debug.messageEnabled()) { 783 FSUtils.debug.message("invalid minor version."); 784 } 785 } 786 787 signature = XMLUtils.toDOMDocument(signatureString, FSUtils.debug) 788 .getDocumentElement(); 789 790 signed = true; 791 xmlString = this.toXMLString(true, true); 792 } catch (Exception e) { 793 throw new SAMLResponderException(FSUtils.BUNDLE_NAME, 794 "signFailed",null); 795 } 796 } 797 798 /** 799 * Sets the Signature. 800 * 801 * @param elem the Document Element. 802 * @return true if success otherwise false. 803 */ 804 public boolean setSignature(Element elem) { 805 signatureString = XMLUtils.print(elem); 806 return super.setSignature(elem); 807 } 808 809 /** 810 * Returns an URL Encoded String. 811 * 812 * @return a url encoded query string. 813 * @throws FSMsgException if there is an error. 814 */ 815 public String toURLEncodedQueryString() throws FSMsgException { 816 if ((providerId == null) || (providerId.length() == 0)) { 817 FSUtils.debug.error("FSLogoutResponse." 818 + "toURLEncodedQueryString: providerId is null in " 819 + "the response "); 820 throw new FSMsgException("nullProviderIdInRequest",null); 821 } 822 if ((responseID == null) || (responseID.length() == 0)){ 823 responseID = FSUtils.generateID(); 824 if (responseID == null) { 825 FSUtils.debug.error("FSNameRegistrationRequest." 826 + "toURLEncodedQueryString: couldn't generate " 827 + "responseID."); 828 throw new FSMsgException("errorGenerateID",null); 829 } 830 } 831 832 StringBuffer urlEncodedAuthnReq = new StringBuffer(300); 833 urlEncodedAuthnReq.append(IFSConstants.RESPONSE_ID) 834 .append(IFSConstants.EQUAL_TO) 835 .append(URLEncDec.encode(responseID)) 836 .append(IFSConstants.AMPERSAND); 837 838 if((inResponseTo != null) && (inResponseTo.length() > 0)) { 839 urlEncodedAuthnReq.append(IFSConstants.IN_RESPONSE_TO) 840 .append(IFSConstants.EQUAL_TO) 841 .append(URLEncDec.encode(inResponseTo)) 842 .append(IFSConstants.AMPERSAND); 843 } 844 urlEncodedAuthnReq.append(IFSConstants.MAJOR_VERSION) 845 .append(IFSConstants.EQUAL_TO) 846 .append(majorVersion) 847 .append(IFSConstants.AMPERSAND) 848 .append(IFSConstants.MINOR_VERSION) 849 .append(IFSConstants.EQUAL_TO) 850 .append(minorVersion) 851 .append(IFSConstants.AMPERSAND); 852 853 if (issueInstant != null) { 854 urlEncodedAuthnReq.append(IFSConstants.ISSUE_INSTANT) 855 .append(IFSConstants.EQUAL_TO) 856 .append(URLEncDec.encode( 857 DateUtils.toUTCDateFormat(issueInstant))) 858 .append(IFSConstants.AMPERSAND); 859 } else { 860 FSUtils.debug.error("FSLogoutResponse." 861 + "toURLEncodedQueryString: issueInstant missing"); 862 String[] args = { IFSConstants.ISSUE_INSTANT }; 863 throw new FSMsgException("missingAttribute",args); 864 } 865 if(providerId != null && providerId.length() != 0) { 866 urlEncodedAuthnReq.append(IFSConstants.PROVIDER_ID) 867 .append(IFSConstants.EQUAL_TO) 868 .append(URLEncDec.encode(providerId)) 869 .append(IFSConstants.AMPERSAND); 870 } 871 872 if(relayState != null && relayState.length() != 0) { 873 urlEncodedAuthnReq.append(IFSConstants.RELAY_STATE) 874 .append(IFSConstants.EQUAL_TO) 875 .append(URLEncDec.encode(relayState)) 876 .append(IFSConstants.AMPERSAND); 877 } 878 879 if (status != null) { 880 urlEncodedAuthnReq.append(IFSConstants.VALUE) 881 .append(IFSConstants.EQUAL_TO) 882 .append(URLEncDec.encode( 883 status.getStatusCode().getValue())) 884 .append(IFSConstants.AMPERSAND); 885 } 886 return urlEncodedAuthnReq.toString(); 887 } 888 889 890 /** 891 * Returns <code>FSLogoutResponse</code> object. The 892 * object is creating by parsing the <code>HttpServletRequest</code> 893 * object. 894 * 895 * @param request the <code>HttpServletRequest</code> object. 896 * @throws FSMsgException if there is an error creating this object. 897 * @throws SAMLException if there is an error. 898 */ 899 public static FSLogoutResponse parseURLEncodedRequest( 900 HttpServletRequest request) 901 throws FSMsgException, SAMLException { 902 FSLogoutResponse retLogoutResponse = new FSLogoutResponse(); 903 try { 904 FSUtils.debug.message("checking minor version"); 905 retLogoutResponse.majorVersion = 906 Integer.parseInt( 907 request.getParameter(IFSConstants.MAJOR_VERSION)); 908 retLogoutResponse.minorVersion = 909 Integer.parseInt( 910 request.getParameter(IFSConstants.MINOR_VERSION)); 911 } catch(NumberFormatException ex){ 912 throw new FSMsgException("invalidNumber",null); 913 } 914 915 String requestID = request.getParameter(IFSConstants.RESPONSE_ID); 916 if (requestID != null) { 917 retLogoutResponse.responseID = requestID ; 918 } else { 919 String[] args = { IFSConstants.RESPONSE_ID }; 920 throw new FSMsgException("missingAttribute",args); 921 } 922 retLogoutResponse.inResponseTo = 923 request.getParameter(IFSConstants.IN_RESPONSE_TO); 924 925 String instantString = 926 request.getParameter(IFSConstants.ISSUE_INSTANT); 927 if (instantString == null || instantString.length() == 0) { 928 String[] args = { IFSConstants.ISSUE_INSTANT }; 929 throw new FSMsgException("missingAttribute",args); 930 } 931 try{ 932 retLogoutResponse.issueInstant = 933 DateUtils.stringToDate(instantString); 934 } catch (ParseException e){ 935 throw new FSMsgException("parseError",null); 936 } 937 FSUtils.debug.message(" get provider Id"); 938 String providerID = request.getParameter(IFSConstants.PROVIDER_ID); 939 if (providerID != null) { 940 retLogoutResponse.providerId = providerID; 941 if (FSUtils.debug.messageEnabled()) { 942 FSUtils.debug.message("ProviderID : " 943 + retLogoutResponse.providerId); 944 } 945 } else { 946 if (FSUtils.debug.messageEnabled()) { 947 FSUtils.debug.message("ProviderID : " 948 + retLogoutResponse.providerId); 949 } 950 throw new FSMsgException("missingElement",null); 951 } 952 953 String relayState = request.getParameter(IFSConstants.RELAY_STATE); 954 if (relayState != null) { 955 retLogoutResponse.relayState = relayState; 956 if (FSUtils.debug.messageEnabled()) { 957 FSUtils.debug.message("RelayState:" 958 + retLogoutResponse.relayState); 959 } 960 } 961 962 String value = request.getParameter(IFSConstants.VALUE); 963 if (value != null){ 964 if (FSUtils.debug.messageEnabled()) { 965 FSUtils.debug.message("Status : " + value); 966 } 967 StatusCode statusCode = new StatusCode(value); 968 retLogoutResponse.status = new Status(statusCode); 969 } else { 970 if (FSUtils.debug.messageEnabled()) { 971 FSUtils.debug.message("Status : " + value); 972 } 973 throw new FSMsgException("missingElement",null); 974 } 975 976 FSUtils.debug.message("Returning Logout response Object"); 977 return retLogoutResponse; 978 } 979 }