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