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