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: FSResponse.java,v 1.2 2008/06/25 05:46:45 qcheng Exp $
026 * Portions Copyrighted 2014 ForgeRock AS
027 */
028
029package com.sun.identity.federation.message;
030
031import java.text.ParseException;
032import java.util.List;
033import java.util.Collections;
034import java.util.ArrayList;
035import java.util.Iterator;
036
037import java.io.ByteArrayInputStream;
038import java.io.IOException;
039
040import org.w3c.dom.Element;
041import org.w3c.dom.Node;
042import org.w3c.dom.NodeList;
043import org.w3c.dom.Document;
044
045import com.sun.identity.shared.encode.Base64;
046import com.sun.identity.shared.xml.XMLUtils;
047import com.sun.identity.shared.DateUtils;
048import com.sun.identity.saml.common.SAMLConstants;
049import com.sun.identity.saml.common.SAMLException;
050import com.sun.identity.saml.common.SAMLResponderException;
051import com.sun.identity.saml.common.SAMLVersionMismatchException;
052import com.sun.identity.saml.xmlsig.XMLSignatureManager;
053import com.sun.identity.saml.protocol.Response;
054import com.sun.identity.saml.protocol.Status;
055
056import com.sun.identity.federation.message.common.FSMsgException;
057import com.sun.identity.federation.common.FSUtils;
058import com.sun.identity.federation.common.IFSConstants;
059
060/**
061 * This class contains methods for creating a Liberty <code>Response</code>.
062 *
063 * @supported.all.api
064 * @deprecated since 12.0.0
065 */
066@Deprecated
067public class FSResponse extends Response {
068    protected String id = null;
069    
070    /**
071     * Returns the value of <code>id</code> attribute.
072     *
073     * @return the value of <code>id</code> attribute.
074     * @see #setID(String)
075     */
076    public String getID() {
077        return id;
078    }
079    
080    /**
081     * Sets the value of <code>id</code> attribute.
082     *
083     * @param id the value of <code>id</code> attribute.
084     * @see #getID()
085     */
086    public void setID(String id) {
087        this.id = id;
088    }
089    
090    /**
091     * Returns the signed <code>XML</code> string.
092     *
093     * @return the signed <code>XML</code> string.
094     */
095    public String getSignatureString(){
096        return signatureString;
097    }
098    
099    /**
100     * Returns the <code>MinorVersion</code>.
101     *
102     * @return the <code>MinorVersion</code>.
103     * @see #setMinorVersion(int)
104     */
105    
106    public int getMinorVersion() {
107        return minorVersion;
108    }
109    
110    /**
111     * Sets the <code>MinorVersion</code>.
112     *
113     * @param version the <code>MinorVersion</code>.
114     * @see #getMinorVersion()
115     */
116    public void setMinorVersion(int version) {
117        minorVersion = version;
118    }
119    
120    /**
121     * Constructor creates <code>FSResponse</code> object.
122     *
123     * @param responseID value of <code>ResponseId</code> attribute.
124     * @param inResponseTo value of <code>inResponseTo</code> attribute.
125     * @param status the <code>Status</code> object.
126     * @param contents list containing response elements.
127     * @throws SAMLException it there is an error creating this object.
128     * @throws FSMsgException it there is an error creating this object.
129     */
130    public FSResponse(String responseID,
131            String inResponseTo,
132            Status status,
133            List contents) throws SAMLException, FSMsgException {
134        super( responseID, inResponseTo, status, contents);
135    }
136    
137    public static FSResponse parseResponseXML(
138            String xml
139            ) throws SAMLException, FSMsgException {
140        // parse the xml string
141        FSUtils.debug.message("FSResponse.parseResponseXML: Called");
142        Element root;
143        Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug);
144        if (doc == null) {
145            FSUtils.debug.error("FSResponse.parseXML:Error "
146                    + "while parsing input xml string");
147            throw new FSMsgException("parseError",null);
148        }
149        root = doc.getDocumentElement();
150        return new FSResponse(root);
151    }
152    
153    /**
154     * Constructor creates <code>FSResponse</code> object form
155     * a Document Element.
156     *
157     * @param root the Document Element object.
158     * @throws SAMLException if there is an error creating this object.
159     * @throws FSMsgException if there is an error creating this object.
160     */
161    public FSResponse(Element root) throws SAMLException, FSMsgException {
162        FSUtils.debug.message("FSResponse(Element): Called");
163        if (root == null) {
164            FSUtils.debug.message("FSResponse(Element): "
165                    + "Input paramenter (root) is null");
166            throw new FSMsgException("nullInput",null);
167        }
168        String tag = null;
169        if (((tag = root.getLocalName()) == null) ||
170                (!tag.equals("Response"))) {
171            FSUtils.debug.message("FSResponse(Element): "
172                    + "Root element name is not Response");
173            throw new FSMsgException("wrongInput",null);
174        }
175        id = root.getAttribute("id");
176        responseID = root.getAttribute("ResponseID");
177        if ((responseID == null) || (responseID.length() == 0)) {
178            if (FSUtils.debug.messageEnabled()) {
179                FSUtils.debug.message("FSResponse(Element): "
180                        + "Response doesn't have ResponseID attribute");
181            }
182            String[] args = { IFSConstants.RESPONSE_ID };
183            throw new FSMsgException("missingAttribute",args);
184        }
185        
186        inResponseTo = root.getAttribute("InResponseTo");
187        if (inResponseTo == null) {
188            if (FSUtils.debug.messageEnabled()) {
189                FSUtils.debug.message("FSResponse(Element): "
190                        + "Response doesn't have InResponseTo attribute");
191            }
192            String[] args = { IFSConstants.IN_RESPONSE_TO };
193            throw new FSMsgException("missingAttribute",args);
194        }
195        
196        // Attribute IssueInstant
197        String instantString = root.getAttribute("IssueInstant");
198        if ((instantString == null) || (instantString.length() == 0)) {
199            FSUtils.debug.message("FSResponse(Element): missing IssueInstant");
200            String[] args = { IFSConstants.ISSUE_INSTANT };
201            throw new FSMsgException("missingAttribute",args);
202        } else {
203            try {
204                issueInstant = DateUtils.stringToDate(instantString);
205            } catch (ParseException e) {
206                if (FSUtils.debug.messageEnabled()) {
207                    FSUtils.debug.message("FSResponse(Element): could not "
208                            + "parse IssueInstant:", e);
209                }
210                throw new FSMsgException("wrongInput", null);
211            }
212        }
213        parseMajorVersion(root.getAttribute("MajorVersion"));
214        parseMinorVersion(root.getAttribute("MinorVersion"));
215        setRecipient(root.getAttribute("Recipient"));
216        NodeList nl = root.getChildNodes();
217        Node child;
218        String childName;
219        int length = nl.getLength();
220        for (int i = 0; i < length; i++) {
221            child = nl.item(i);
222            if ((childName = child.getLocalName()) != null) {
223                if (childName.equals("Status")) {
224                    if (status != null) {
225                        if (FSUtils.debug.messageEnabled()) {
226                            FSUtils.debug.message(
227                                    "FSResponse(Element): included more"
228                                    + " than one <Status>");
229                        }
230                        throw new FSMsgException("moreElement",null);
231                    }
232                    status = new Status((Element) child);
233                } else if (childName.equals("Assertion")) {
234                    if (assertions == Collections.EMPTY_LIST) {
235                        assertions = new ArrayList();
236                    }
237                    assertions.add(new FSAssertion((Element) child));
238                }else {
239                    if (FSUtils.debug.messageEnabled()) {
240                        FSUtils.debug.message(
241                                "FSResponse(Element): included wrong "
242                                + "element: " + childName);
243                    }
244                    throw new FSMsgException("wrongInput",null);
245                }
246            } // end if childName != null
247        } // end for loop
248        
249        if (status == null) {
250            FSUtils.debug.message(
251                    "FSResponse(Element): missing element <Status>.");
252            throw new FSMsgException("missingElement",null);
253        }
254        
255        //check for signature
256        List signs = XMLUtils.getElementsByTagNameNS1(root,
257                SAMLConstants.XMLSIG_NAMESPACE_URI,
258                SAMLConstants.XMLSIG_ELEMENT_NAME);
259        int signsSize = signs.size();
260        if (signsSize == 1) {
261            Element elem = (Element)signs.get(0);
262            setSignature(elem);
263            xmlString = XMLUtils.print(root);
264            signed = true;
265        } else if (signsSize != 0) {
266            if (FSUtils.debug.messageEnabled()) {
267                FSUtils.debug.message("FSResponse(Element): included more than"
268                        + " one Signature element.");
269            }
270            throw new FSMsgException("moreElement",null);
271        }
272        //end check for signature
273    }
274    
275    /**
276     * Sets the <code>MajorVersion</code> by parsing the version string.
277     *
278     * @param majorVer a String representing the <code>MajorVersion</code> to
279     *        be set.
280     * @throws SAMLException on error.
281     * @throws FSMsgException if there is an error parsing the version string.
282     */
283    private void parseMajorVersion(String majorVer)
284    throws SAMLException, FSMsgException {
285        try {
286            majorVersion = Integer.parseInt(majorVer);
287        } catch (NumberFormatException e) {
288            if (FSUtils.debug.messageEnabled()) {
289                FSUtils.debug.message("FSResponse(Element): invalid "
290                        + "MajorVersion", e);
291            }
292            throw new FSMsgException("wrongInput",null);
293        }
294        
295        if (majorVersion != SAMLConstants.PROTOCOL_MAJOR_VERSION) {
296            if (majorVersion > SAMLConstants.PROTOCOL_MAJOR_VERSION) {
297                if (FSUtils.debug.messageEnabled()) {
298                    FSUtils.debug.message("FSResponse(Element):MajorVersion of"
299                            + " the Response is too high.");
300                }
301                throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME,
302                        "responseVersionTooHigh",null);
303            } else {
304                if (FSUtils.debug.messageEnabled()) {
305                    FSUtils.debug.message("FSResponse(Element):MajorVersion of"
306                            + " the Response is too low.");
307                }
308                throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME,
309                        "responseVersionTooLow",null);
310            }
311        }
312    }
313    
314    /**
315     * Sets the <code>MinorVersion</code> by parsing the version string.
316     *
317     * @param minorVer a String representing the <code>MinorVersion</code> to
318     *        be set.
319     * @throws SAMLException when the version mismatchs.
320     * @throws FSMsgException if there is an error
321     *          parsing the version string.
322     */
323    private void parseMinorVersion(String minorVer)
324    throws SAMLException, FSMsgException {
325        try {
326            minorVersion = Integer.parseInt(minorVer);
327        } catch (NumberFormatException e) {
328            if (FSUtils.debug.messageEnabled()) {
329                FSUtils.debug.message("FSResponse(Element): invalid "
330                        + "MinorVersion", e);
331            }
332            throw new FSMsgException("wrongInput",null);
333        }
334        
335        if (minorVersion > IFSConstants.FF_12_SAML_PROTOCOL_MINOR_VERSION) {
336            FSUtils.debug.error("FSResponse(Element):MinorVersion of"
337                    + " the Response is too high.");
338            throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME,
339                    "responseVersionTooHigh",null);
340        } else if (minorVersion <
341                IFSConstants.FF_11_SAML_PROTOCOL_MINOR_VERSION) {
342            FSUtils.debug.error("FSResponse(Element):MinorVersion of"
343                    + " the Response is too low.");
344            throw new SAMLVersionMismatchException(FSUtils.BUNDLE_NAME,
345                    "responseVersionTooLow",null);
346        }
347    }
348    
349    /**
350     * Returns a String representation of the Logout Response.
351     *
352     * @return a string containing the valid XML for this element
353     * @throws FSMsgException if there is an error converting
354     *         this object to a string.
355     */
356    public String toXMLString() throws FSMsgException {
357        return this.toXMLString(true, true);
358    }
359    
360    /**
361     * Returns a String representation of the Logout Response.
362     *
363     * @param includeNS : Determines whether or not the namespace qualifier
364     *        is prepended to the Element when converted
365     * @param declareNS : Determines whether or not the namespace is declared
366     *        within the Element.
367     * @return a string containing the valid XML for this element
368     * @throws FSMsgException if there is an error converting
369     *         this object ot a string.
370     */
371    
372    public String toXMLString(boolean includeNS, boolean declareNS)
373    throws FSMsgException {
374        return toXMLString(includeNS, declareNS, false);
375    }
376    
377    public String toXMLString(boolean includeNS,boolean declareNS,
378            boolean includeHeader)  throws FSMsgException {
379        FSUtils.debug.message("FSResponse.toXMLString(3): Called");
380        StringBuffer xml = new StringBuffer(500);
381        if (includeHeader) {
382            xml.append("<?xml version=\"1.0\" encoding=\"").
383                    append(SAMLConstants.DEFAULT_ENCODING).append("\" ?>");
384        }
385        String prefixSAML=null;
386        String prefixLIB=null;
387        String prefixSAML_PROTOCOL = "";
388        String uriSAML_PROTOCOL = "";
389        String uriSAML = "";
390        String uriLIB = "";
391        String uriDS="";
392        String uriXSI="";
393        
394        if (includeNS) {
395            prefixLIB = IFSConstants.LIB_PREFIX;
396            prefixSAML = IFSConstants.ASSERTION_PREFIX;
397            prefixSAML_PROTOCOL = IFSConstants.PROTOCOL_PREFIX;
398        }
399        if (declareNS) {
400            if(minorVersion == IFSConstants.FF_12_SAML_PROTOCOL_MINOR_VERSION){
401                uriLIB = IFSConstants.LIB_12_NAMESPACE_STRING;
402            } else {
403                uriLIB = IFSConstants.LIB_NAMESPACE_STRING;
404            }
405            uriSAML = IFSConstants.assertionDeclareStr;
406            uriSAML_PROTOCOL = IFSConstants.PROTOCOL_NAMESPACE_STRING;
407            uriDS = IFSConstants.DSSAMLNameSpace;
408            uriXSI = IFSConstants.XSI_NAMESPACE_STRING;
409        }
410        
411        String instantString = DateUtils.toUTCDateFormat(issueInstant);
412        
413        if((responseID != null) && (inResponseTo != null)){
414            xml.append("<").append(prefixSAML_PROTOCOL).append("Response").
415                    append(uriLIB).
416                    append(uriSAML).append(uriSAML_PROTOCOL).append(" ").
417                    append(uriDS).
418                    append(" ").append(uriXSI).append(" ResponseID=\"").
419                    append(responseID).append("\" ");
420            if ((inResponseTo != null) && (inResponseTo.length() != 0)) {
421                xml.append(" InResponseTo=\"").append(inResponseTo).
422                        append("\" ");
423            }
424            if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION &&
425                    id != null && !(id.length() == 0)){
426                xml.append(" id=\"").append(id).append("\"");
427            }
428            xml.append(" MajorVersion=\"").
429                    append(majorVersion).append("\" ").
430                    append(" MinorVersion=\"").append(minorVersion).
431                    append("\" ").
432                    append(" IssueInstant=\"").append(instantString).
433                    append("\"");
434            if ((recipient != null) && (recipient.length() != 0)) {
435                xml.append(" Recipient=\"").append(recipient).append("\" ");
436            }
437            xml.append(">");
438        }
439        
440        if (signed) {
441            if (signatureString != null) {
442                xml.append(signatureString);
443            } else if (signature != null) {
444                signatureString = XMLUtils.print(signature);
445                xml.append(signatureString);
446            }
447        }
448        
449        if(status != null)
450            xml.append(status.toString(includeNS, false));
451        
452        if ((assertions != null) && (assertions != Collections.EMPTY_LIST)) {
453            Iterator j = assertions.iterator();
454            while (j.hasNext()) {
455                xml.append(((FSAssertion) j.next()).
456                        toXMLString(true,declareNS));
457            }
458        }
459        
460        xml.append("</").append(prefixSAML_PROTOCOL).append("Response>");
461        return xml.toString();
462    }
463    
464    /**
465     * Returns <code>FSResponse</code> object. The object
466     * is created by parsing an Base64 encoded response string.
467     *
468     * @param encodedRes the encoded response string
469     * @throws FSMsgException if there is an error creating
470     *            <code>FSResponse</code> object.
471     * @throws FSMsgException if there is an error creating
472     *            <code>FSResponse</code> object.
473     */
474    public static FSResponse parseBASE64EncodedString(
475            String encodedRes) throws FSMsgException, SAMLException {
476        FSUtils.debug.message("FSResponse.parseBASE64EncodedString:Called new");
477        if (encodedRes != null) {
478            String decodedAuthnRes = new String(Base64.decode(encodedRes));
479            if (FSUtils.debug.messageEnabled()) {
480                FSUtils.debug.message("FSResponse.parseBASE64EncodedString:"
481                        + "Decoded AuthnResponse message: "
482                        + decodedAuthnRes);
483            }
484            return parseResponseXML(decodedAuthnRes);
485        } else{
486            if (FSUtils.debug.messageEnabled()) {
487                FSUtils.debug.message("FSResponse.parseBASE64EncodedString:"
488                        + "null String passed in as argument.");
489            }
490            throw new FSMsgException("nullInput",null);
491        }
492    }
493    
494    /**
495     * Returns a Base64 Encoded String.
496     *
497     * @return a Base64 Encoded String.
498     * @throws FSMsgException if there is an error encoding the string.
499     */
500    public String toBASE64EncodedString() throws FSMsgException {
501        FSUtils.debug.message("FSResponse.toBASE64EncodedString: Called");
502        if ((responseID == null) || (responseID.length() == 0)){
503            responseID = FSUtils.generateID();
504            if (responseID == null) {
505                FSUtils.debug.error("FSResponse.toBASE64EncodedString: "
506                        + "couldn't generate ResponseID.");
507                throw new FSMsgException("errorGenerateID",null);
508            }
509        }
510        return Base64.encode(this.toXMLString().getBytes());
511    }
512    
513    /**
514     * Signs the Response.
515     *
516     * @param certAlias the Certificate Alias.
517     * @throws XMLSignatureException if <code>FSAuthnRequest</code>
518     *         cannot be signed.
519     */
520    public void signXML(String certAlias) throws SAMLException {
521        FSUtils.debug.message("FSResponse.signXML: Called");
522        if (signed) {
523            if (FSUtils.debug.messageEnabled()) {
524                FSUtils.debug.message("FSResponse.signXML: the assertion is "
525                        + "already signed.");
526            }
527            throw new SAMLResponderException(FSUtils.BUNDLE_NAME,
528                    "alreadySigned",null);
529        }
530        if (certAlias == null || certAlias.length() == 0) {
531            throw new SAMLResponderException(FSUtils.BUNDLE_NAME,
532                    "cannotFindCertAlias",null);
533        }
534        try {
535            XMLSignatureManager manager = XMLSignatureManager.getInstance();
536            if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
537                signatureString = manager.signXML(
538                        this.toXMLString(true, true),
539                        certAlias, IFSConstants.DEF_SIG_ALGO,
540                        IFSConstants.ID,
541                        this.id, false);
542            } else if (minorVersion ==
543                    IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
544                signatureString = manager.signXML(
545                        this.toXMLString(true, true),
546                        certAlias, IFSConstants.DEF_SIG_ALGO,
547                        IFSConstants.RESPONSE_ID,
548                        this.getResponseID(), false);
549            } else {
550                if (FSUtils.debug.messageEnabled()) {
551                    FSUtils.debug.message("invalid minor version.");
552                }
553            }
554            
555            signature =
556                    XMLUtils.toDOMDocument(signatureString, FSUtils.debug)
557                    .getDocumentElement();
558            
559            signed = true;
560            xmlString = this.toXMLString(true, true);
561        } catch(Exception e){
562            throw new SAMLResponderException(FSUtils.BUNDLE_NAME,
563                    "signFailed",null);
564        }
565    }
566    
567    /**
568     * Unsupported operation.
569     */
570    public void signXML() throws SAMLException {
571        throw new SAMLException(FSUtils.BUNDLE_NAME,
572                "unsupportedOperation",null);
573    }
574}




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.