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




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.