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: FSAuthnResponse.java,v 1.2 2008/06/25 05:46:43 qcheng Exp $
026 *
027 */
028
029
030package com.sun.identity.federation.message;
031
032import com.sun.identity.federation.message.common.FSMsgException;
033import com.sun.identity.federation.common.FSUtils;
034import com.sun.identity.federation.common.IFSConstants;
035import com.sun.identity.saml.common.SAMLException;
036import com.sun.identity.saml.common.SAMLConstants;
037import com.sun.identity.saml.common.SAMLResponderException;
038import com.sun.identity.saml.common.SAMLVersionMismatchException;
039import com.sun.identity.saml.protocol.Response;
040import com.sun.identity.saml.protocol.Status;
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.xml.XMLUtils;
045import java.io.IOException;
046import java.text.ParseException;
047import java.util.List;
048import java.util.Collections;
049import java.util.ArrayList;
050import java.util.Iterator;
051import java.util.Date;
052import org.w3c.dom.Element;
053import org.w3c.dom.Node;
054import org.w3c.dom.NodeList;
055import org.w3c.dom.Document;
056
057/**
058 * The class <code>FSAuthnResponse</code> creates and parses the
059 * Liberty Response. This class extends the <code>SAML</code>
060 * <code>Response</code>.
061 *
062 * @supported.all.api
063 */
064
065public class FSAuthnResponse extends Response {
066
067    private String providerId = null;
068    protected String    relayState      = null;
069    protected String consentURI = null;
070    protected int minorVersion = 0;
071    protected String id = null; 
072    protected Element domElement = null;
073    
074
075   /**
076    * Constructor to create <code>FSAuthnResponse</code> object.
077    *
078    * @param responseID value of the <code>ResponseID</code> attribute.
079    * @param inResponseTo value of the <code>inResponseTo</code> attribute.
080    * @param status the <code>Status</code> object.
081    * @param contents  List of Assertions in the response.
082    *                  It could be null when there are no Assertions.
083    * @param relayState value of the <code>RelayState</code> attribute.
084    * @throws FSMsgException on error.
085    * @throws SAMLException on error.
086    */
087    public FSAuthnResponse(String responseID,String inResponseTo,
088                           Status status, List contents, String relayState)
089                           throws SAMLException, FSMsgException {
090        super( responseID, inResponseTo, status, contents);
091        setIssueInstant(new Date());
092        this.relayState = relayState;
093    }
094
095   /**
096    * Creates <code>FSAuthnResponse</code> object from XML Schema.
097    *
098    * @param xml the XML Schema for this object.
099    * @throws <code>SAMLException</code> on error.
100    * @throws FSMsgException on error.
101    */
102    public static FSAuthnResponse parseAuthnResponseXML(
103        String xml) throws SAMLException, FSMsgException {
104        // parse the xml string
105        FSUtils.debug.message("FSAuthnResponse.parseAuthnResponseXML: Called");
106        Element root;
107        Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug);
108        if (doc == null) {
109           if (FSUtils.debug.messageEnabled()) {
110                    FSUtils.debug.message(
111                        "FSAuthnResponse.parseXML:Error "
112                        + "while parsing input xml string");
113                }
114           throw new FSMsgException("parseError",null);
115        }
116        root = doc.getDocumentElement();
117        return new FSAuthnResponse(root);
118    }
119
120    /**
121     * Constructor creates <code>FSAuthnResponse</code> object from
122     * Document Element.
123     *
124     * @param root the Document Element
125     * @throws SAMLException on error.
126     * @throws FSMsgException on error.
127     */
128    public FSAuthnResponse(Element root) throws SAMLException, FSMsgException {
129        // Make sure this is a Response
130        FSUtils.debug.message("FSAuthnResponse(Element): Called");
131        if (root == null) {
132            FSUtils.debug.message("FSAuthnResponse(Element): "
133                + "Input paramenter (root) is null");
134            throw new FSMsgException("nullInput",null);
135        }
136        String tag = null;
137        if (((tag = root.getLocalName()) == null) ||
138            (!tag.equals(IFSConstants.AUTHN_RESPONSE))) {
139            FSUtils.debug.message("FSAuthnResponse(Element): "
140                + "Root element name is not AuthnResponse");
141            throw new FSMsgException("wrongInput",null);
142        }
143        domElement = root;
144        consentURI = root.getAttribute(IFSConstants.CONSENT);
145
146        // Attribute ResponseID
147        id = root.getAttribute(IFSConstants.ID);
148        responseID = root.getAttribute(IFSConstants.RESPONSE_ID);
149        if ((responseID == null) || (responseID.length() == 0)) {
150            if (FSUtils.debug.messageEnabled()) {
151                FSUtils.debug.message("FSAuthnResponse(Element): "
152                    + "AuthnResponse doesn't have ResponseID attribute");
153            }
154            String[] args = { IFSConstants.RESPONSE_ID };
155            throw new FSMsgException("missingAttribute",args);
156        }
157
158        inResponseTo = root.getAttribute(IFSConstants.IN_RESPONSE_TO);
159        if (inResponseTo == null) {
160            if (FSUtils.debug.messageEnabled()) {
161                FSUtils.debug.message("FSAuthnResponse(Element): "
162                    + "AuthnResponse doesn't have InResponseTo attribute");
163            }            
164        }
165        
166        // Attribute IssueInstant
167        String instantString = root.getAttribute(IFSConstants.ISSUE_INSTANT);
168
169        if ((instantString == null) || (instantString.length() == 0)) {
170            FSUtils.debug.message("FSAuthnResponse(Element): "
171                                  + " missing IssueInstant");
172            String[] args = { IFSConstants.ISSUE_INSTANT };
173            throw new FSMsgException("missingAttribute",args);
174        } else {
175            try {
176                issueInstant = DateUtils.stringToDate(instantString);
177            } catch (ParseException e) {
178                FSUtils.debug.message(
179                    "FSAuthnResponse(Element): could not parse IssueInstant",e);
180                throw new FSMsgException("wrongInput",null);
181            }
182        }
183
184        parseMajorVersion(root.getAttribute(IFSConstants.MAJOR_VERSION));
185        parseMinorVersion(root.getAttribute(IFSConstants.MINOR_VERSION));
186        
187        setRecipient(root.getAttribute(IFSConstants.RECIPIENT));
188 
189        NodeList nl = root.getChildNodes();
190        Node child;
191        String childName;
192        int length = nl.getLength();
193        for (int i = 0; i < length; i++) {
194            child = nl.item(i);
195            if ((childName = child.getLocalName()) != null) {
196                if (childName.equals(IFSConstants.STATUS)) {
197                    if (status != null) {
198                        if (FSUtils.debug.messageEnabled()) {
199                            FSUtils.debug.message("FSAuthnResponse(Element): "
200                                + "included more than one <Status>");
201                        }
202                        throw new FSMsgException("moreElement",null);
203                    }
204                    status = new Status((Element) child);
205                } else if (childName.equals(IFSConstants.ASSERTION)) {
206                    if (assertions == Collections.EMPTY_LIST) {
207                        assertions = new ArrayList();
208                    }
209                    assertions.add(new FSAssertion((Element) child));
210                } else if (childName.equals(IFSConstants.RELAY_STATE)) {
211                    // make sure the providerId is not assigned already
212                    if (relayState != null) {
213                        if (FSUtils.debug.messageEnabled()) {
214                            FSUtils.debug.message("FSAuthnResponse(Element): "
215                                + "should contain only one RelayState.");
216                        } 
217                        throw new FSMsgException("wrongInput",null);
218                    }
219                    relayState = XMLUtils.getElementValue((Element) child);
220                } else if (childName.equals(IFSConstants.PROVIDER_ID)) {
221                    if (providerId != null && providerId.length() != 0) {
222                        if (FSUtils.debug.messageEnabled()) {
223                            FSUtils.debug.message("FSAuthnResponse(Element): "
224                                + "should contain only one ProviderID.");
225                        } 
226                        throw new FSMsgException("wrongInput",null);
227                    }
228                    providerId = XMLUtils.getElementValue((Element) child);
229                  } else {
230                    if (FSUtils.debug.messageEnabled()) {
231                        FSUtils.debug.message("FSAuthnResponse(Element): "
232                            + "included wrong element: " + childName);
233                    }
234                    throw new FSMsgException("wrongInput",null);
235                }
236            } // end if childName != null
237        } // end for loop
238
239        if (status == null) {
240            FSUtils.debug.message("FSAuthnResponse(Element): "
241                + "missing element <Status>.");
242            throw new FSMsgException("missingElement",null);
243        }
244        //check for signature
245        List signs = XMLUtils.getElementsByTagNameNS1(root,
246                                        SAMLConstants.XMLSIG_NAMESPACE_URI,
247                                        SAMLConstants.XMLSIG_ELEMENT_NAME);
248        int signsSize = signs.size();
249        if (signsSize == 1) {
250            Element elem = (Element)signs.get(0);
251            setSignature(elem);
252            xmlString = XMLUtils.print(root);
253            signed = true;
254        } else if (signsSize != 0) {
255            if (FSUtils.debug.messageEnabled()) {
256                FSUtils.debug.message("FSAuthnResponse(Element): "
257                    + "included more than one Signature element.");
258            }
259            throw new FSMsgException("moreElement",null);
260        }        
261        //end check for signature
262    }
263
264   /**
265    * Returns the value of the <code>id</code> attribute.
266    *
267    * @return the value of <code>id</code> attribute.
268    * @see #setID(String)
269    */
270    public String getID() {
271        return id;
272    }
273    
274    /**
275     * Sets the value of the <code>id</code> attribute.
276     *
277     * @param id the new value of <code>id</code> attribute.
278     * @see #getID
279     */
280    public void setID(String id) {
281        this.id = id;
282    }    
283    
284   /**
285    * Returns the <code>ProviderID</code> attribute value.
286    *
287    * @return value of the <code>ProviderID</code> attribute.
288    * @see #setProviderId(String)
289    */
290    public String getProviderId() {
291       return providerId;
292    }
293   
294    /**
295     * Sets the <code>ProviderID</code> attribute value.
296     *
297     * @param provId new value of <code>ProviderID</code> attribute.
298     * @see #getProviderId
299     */
300    public void setProviderId(String provId) {
301       providerId = provId;
302    }
303   
304   /**
305    * Returns a signed XML Representation of this object.
306    *
307    * @return a signed XML Representation of this object.
308    */
309    public String getSignedXMLString(){
310       return xmlString;
311    }
312   
313   /**
314    * Returns the Signature string.
315    *
316    * @return the Signature string.
317    */
318    public String getSignatureString(){
319       return signatureString;
320    }
321
322   /**
323    * Returns the value <code>MinorVersion</code> attribute.
324    *
325    * @return the value <code>MinorVersion</code> attribute.
326    * @see #setMinorVersion(int)
327    */
328    public int getMinorVersion() {
329       return minorVersion;
330    }
331
332   /**
333    * Returns the value of <code>MajorVersion</code> attribute.
334    *
335    * @param version the value of <code>MajorVersion</code> attribute.
336    * @see #getMinorVersion
337    */
338    public void setMinorVersion(int version) {
339       minorVersion = version;
340    }
341
342   /**
343    * Returns the value of the <code>consent</code> attribute.
344    *
345    * @return value of <code>consent</code> attribute.
346    * @see #setConsentURI(String)
347    */
348
349    public String getConsentURI() {
350       return consentURI;
351    }
352
353   /**
354    * Sets the value of the <code>consent</code> attribute.
355    *
356    * @param consent new value of <code>consent</code> attribute.
357    * @see #getConsentURI
358    */
359    public void setConsentURI(String consent) {
360       this.consentURI = consent;
361    }
362
363   /**
364    * Returns the Document Element for this object.
365    *
366    * @return the Document Element for this object.
367    */
368    public Element getDOMElement() {
369        return domElement;
370    }
371
372    /**
373     * Parses the input and sets the <code>MajorVersion</code>.
374     *
375     * @param majorVer value of <code>MajorVersion</code> attribute to be set.
376     * @throws FSMsgException on error.
377     * @throws SAMLException if the version is incorrect.
378     */
379    private void parseMajorVersion(String majorVer) 
380                 throws SAMLException, FSMsgException {
381        try {
382            majorVersion = Integer.parseInt(majorVer);
383        } catch (NumberFormatException e) {
384            if (FSUtils.debug.messageEnabled()) {
385                FSUtils.debug.message("FSAuthnResponse(Element): invalid "
386                    + "MajorVersion", e);
387            }
388            throw new FSMsgException("wrongInput",null);
389        }
390
391        if (majorVersion != SAMLConstants.PROTOCOL_MAJOR_VERSION) {
392            if (majorVersion > SAMLConstants.PROTOCOL_MAJOR_VERSION) {
393                if (FSUtils.debug.messageEnabled()) {
394                    FSUtils.debug.message(
395                        "FSAuthnResponse(Element):MajorVersion of"
396                        + " the Response is too high.");
397                }
398                throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME,
399                                                 "responseVersionTooHigh",null);
400            } else {
401                if (FSUtils.debug.messageEnabled()) {
402                    FSUtils.debug.message(
403                        "FSAuthnResponse(Element):MajorVersion of"
404                        + " the Response is too low.");
405                }
406                throw new SAMLVersionMismatchException(
407                    FSUtils.BUNDLE_NAME,"responseVersionTooLow",null);
408            }
409        }
410    }
411
412   /**
413    * Parses the input and set the <code>MinorVersion</code>.
414    *
415    * @param minorVer value of <code>MinorVersion</code> attribute to be set.
416    * @throws FSMsgException on error.
417    * @throws SAMLException if the version is incorrect.
418    */
419    private void parseMinorVersion(
420        String minorVer) throws SAMLException, FSMsgException {
421        try {
422            minorVersion = Integer.parseInt(minorVer);
423        } catch (NumberFormatException e) {
424            if (FSUtils.debug.messageEnabled()) {
425                FSUtils.debug.message("FSAuthnResponse(Element): invalid "
426                    + "MinorVersion", e);
427            }
428            throw new FSMsgException("wrongInput",null);
429        }
430
431        if (minorVersion > IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
432           if(FSUtils.debug.messageEnabled()) {
433              FSUtils.debug.message("FSAuthnResponse.checkMinorVersion:"+
434              " Minor Version of the AuthnResponse is too high.");
435           }
436           throw new FSMsgException("requestVersionTooHigh",null);
437        } else if (minorVersion < IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
438           if(FSUtils.debug.messageEnabled()) {
439              FSUtils.debug.message("FSAuthnResponse.checkMinorVersion:" +
440              " Minor Version of the AuthnResponse is too low.");
441           }
442           throw new FSMsgException("requestVersionTooLow",null);
443        }
444    }
445
446    /**
447     * Returns the <code>RelayState</code> attribute in the Response.
448     *
449     * @return the <code>RelayState</code> attribute in the Response.
450     */
451    public String getRelayState() {
452        return relayState;
453    }
454
455    /**
456     * Returns the string representation of this object.
457     * This method translates the response to an XML document string based on
458     * the Response schema described above.
459     *
460     * @return An XML String representing the response. NOTE: this is a
461     *                complete SAML response xml string with ResponseID,
462     *                MajorVersion, etc.
463     */
464    public String toXMLString()  throws FSMsgException {
465        return this.toXMLString(true, true);
466    }
467
468    /**
469     * Returns a String representation of the &lt;samlp:Response&gt; element.
470     *
471     * @param includeNS : Determines whether or not the namespace qualifier
472     *          is prepended to the Element when converted
473     * @param declareNS : Determines whether or not the namespace is declared
474     *          within the Element.
475     * @return A string containing the valid XML for this element
476     */   
477    public String toXMLString(boolean includeNS, boolean declareNS) 
478           throws FSMsgException {
479        return toXMLString(includeNS, declareNS, false);
480    }
481
482    /**
483     * Returns a String representation of the &lt;samlp:Response&gt; element.
484     *
485     * @param includeNS  Determines whether or not the namespace qualifier
486     *          is prepended to the Element when converted
487     * @param declareNS  Determines whether or not the namespace is declared
488     *          within the Element.
489     * @param includeHeader  Determines whether the output include the xml
490     *                declaration header.
491     * @return A string containing the valid XML for this element
492     */   
493    public String toXMLString(boolean includeNS,
494                        boolean declareNS,
495                        boolean includeHeader)  throws FSMsgException {
496        FSUtils.debug.message("FSAuthnResponse.toXMLString(3): Called");
497        
498        if((providerId == null) || (providerId.length() == 0)){
499            FSUtils.debug.error("FSAuthnResponse.toXMLString: "
500                + "providerId is null ");
501                throw new FSMsgException("nullProviderID",null);
502        }
503        
504        StringBuffer xml = new StringBuffer(300);
505        if (includeHeader) {
506            xml.append(IFSConstants.XML_PREFIX)
507               .append(SAMLConstants.DEFAULT_ENCODING).append("\" ?>\n")
508               .append(IFSConstants.QUOTE)
509               .append(IFSConstants.QUESTION_MARK)
510               .append(IFSConstants.RIGHT_ANGLE)
511               .append(IFSConstants.NL);
512        }
513        String prefixSAML = "";
514        String prefixLIB = "";
515        String prefixSAML_PROTOCOL = "";
516        String uriSAML_PROTOCOL = "";
517        String uriSAML = "";
518        String uriLIB = "";
519        String uriDS="";
520        String uriXSI="";
521        
522        if (includeNS) {
523            prefixLIB = IFSConstants.LIB_PREFIX;
524            prefixSAML = IFSConstants.ASSERTION_PREFIX;
525            prefixSAML_PROTOCOL = IFSConstants.PROTOCOL_PREFIX; 
526        }
527        if (declareNS) {
528            if(minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { 
529               uriLIB = IFSConstants.LIB_12_NAMESPACE_STRING;
530            } else {
531               uriLIB = IFSConstants.LIB_NAMESPACE_STRING;
532            }
533            uriSAML = IFSConstants.assertionDeclareStr;
534            uriSAML_PROTOCOL = IFSConstants.PROTOCOL_NAMESPACE_STRING;
535            uriDS = IFSConstants.DSSAMLNameSpace;
536            uriXSI = IFSConstants.XSI_NAMESPACE_STRING;
537        }
538
539        String instantString = DateUtils.toUTCDateFormat(issueInstant);
540
541        if((responseID != null) && (inResponseTo != null)){
542            xml.append(IFSConstants.LEFT_ANGLE)
543               .append(prefixLIB)
544               .append(IFSConstants.AUTHN_RESPONSE)
545               .append(uriLIB)
546               .append(uriSAML)
547               .append(uriSAML_PROTOCOL)
548               .append(IFSConstants.SPACE)
549               .append(uriDS)
550               .append(IFSConstants.SPACE)
551               .append(uriXSI)
552               .append(IFSConstants.SPACE)
553               .append(IFSConstants.RESPONSE_ID)
554               .append(IFSConstants.EQUAL_TO)
555               .append(IFSConstants.QUOTE)
556               .append(responseID)
557               .append(IFSConstants.QUOTE)
558               .append(IFSConstants.SPACE);
559               
560                if ((inResponseTo != null) && (inResponseTo.length() != 0)) {
561                    xml.append(IFSConstants.SPACE)
562                       .append(IFSConstants.IN_RESPONSE_TO)
563                       .append(IFSConstants.EQUAL_TO)
564                       .append(IFSConstants.QUOTE)
565                       .append(inResponseTo)
566                       .append(IFSConstants.QUOTE);
567                }
568                if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION && 
569                    id != null && (id.length() > 0)) {
570                        xml.append(IFSConstants.SPACE)
571                           .append(IFSConstants.ID)
572                           .append(IFSConstants.EQUAL_TO)
573                           .append(IFSConstants.QUOTE)
574                           .append(id)
575                           .append(IFSConstants.QUOTE);
576                }
577                xml.append(IFSConstants.SPACE)
578                   .append(IFSConstants.MAJOR_VERSION) 
579                   .append(IFSConstants.EQUAL_TO)
580                   .append(IFSConstants.QUOTE)
581                   .append(majorVersion)
582                   .append(IFSConstants.QUOTE)
583                   .append(IFSConstants.SPACE)
584                   .append(IFSConstants.MINOR_VERSION) 
585                   .append(IFSConstants.EQUAL_TO)
586                   .append(IFSConstants.QUOTE)
587                   .append(minorVersion)
588                   .append(IFSConstants.QUOTE)
589                   .append(IFSConstants.SPACE)
590                   .append(IFSConstants.ISSUE_INSTANT)
591                   .append(IFSConstants.EQUAL_TO)
592                   .append(IFSConstants.QUOTE)
593                   .append(instantString)
594                   .append(IFSConstants.QUOTE);
595
596                if (consentURI != null) {
597                    xml.append(IFSConstants.SPACE)
598                       .append(IFSConstants.CONSENT)
599                       .append(IFSConstants.EQUAL_TO)
600                       .append(IFSConstants.QUOTE)
601                       .append(consentURI)
602                       .append(IFSConstants.QUOTE)
603                       .append(IFSConstants.SPACE);
604                }
605                if ((recipient != null) && (recipient.length() != 0)) {
606                    xml.append(IFSConstants.SPACE)
607                       .append(IFSConstants.RECIPIENT)
608                       .append(IFSConstants.EQUAL_TO)
609                       .append(IFSConstants.QUOTE)
610                       .append(recipient)
611                       .append(IFSConstants.QUOTE)
612                       .append(IFSConstants.SPACE);
613                }
614                xml.append(IFSConstants.RIGHT_ANGLE);
615        }
616
617        if (signed) {
618            if (signatureString != null && signatureString.length() != 0) {
619                xml.append(signatureString);
620            } else if (signature != null) {
621                signatureString = XMLUtils.print(signature);
622                xml.append(signatureString);
623            }
624        }
625        
626        if (status != null) {
627            xml.append(status.toString(includeNS, false));
628        }
629        
630        if ((assertions != null) && (assertions != Collections.EMPTY_LIST)) {
631            Iterator j = assertions.iterator();
632            while (j.hasNext()) {
633                xml.append(((FSAssertion) j.next())
634                                .toXMLString(true,declareNS));
635            }
636        }
637        
638        xml.append(IFSConstants.LEFT_ANGLE)
639           .append(prefixLIB)
640           .append(IFSConstants.PROVIDER_ID)
641           .append(IFSConstants.RIGHT_ANGLE)
642           .append(providerId)
643           .append(IFSConstants.START_END_ELEMENT)
644           .append(prefixLIB)
645           .append(IFSConstants.PROVIDER_ID)
646           .append(IFSConstants.RIGHT_ANGLE);
647        
648        if (relayState != null && relayState.length() != 0) {
649            xml.append(IFSConstants.LEFT_ANGLE)
650               .append(prefixLIB)
651               .append(IFSConstants.RELAY_STATE)
652               .append(IFSConstants.RIGHT_ANGLE)
653               .append(XMLUtils.escapeSpecialCharacters(relayState))
654               .append(IFSConstants.START_END_ELEMENT)
655               .append(prefixLIB)
656               .append(IFSConstants.RELAY_STATE)
657               .append(IFSConstants.RIGHT_ANGLE);
658        }     
659
660        xml.append(IFSConstants.START_END_ELEMENT)
661           .append(prefixLIB)
662           .append(IFSConstants.AUTHN_RESPONSE)
663           .append(IFSConstants.RIGHT_ANGLE)
664           .append(IFSConstants.NL);
665
666        return xml.toString();
667    }
668    
669   /**
670    * Returns <code>FSAutnResponse</code> object by parsing a 
671    * <code>Base64</code> encoding XML string.
672    *
673    *
674    * @param encodedRes the <code>Base64</code> encoded string.
675    * @return <code>FSAuthnResponse</code> object.
676    * @throws FSMsgException if there is an error parsing
677    *         the <code>Base64</code> encoded string.
678    * @throws SAMLException if there is an error creating
679    *         the <code>FSAuthnResponse</code> object.
680    */    
681    public static FSAuthnResponse parseBASE64EncodedString(String encodedRes)
682                                  throws FSMsgException, SAMLException {
683        FSUtils.debug.message(
684            "FSAuthnResponse.parseBASE64EncodedString: Called new");
685        if(encodedRes != null){
686            String decodedAuthnRes = new String(Base64.decode(encodedRes));
687            if (FSUtils.debug.messageEnabled()) {
688                FSUtils.debug.message(
689                    "FSAuthnResponse.parseBASE64EncodedString: "
690                    + "Decoded AuthnResponse message: \n"
691                    + decodedAuthnRes);
692            }
693            return parseAuthnResponseXML(decodedAuthnRes);
694        } else {
695            if (FSUtils.debug.messageEnabled()) {
696                    FSUtils.debug.message(
697                        "FSAuthnResponse.parseBASE64EncodedString: "
698                        + "null String passed in as argument.");
699                }
700                throw new FSMsgException("nullInput",null);
701        }
702    }
703    
704   /**
705    * Returns a <code>Base64</code> encoded string representing this
706    * object.
707    *
708    * @return a <code>Base64</code> encoded string representing this
709    *         object.
710    * @throws FSMsgException if there is an error creating
711    *         a <code>Base64</code> encoded string.
712    */
713    public String toBASE64EncodedString() throws FSMsgException  {
714        FSUtils.debug.message("FSAuthnResponse.toBASE64EncodedString: Called");
715        if ((responseID == null) || (responseID.length() == 0)){
716         responseID = FSUtils.generateID();
717            if (responseID == null) {
718                FSUtils.debug.error("FSAuthnResponse.toBASE64EncodedString: "
719                    + "couldn't generate ResponseID.");
720                throw new FSMsgException("errorGenerateID",null);
721            }
722        }
723        return Base64.encode(this.toXMLString(true, true).getBytes());
724    } 
725    
726    /**
727     * Signs the <code>Response</code>.
728     *
729     * @param certAlias the Certificate Alias
730     * @throws SAMLException if <code>Response</code>
731     *         cannot be signed.
732     */
733    public void signXML(String certAlias) throws SAMLException {
734        FSUtils.debug.message("FSAuthnResponse.signXML: Called");
735        if (signed) {
736            if (FSUtils.debug.messageEnabled()) {
737                FSUtils.debug.message(
738                    "FSAuthnResponse.signXML: the assertion is "
739                    + "already signed.");
740            }
741            throw new SAMLResponderException(
742                                  FSUtils.BUNDLE_NAME,"alreadySigned",null);
743        }
744        if (certAlias == null || certAlias.length() == 0) {
745            throw new SAMLResponderException(
746                FSUtils.BUNDLE_NAME,"cannotFindCertAlias",null);
747        }
748        try{
749            XMLSignatureManager manager = XMLSignatureManager.getInstance();
750            if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
751                signatureString = manager.signXML(this.toXMLString(true, true), 
752                                          certAlias, 
753                                          IFSConstants.DEF_SIG_ALGO, 
754                                          IFSConstants.ID, 
755                                          this.id, false);
756            } else if (minorVersion == 
757                          IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
758                  signatureString = manager.signXML(
759                                         this.toXMLString(true, true), 
760                                         certAlias, IFSConstants.DEF_SIG_ALGO,
761                                         IFSConstants.RESPONSE_ID, 
762                                         this.getResponseID(), false);
763            } else { 
764                if (FSUtils.debug.messageEnabled()) { 
765                    FSUtils.debug.message("invalid minor version.");                 
766                }
767            }  
768            signature = XMLUtils.toDOMDocument(signatureString, FSUtils.debug)
769                                               .getDocumentElement();
770            signed = true;
771            xmlString = this.toXMLString(true, true);      
772        } catch(Exception e) {
773            throw new SAMLResponderException(FSUtils.BUNDLE_NAME,
774                                             "signFailed",null);
775        }
776    }
777    
778   /**
779    * Sets the <code>Element</code> signature.
780    *
781    * @param elem the <code>Element</code> object
782    * @return true if signature is set otherwise false
783    */
784    public boolean setSignature(Element elem) {
785        signatureString = XMLUtils.print(elem); 
786        return super.setSignature(elem); 
787    }
788}