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