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: FSAuthnRequest.java,v 1.4 2008/07/08 06:03:37 exu Exp $
026 *
027 */
028
029package com.sun.identity.federation.message;
030
031import java.util.List;
032import java.util.Date;
033import java.util.Collections;
034import java.util.ArrayList;
035import java.util.Iterator;
036
037import java.io.ByteArrayInputStream;
038import java.io.IOException;
039import java.text.ParseException;
040
041import javax.servlet.http.HttpServletRequest;
042
043import org.w3c.dom.Element;
044import org.w3c.dom.Node;
045import org.w3c.dom.NodeList;
046import org.w3c.dom.Document;
047
048import com.sun.identity.federation.common.FSUtils;
049import com.sun.identity.federation.common.IFSConstants;
050import com.sun.identity.federation.message.common.Extension;
051import com.sun.identity.federation.message.common.FSMsgException;
052import com.sun.identity.federation.message.common.RequestAuthnContext;
053import com.sun.identity.saml.common.SAMLConstants;
054import com.sun.identity.saml.common.SAMLException;
055import com.sun.identity.saml.common.SAMLUtils;
056import com.sun.identity.saml.common.SAMLResponderException;
057import com.sun.identity.saml.protocol.AbstractRequest;
058import com.sun.identity.saml.xmlsig.XMLSignatureManager;
059import com.sun.identity.shared.DateUtils;
060import com.sun.identity.shared.encode.Base64;
061import com.sun.identity.shared.encode.URLEncDec;
062import com.sun.identity.shared.xml.XMLUtils;
063
064/**
065 * The class <code>FSAuthnRequest</code> is used to create , parse
066 * <code>AuthnRequest</code> object.
067 *
068 * @supported.all.api
069 */
070public class FSAuthnRequest extends AbstractRequest {
071    private List extensions = null;
072    private boolean isPassive = false;
073    private boolean forceAuthn = false;
074    private boolean federate = false;
075    private String nameIDPolicy = null;
076    private String protocolProfile = null;
077    private String providerId = null;
078    private RequestAuthnContext authnContext = null;
079    private String relayState = null;
080    protected String xmlString = null;
081    protected String signatureString = null;
082    protected String authContextCompType = null;
083    protected String id = null;
084    protected String assertionConsumerServiceID = null;
085    protected String consentURI = null;
086    protected String affiliationID = null;
087    protected int minorVersion = 0;
088    protected FSScoping scoping = null;
089    private static final String QUERY_STRING_EXTENSION_PREFIX = "AE_";    
090    /**
091     * Default AuthnRequest construtor
092     */
093    public FSAuthnRequest() {
094        setIssueInstant(new Date());
095    }
096    
097    /**
098     * Constructor to create <code>FSAuthnRequest</code> object.
099     *
100     * @param requestId the request identifier.
101     * @param respondWiths List of respond withs attributes.
102     * @param providerID provider id of the requesting provider.
103     * @param forceAuthn Force Authentication boolean value.
104     * @param isPassive attribute for IDP to be passive or active.
105     * @param fed attribute to distingush this request for Federation or SSO
106     * @param nameIDPolicy Name ID Policy for this request, possible values
107     *                     are "none", "onetime", "federated", "any".
108     * @param protocolProf ProtocolProfile used for the SSO.
109     * @param authnCxt Authentication Context used for the SSO.
110     * @param relaySt Relay State i.e. original URL to be redirected after SSO.
111     * @param authContextCompType AuthContext comparison type.
112     * @throws <code>FSMsgException</code> on error.
113     */
114    public FSAuthnRequest(String requestId,
115            List respondWiths,
116            String providerID,
117            boolean forceAuthn,
118            boolean isPassive,
119            boolean fed,
120            String nameIDPolicy,
121            String protocolProf,
122            RequestAuthnContext authnCxt,
123            String relaySt,
124            String authContextCompType)
125            throws FSMsgException {
126        
127        setIssueInstant(new Date());
128        if((respondWiths != null) && (respondWiths != Collections.EMPTY_LIST)) {
129            int length = respondWiths.size();
130            for(int i = 0; i < length; i++) {
131                Object temp = respondWiths.get(i);
132                if(!(temp instanceof String)) {
133                    FSUtils.debug.error("FSAuthnRequest: wrong input for " +
134                            "RespondWith");
135                    throw new FSMsgException("wrongInput", null);
136                }
137            }
138            this.respondWiths = respondWiths;
139        }
140        
141        if ((requestId != null) && (requestId.length() != 0)) {
142            requestID = requestId;
143        } else {
144            // random generate one
145            requestID = SAMLUtils.generateID();
146            if (requestID == null) {
147                FSUtils.debug.error("FSAuthnRequest: couldn't gen RequestID.");
148                throw new FSMsgException("errorGenerateID",null);
149            }
150        }
151        this.isPassive = isPassive;
152        this.forceAuthn = forceAuthn;
153        this.providerId = providerID;
154        this.federate = fed;
155        this.nameIDPolicy = nameIDPolicy;
156        this.protocolProfile = protocolProf;
157        this.relayState = relaySt;
158        this.authnContext = authnCxt;
159        this.authContextCompType = authContextCompType;
160        id = requestID;
161    }
162    
163    /**
164     * Constructor to create <code>FSAuthnRequest</code> object.
165     *
166     * @param root the Document Element object.
167     * @throws <code>FSMsgException</code> on error.
168     */
169    public FSAuthnRequest(Element root) throws FSMsgException {
170        String tag = null;
171        if (root == null) {
172            FSUtils.debug.error("FSAuthnRequest(Element): null input.");
173            throw new FSMsgException("nullInput",null);
174        }
175        if(((tag = root.getLocalName()) == null) ||
176                (!tag.equals(IFSConstants.AUTHN_REQUEST))) {
177            FSUtils.debug.error("FSAuthnRequest(Element): wrong input");
178            throw new FSMsgException("wrongInput",null);
179        }
180        // Attribute IssueInstant
181        String instantString = root.getAttribute(IFSConstants.ISSUE_INSTANT);
182        if ((instantString == null) || (instantString.length() == 0)) {
183            FSUtils.debug.error("FSAuthnRequest(Element): " 
184                                 + "missing IssueInstant");
185            String[] args = { IFSConstants.ISSUE_INSTANT };
186            throw new FSMsgException("missingAttribute",args);
187        } else {
188            try {
189                issueInstant = DateUtils.stringToDate(instantString);
190            } catch (ParseException e) {
191                FSUtils.debug.error("FSAuthnRequest(Element): "
192                 + "could not parse IssueInstant", e);
193                throw new FSMsgException("wrongInput", null);
194            }
195        }
196        // Consent attribute
197        consentURI = root.getAttribute(IFSConstants.CONSENT);
198        
199        id = root.getAttribute(IFSConstants.ID);
200        requestID = root.getAttribute(IFSConstants.AUTH_REQUEST_ID);
201        parseMajorVersion(root.getAttribute(IFSConstants.MAJOR_VERSION));
202        parseMinorVersion(root.getAttribute(IFSConstants.MINOR_VERSION));
203        NodeList contentnl = root.getChildNodes();
204        Node child;
205        String nodeName;
206        int length = contentnl.getLength();
207        for(int i = 0; i < length; i++) {
208            child = contentnl.item(i);
209            if ((nodeName = child.getLocalName()) != null) {
210                if (nodeName.equals(IFSConstants.RESPONDWITH)) {
211                    if (respondWiths == Collections.EMPTY_LIST) {
212                        respondWiths = new ArrayList();
213                    }
214                    respondWiths.add(XMLUtils.getElementValue((Element) child));
215                } else if (nodeName.equals(IFSConstants.PROVIDER_ID)) {
216                    if(providerId != null && providerId.length() != 0) {
217                        FSUtils.debug.error("FSAuthnRequest(Element): should"
218                                + "contain only one ProviderID.");
219                        throw new FSMsgException("wrongInput",null);
220                    }
221                    providerId = XMLUtils.getElementValue((Element) child);
222                } else if(nodeName.equals(IFSConstants.NAMEID_POLICY_ELEMENT)) {
223                    nameIDPolicy=XMLUtils.getElementValue((Element) child);
224                    
225                    if (nameIDPolicy != null &&
226                            (nameIDPolicy.equals(
227                            IFSConstants.NAME_ID_POLICY_FEDERATED) ||
228                            nameIDPolicy.equals(
229                            IFSConstants.NAME_ID_POLICY_ONETIME))
230                            ) {
231                        federate = true;
232                    }
233                } else if (nodeName.equals(IFSConstants.FEDERATE)) {
234                    String strFederate = 
235                             XMLUtils.getElementValue((Element)child);
236                    if(strFederate != null && strFederate.length() != 0 &&
237                            strFederate.equals(IFSConstants.TRUE)
238                                    || strFederate.equals(IFSConstants.ONE)) {
239                        federate = true;
240                    }
241                } else if (nodeName.equals(IFSConstants.IS_PASSIVE_ELEM)) {
242                    String strIsPassive =
243                            XMLUtils.getElementValue((Element) child);
244                    if(strIsPassive != null && strIsPassive.length() != 0 &&
245                            strIsPassive.equals(IFSConstants.TRUE)) {
246                        isPassive = true;
247                    } else {
248                        isPassive = false;
249                    }
250                } else if (nodeName.equals(IFSConstants.FORCE_AUTHN_ELEM)) {
251                    String strForceAuthn =
252                            XMLUtils.getElementValue((Element) child);
253                    if(strForceAuthn != null && strForceAuthn.length() != 0 &&
254                            strForceAuthn.equals(IFSConstants.TRUE)) {
255                        forceAuthn = true;
256                    } else {
257                        forceAuthn = false;
258                    }
259                } else if (nodeName.equals(IFSConstants.PROTOCOL_PROFILE)) {
260                    if(protocolProfile != null 
261                            && protocolProfile.length() != 0) {
262                        FSUtils.debug.error("FSAuthnRequest(Element): "
263                                + "should contain only one ProtocolProfile.");
264                        throw new FSMsgException("wrongInput",null);
265                    }
266                    protocolProfile = XMLUtils.getElementValue((Element) child);
267                    
268                } else if (nodeName.equals(IFSConstants.AUTHN_CONTEXT)) {
269                    authnContext = new RequestAuthnContext((Element) child);
270                    
271                } else if (nodeName.equals(
272                                   IFSConstants.REQUEST_AUTHN_CONTEXT)) {
273                    authnContext = new RequestAuthnContext((Element) child);
274                    
275                } else if (nodeName.equals(IFSConstants.RELAY_STATE)) {
276                    relayState = XMLUtils.getElementValue((Element) child);
277                    
278                } else if (nodeName.equals(
279                                 IFSConstants.AUTHN_CONTEXT_COMPARISON)) {
280                    authContextCompType =
281                            XMLUtils.getElementValue((Element) child);
282                    if(!(authContextCompType.equals(IFSConstants.MINIMUM) ||
283                            authContextCompType.equals(IFSConstants.EXACT) ||
284                            authContextCompType.equals(IFSConstants.MAXIMUM) ||
285                            authContextCompType.equals(IFSConstants.BETTER)) ) {
286                        throw new FSMsgException("wrongInput",null);
287                    }
288                } else if (nodeName.equals(
289                             IFSConstants.ASSERTION_CONSUMER_SVC_ID)) {
290                    assertionConsumerServiceID =
291                            XMLUtils.getElementValue((Element) child);
292                } else if(nodeName.equals(IFSConstants.AFFILIATIONID)) {
293                    affiliationID = XMLUtils.getElementValue((Element) child);
294                } else if(nodeName.equals(IFSConstants.EXTENSION)) {
295                    if (extensions == null) {
296                        extensions = new ArrayList();
297                    }
298                    extensions.add(new Extension((Element)child));
299                } else if(nodeName.equals(IFSConstants.SCOPING)) {
300                    scoping = new FSScoping((Element)child);
301                } else {
302                    FSUtils.debug.error("FSAuthnRequest(Element): invalid"
303                            + " node" + nodeName);
304                    throw new FSMsgException("wrongInput",null);
305                }
306            }
307        }
308        
309        //check for signature
310        List signs = XMLUtils.getElementsByTagNameNS1(root,
311                SAMLConstants.XMLSIG_NAMESPACE_URI,
312                SAMLConstants.XMLSIG_ELEMENT_NAME);
313        int signsSize = signs.size();
314        if (signsSize == 1) {
315            Element elem = (Element)signs.get(0);
316            setSignature(elem);
317            xmlString = XMLUtils.print(root);
318            signed = true;
319        } else if (signsSize != 0) {
320            FSUtils.debug.error("FSAuthnRequest(Element): "
321                    + "included more than one Signature element.");
322            throw new FSMsgException("moreElement",null);
323        }
324        //end check for signature
325    }
326    
327    /**
328     * This method translates the request to an XML document String based on
329     * the Request schema described above.
330     * NOTE: this is a complete AuthnRequest xml string with RequestID,
331     * MajorVersion, etc.
332     *
333     * @return XML String representing the request.
334     * @throws FSMsgException if there is an error.
335     */
336    public String toXMLString() throws FSMsgException {
337        return toXMLString(true, true);
338    }
339    
340    /**
341     * Creates a String representation of the &lt;lib:AuthnRequest&gt; element.
342     *
343     * @param includeNS : Determines whether or not the namespace qualifier
344     *          is prepended to the Element when converted
345     * @param declareNS : Determines whether or not the namespace is declared
346     *          within the Element.
347     * @return string containing the valid XML for this element.
348     * @throws FSMsgException if there is an error.
349     */
350    public String toXMLString(
351            boolean includeNS, boolean declareNS
352            ) throws FSMsgException {
353        return toXMLString(includeNS, declareNS, false);
354    }
355    
356    /**
357     * Creates a String representation of the &lt;lib:AuthnRequest&gt; element.
358     *
359     * @param includeNS  Determines whether or not the namespace qualifier
360     *          is prepended to the Element when converted
361     * @param declareNS Determines whether or not the namespace is declared
362     *          within the Element.
363     * @param includeHeader Determines whether the output include the xml
364     *        declaration header.
365     * @return A string containing the valid XML for this element.
366     * @throws FSMsgException if there is an error.
367     */
368    public String toXMLString(boolean includeNS,
369            boolean declareNS,
370            boolean includeHeader) throws FSMsgException {
371        if (xmlString != null) {
372            return xmlString;
373        }
374        if((providerId == null) || (providerId.length() == 0)){
375            FSUtils.debug.error("FSAuthnRequest.toXMLString: "
376                    + "providerId is null in the request with requestId:"
377                    + requestID);
378            String[] args = { requestID };
379            throw new FSMsgException("nullProviderIdWRequestId",args);
380        }
381        if ((requestID == null) || (requestID.length() == 0)){
382            requestID = SAMLUtils.generateID();
383            if (requestID == null) {
384                FSUtils.debug.error("FSAuthnRequest.toXMLString: "
385                        + "couldn't generate RequestID.");
386                throw new FSMsgException("errorGenerateID",null);
387            }
388        }
389        
390        StringBuffer xml = new StringBuffer(300);
391        if (includeHeader) {
392            xml.append("<?xml version=\"1.0\" encoding=\"").
393                    append(IFSConstants.DEFAULT_ENCODING).append("\" ?>");
394        }
395        String prefix = "";
396        String samlpPrefix = "";
397        String uri = "";
398        String samlpUri = "";
399        if (includeNS) {
400            prefix = IFSConstants.LIB_PREFIX;
401            samlpPrefix = IFSConstants.PROTOCOL_PREFIX;
402        }
403        if (declareNS) {
404            if(minorVersion ==  IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
405                uri = IFSConstants.LIB_12_NAMESPACE_STRING;
406            } else {
407                uri = IFSConstants.LIB_NAMESPACE_STRING;
408            }
409            samlpUri = IFSConstants.PROTOCOL_NAMESPACE_STRING;
410        }
411        
412        String instantString = DateUtils.toUTCDateFormat(issueInstant);
413        
414        if (requestID != null) {
415            xml.append(IFSConstants.LEFT_ANGLE)
416               .append(prefix)
417               .append(IFSConstants.AUTHN_REQUEST)
418               .append(uri)
419               .append(IFSConstants.SPACE)
420               .append(samlpUri);
421 
422            if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION &&
423                    id != null && !(id.length() == 0)){
424                xml.append(IFSConstants.SPACE)
425                   .append(IFSConstants.ID)
426                   .append(IFSConstants.EQUAL_TO)
427                   .append(IFSConstants.QUOTE)
428                   .append(id)
429                   .append(IFSConstants.QUOTE);
430            }
431            xml.append(IFSConstants.SPACE)
432               .append(IFSConstants.REQUEST_ID)
433               .append(IFSConstants.EQUAL_TO)
434               .append(IFSConstants.QUOTE)
435               .append(requestID)
436               .append(IFSConstants.QUOTE)
437               .append(IFSConstants.SPACE)
438               .append(IFSConstants.MAJOR_VERSION)
439               .append(IFSConstants.EQUAL_TO)
440               .append(IFSConstants.QUOTE)
441               .append(majorVersion)
442               .append(IFSConstants.QUOTE)
443               .append(IFSConstants.SPACE)
444               .append(IFSConstants.MINOR_VERSION)
445               .append(IFSConstants.EQUAL_TO)
446               .append(IFSConstants.QUOTE)
447               .append(minorVersion)
448               .append(IFSConstants.QUOTE)
449               .append(IFSConstants.SPACE)
450               .append(IFSConstants.ISSUE_INSTANT)
451               .append(IFSConstants.EQUAL_TO)
452               .append(IFSConstants.QUOTE)
453               .append(instantString)
454               .append(IFSConstants.QUOTE);
455
456            if (consentURI != null) {
457                xml.append(IFSConstants.SPACE) 
458                   .append(IFSConstants.CONSENT)
459                   .append(IFSConstants.EQUAL_TO)
460                   .append(IFSConstants.QUOTE)
461                   .append(consentURI)
462                   .append(IFSConstants.QUOTE);
463            }
464            xml.append(IFSConstants.RIGHT_ANGLE);
465            
466            if((respondWiths != null) &&
467                    (respondWiths != Collections.EMPTY_LIST)) {
468                Iterator i = respondWiths.iterator();
469                while (i.hasNext()) {
470                    xml.append(IFSConstants.LEFT_ANGLE)
471                       .append(samlpPrefix)
472                       .append(IFSConstants.RESPONDWITH)
473                       .append(IFSConstants.RIGHT_ANGLE)
474                       .append((String) i.next())
475                       .append(IFSConstants.START_END_ELEMENT)
476                       .append(samlpPrefix)
477                       .append(IFSConstants.RESPONDWITH)
478                       .append(IFSConstants.RIGHT_ANGLE);
479                }
480            }
481            
482            if (signed) {
483                if (signatureString != null) {
484                    xml.append(signatureString);
485                } else if (signature != null) {
486                    signatureString = XMLUtils.print(signature);
487                    xml.append(signatureString);
488                }
489            }
490
491            if ((extensions != null) && (!extensions.isEmpty())) {
492                for(Iterator iter = extensions.iterator(); iter.hasNext();) {
493                    Extension extension = (Extension)iter.next();
494                    extension.setMinorVersion(minorVersion);
495                    xml.append(extension.toXMLString());
496                }
497
498            }
499
500            xml.append(IFSConstants.LEFT_ANGLE)
501               .append(prefix)
502               .append(IFSConstants.PROVIDER_ID)
503               .append(IFSConstants.RIGHT_ANGLE)
504               .append(providerId)
505               .append(IFSConstants.START_END_ELEMENT)
506               .append(prefix)
507               .append(IFSConstants.PROVIDER_ID)
508               .append(IFSConstants.RIGHT_ANGLE);
509            
510            if (affiliationID != null) {
511                xml.append(IFSConstants.LEFT_ANGLE)
512                   .append(prefix)
513                   .append(IFSConstants.AFFILIATIONID)
514                   .append(IFSConstants.RIGHT_ANGLE)
515                   .append(affiliationID)
516                   .append(IFSConstants.START_END_ELEMENT)
517                   .append(prefix)
518                   .append(IFSConstants.AFFILIATIONID)
519                   .append(IFSConstants.RIGHT_ANGLE);
520            }
521            
522            if (minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
523                String strFederate = IFSConstants.NAME_ID_POLICY_NONE;
524                if (federate) {
525                    strFederate = IFSConstants.NAME_ID_POLICY_FEDERATED;
526                    if (nameIDPolicy != null && nameIDPolicy.length()>0) {
527                        strFederate = nameIDPolicy;
528                    }
529                }
530                xml.append(IFSConstants.LEFT_ANGLE)
531                   .append(prefix)
532                   .append(IFSConstants.NAMEID_POLICY_ELEMENT)
533                   .append(IFSConstants.RIGHT_ANGLE)
534                   .append(strFederate)
535                   .append(IFSConstants.START_END_ELEMENT)
536                   .append(prefix)
537                   .append(IFSConstants.NAMEID_POLICY_ELEMENT)
538                   .append(IFSConstants.RIGHT_ANGLE);
539            } else {
540                String strFederate = IFSConstants.FALSE;
541                if (federate) {
542                    strFederate = IFSConstants.TRUE;
543                }
544                xml.append(IFSConstants.LEFT_ANGLE)
545                   .append(prefix)
546                   .append(IFSConstants.FEDERATE)
547                   .append(IFSConstants.RIGHT_ANGLE)
548                   .append(strFederate)
549                   .append(IFSConstants.START_END_ELEMENT)
550                   .append(prefix)
551                   .append(IFSConstants.FEDERATE)
552                   .append(IFSConstants.RIGHT_ANGLE);
553            }
554            
555            String strForceAuthn = IFSConstants.FALSE;
556            if (forceAuthn) {
557                strForceAuthn = IFSConstants.TRUE;
558            }
559            
560            xml.append(IFSConstants.LEFT_ANGLE)
561               .append(prefix)
562               .append(IFSConstants.FORCE_AUTHN_ELEM)
563               .append(IFSConstants.RIGHT_ANGLE)
564               .append(strForceAuthn)
565               .append(IFSConstants.START_END_ELEMENT)
566               .append(prefix)
567               .append(IFSConstants.FORCE_AUTHN_ELEM)
568               .append(IFSConstants.RIGHT_ANGLE);
569            
570            String strIsPassive = IFSConstants.FALSE;
571            if (isPassive) {
572                strIsPassive = IFSConstants.TRUE;
573            }
574            
575            xml.append(IFSConstants.LEFT_ANGLE)
576               .append(prefix)
577               .append(IFSConstants.IS_PASSIVE_ELEM)
578               .append(IFSConstants.RIGHT_ANGLE)
579               .append(strIsPassive)
580               .append(IFSConstants.START_END_ELEMENT)
581               .append(prefix)
582               .append(IFSConstants.IS_PASSIVE_ELEM)
583               .append(IFSConstants.RIGHT_ANGLE);
584            
585            if(protocolProfile != null && protocolProfile.length() != 0) {
586                xml.append(IFSConstants.LEFT_ANGLE)
587                   .append(prefix)
588                   .append(IFSConstants.PROTOCOL_PROFILE)
589                   .append(IFSConstants.RIGHT_ANGLE)
590                   .append(protocolProfile)
591                   .append(IFSConstants.START_END_ELEMENT)
592                   .append(prefix)
593                   .append(IFSConstants.PROTOCOL_PROFILE)
594                   .append(IFSConstants.RIGHT_ANGLE);
595            }
596            
597            if(assertionConsumerServiceID != null) {
598                xml.append(IFSConstants.LEFT_ANGLE)
599                   .append(prefix)
600                   .append(IFSConstants.ASSERTION_CONSUMER_SVC_ID)
601                   .append(IFSConstants.RIGHT_ANGLE)
602                   .append(assertionConsumerServiceID)
603                   .append(IFSConstants.START_END_ELEMENT)
604                   .append(prefix)
605                   .append(IFSConstants.ASSERTION_CONSUMER_SVC_ID)
606                   .append(IFSConstants.RIGHT_ANGLE);
607            }
608            
609            if(authnContext != null){
610                authnContext.setMinorVersion(minorVersion);
611                xml.append(authnContext.toXMLString());
612            }
613            
614            if(relayState != null && relayState.length() != 0){
615                xml.append(IFSConstants.LEFT_ANGLE)
616                   .append(prefix)
617                   .append(IFSConstants.RELAY_STATE)
618                   .append(IFSConstants.RIGHT_ANGLE)
619                   .append(XMLUtils.escapeSpecialCharacters(relayState))
620                   .append(IFSConstants.START_END_ELEMENT)
621                   .append(prefix)
622                   .append(IFSConstants.RELAY_STATE)
623                   .append(IFSConstants.RIGHT_ANGLE);
624            }
625            
626            if (minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION)  {
627                if (scoping != null) {
628                    xml.append(scoping.toXMLString(true, false));
629                }
630            }
631            
632            if(minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
633                if(authContextCompType != null &&
634                        authContextCompType.length() != 0) {
635                    xml.append(IFSConstants.LEFT_ANGLE)
636                       .append(prefix)
637                       .append(IFSConstants.AUTHN_CONTEXT_COMPARISON)
638                       .append(IFSConstants.RIGHT_ANGLE)
639                       .append(authContextCompType)
640                       .append(IFSConstants.START_END_ELEMENT)
641                       .append(prefix)
642                       .append(IFSConstants.AUTHN_CONTEXT_COMPARISON)
643                       .append(IFSConstants.RIGHT_ANGLE);
644                }
645            }
646            
647            xml.append(IFSConstants.START_END_ELEMENT)
648               .append(prefix)
649               .append(IFSConstants.AUTHN_REQUEST)
650               .append(IFSConstants.RIGHT_ANGLE);
651        } else{
652            FSUtils.debug.error("FSAuthnRequest.toString: requestID is null ");
653            throw new FSMsgException("nullAuthnRequestID",null);
654        }
655        return xml.toString();
656    }
657    
658    /**
659     * Returns the <code>FSAuthnRequest</code> object.
660     *
661     * @param xml the XML string.
662     * @return <code>FSAuthnRequest</code> object.
663     * @throws FSMsgException if there is 
664     *         error creating the object.
665     */
666    public static FSAuthnRequest parseXML(String xml) throws FSMsgException {
667        Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug);
668        if (doc == null) {
669            FSUtils.debug.error("FSAuthnRequest.parseXML:Error "
670                    + "while parsing input xml string");
671            throw new FSMsgException("parseError",null);
672        }
673        Element root = doc.getDocumentElement();
674        return new FSAuthnRequest(root);
675    }
676    
677    /**
678     * Returns Signed XML String representation of this object.
679     *
680     * @return signed XML String.
681     */
682    public String getSignedXMLString(){
683        return xmlString;
684    }
685    
686    /**
687     * Returns the signature string.
688     *
689     * @return the signature string.
690     */
691    public String getSignatureString(){
692        return signatureString;
693    }
694    
695    /**
696     * Returns a list of <code>Extension</code> objects.
697     * Each entry of the list is a <code>Extension</code> object.
698     *
699     * @return a list of <code>Extension</code> elements.
700     * @see #setExtensions(List)
701     */
702    
703    public List getExtensions() {
704        return extensions;
705    }
706    
707    /**
708     * Sets <code>Extension</code> objects.
709     * Each entry of the list is a <code>Extension</code> object.
710     *
711     * @param extensions a list of <code>Extension</code> objects.
712     * @see #getExtensions
713     */
714    public void setExtensions(List extensions) {
715        this.extensions = extensions;
716    }
717
718    /**
719     * Returns the value of Force Authentication attribute.
720     *
721     * @return the value of Force Authentication attribute.
722     */
723    public boolean getForceAuthn() {
724        return forceAuthn;
725    }
726    
727    /**
728     * Sets the value of Force Authentication attribute.
729     *
730     * @param forceAuthn value of Force Authentication attribute.
731     */
732    public void setForceAuthn(boolean forceAuthn) {
733        this.forceAuthn = forceAuthn;
734    }
735    
736    /**
737     * Returns the value of the <code>isPassive</code> attribute.
738     *
739     * @return value of <code>isPassive</code> attribute.
740     */
741    public boolean getIsPassive() {
742        return isPassive;
743    }
744    
745    /**
746     * Sets the value of the <code>IsPassive</code> attribute.
747     *
748     * @param isPassive value of <code>isPassive</code> attribute.
749     */
750    public void setIsPassive(boolean isPassive) {
751        this.isPassive = isPassive;
752    }
753    
754    /**
755     * Returns the value of the <code>Federate</code> attribute.
756     *
757     * @return the value fo the <code>Federate</code> attribute.
758     */
759    public boolean getFederate() {
760        return federate;
761    }
762    
763    /**
764     * Sets the value of the <code>Federate</code> attribute.
765     *
766     * @param fed the value of the <code>Federate</code> attribute.
767     */
768    public void setFederate(boolean fed) {
769        federate = fed;
770    }
771    
772    /**
773     * Returns the <code>NameIDPolicy</code> object.
774     *
775     * @return the <code>NameIDPolicy</code> object.
776     * @see #setNameIDPolicy(String)
777     */
778    
779    public String getNameIDPolicy() {
780        return nameIDPolicy;
781    }
782    
783    /**
784     * Sets the <code>NameIDPolicy</code> object.
785     *
786     * @param nameIDPolicy the new <code>NameIDPolicy</code> object.
787     * @see #getNameIDPolicy
788     */
789    public void setNameIDPolicy(String nameIDPolicy) {
790        this.nameIDPolicy = nameIDPolicy;
791    }
792    
793    /**
794     * Returns the value of <code>ProtocolProfile<code> attribute.
795     *
796     * @return the value of <code>ProtocolProfile<code> attribute.
797     * @see #setProtocolProfile(String)
798     */
799    public String getProtocolProfile() {
800        return protocolProfile;
801    }
802    
803    /**
804     * Sets the value of <code>ProtocolProfile<code> attribute.
805     *
806     * @param protocolProf the value of <code>ProtocolProfile<code> attribute.
807     * @see #getProtocolProfile()
808     */
809    public void setProtocolProfile(String protocolProf) {
810        protocolProfile = protocolProf;
811    }
812    
813    /**
814     * Returns the value of RelayState attribute.
815     *
816     * @return the value of RelayState attribute.
817     * @see #setRelayState(String)
818     */
819    public String getRelayState() {
820        return relayState;
821    }
822    
823    /**
824     * Set the value of RelayState attribute.
825     *
826     * @param relaySt the value of RelayState attribute.
827     * @see #getRelayState()
828     */
829    public void setRelayState(String relaySt) {
830        relayState = relaySt;
831    }
832
833    /**
834     * Returns the <code>RequestedAuthnContext</code> object.
835     *
836     * @return the <code>RequestedAuthnContext</code> object.
837     * @see #setAuthnContext(RequestAuthnContext)
838     */
839    public RequestAuthnContext getAuthnContext() {
840        return authnContext;
841    }
842    
843    /**
844     * Sets the <code>RequestedAuthnContext</code> object.
845     *
846     * @param authnCxt the <code>RequestAuthnContext</code> object.
847     * @see #getAuthnContext()
848     */
849    public void setAuthnContext(RequestAuthnContext authnCxt) {
850        authnContext = authnCxt;
851    }
852    
853    /**
854     * Returns the value of <code>ProviderID</code> attribute.
855     *
856     * @return the value of <code>ProviderID</code> attribute.
857     * @see #setProviderId(String).
858     */
859    public String getProviderId() {
860        return providerId;
861    }
862    
863    /**
864     * Sets the value of <code>ProviderID</code> attribute.
865     *
866     * @param provId the value of <code>ProviderID</code> attribute.
867     * @see #getProviderId()
868     */
869    public void setProviderId(String provId) {
870        providerId = provId;
871    }
872    
873    /**
874     * Returns the value of AuthContext Comparison attribute.
875     *
876     * @return he value of AuthContext Comparison attribute.
877     * @see #setAuthContextCompType(String)
878     */
879    public String getAuthContextCompType() {
880        return authContextCompType;
881    }
882    
883    /**
884     * Sets the value of AuthContext Comparison attribute.
885     *
886     * @param authType he value of AuthContext Comparison attribute.
887     * @see #getAuthContextCompType()
888     */
889    public void setAuthContextCompType(String authType) {
890        authContextCompType = authType;
891    }
892    
893    /**
894     * Returns the value of <code>id</code> attribute.
895     *
896     * @return the value of <code>id</code> attribute.
897     * @see #setID(String)
898     */
899    public String getID() {
900        return id;
901    }
902    
903    /**
904     * Sets the value of <code>id</code> attribute.
905     *
906     * @param id the value of <code>id</code> attribute.
907     * @see #getID()
908     */
909    public void setID(String id) {
910        this.id = id;
911    }
912
913    /**
914     * Returns the value of the <code>MinorVersion</code> attribute.
915     *
916     * @return the value of the <code>MinorVersion</code> attribute.
917     * @see #setMinorVersion(int)
918     */
919    public int getMinorVersion() {
920        return minorVersion;
921    }
922    
923    /**
924     * Sets the value of the <code>MinorVersion</code> attribute.
925     *
926     * @param version the value of the <code>MinorVersion</code> attribute.
927     * @see #getMinorVersion()
928     */
929    public void setMinorVersion(int version) {
930        minorVersion = version;
931    }
932    
933    /**
934     * Returns the Affliation Identifier.
935     *
936     * @return the Affliation Identifier.
937     * @see #setAffiliationID(String)
938     */
939    public String getAffiliationID() {
940        return affiliationID;
941    }
942    
943    /**
944     * Sets the Affiliation Identifier.
945     *
946     * @param affiliationID the Affiliation Identifier.
947     * @see #getAffiliationID()
948     */
949    public void setAffiliationID(String affiliationID) {
950        this.affiliationID = affiliationID;
951    }
952    
953    /**
954     * Returns the Assertion Consumer Service Identifier.
955     *
956     * @return the  Assertion Consumer Service Identifier.
957     * @see #setAssertionConsumerServiceID(String)
958     */
959    public String getAssertionConsumerServiceID() {
960        return assertionConsumerServiceID;
961    }
962    
963    /**
964     * Sets the Assertion Consumer Service Identifier.
965     *
966     * @param assertionConsumerServiceID the Assertion Consumer 
967     *        Service Identifier.
968     * @see #getAssertionConsumerServiceID
969     */
970    public void setAssertionConsumerServiceID(
971                       String assertionConsumerServiceID) {
972        this.assertionConsumerServiceID = assertionConsumerServiceID;
973    }
974    
975    /** 
976     * Returns the value of <code>consent</code> attribute.
977     *
978     * @return the value of <code>consent</code> attribute.
979     * @see #setConsent(String)
980     */
981    public String getConsent() {
982        return consentURI;
983    }
984    
985    /**
986     * Sets the value of <code>consent</code> attribute.
987     *
988     * @param consentURI the value of <code>consent</code> attribute.
989     * @see #getConsent()
990     */
991    public void setConsent(String consentURI) {
992        this.consentURI = consentURI;
993    }
994    
995    /**
996     * Sets the <code>FSScoping</code> object.
997     *
998     * @param scoping the <code>FSScoping</code> object.
999     * @see #getScoping()
1000     */
1001    public void setScoping(FSScoping scoping) {
1002        this.scoping = scoping;
1003    }
1004    
1005    /**
1006     * Returns the <code>FSScoping</code> object.
1007     *
1008     * @return the <code>FSScoping</code> object.
1009     * @see #setScoping(FSScoping)
1010     */
1011    public FSScoping getScoping() {
1012        return scoping;
1013    }
1014    
1015    /**
1016     * Validates the the <code>MajorVersion</code> property in the 
1017     * <code>AuthnRequest</code>.
1018     * 
1019     * @param majorVer the value of <code>MajorVersion</code> property
1020     * @throws FSMsgException if the <code>MajoorVersion</code>
1021     *         is null or is invalid.
1022     */
1023    private void parseMajorVersion(String majorVer) throws FSMsgException {
1024        try {
1025            majorVersion = Integer.parseInt(majorVer);
1026        } catch (NumberFormatException e) {
1027            if (FSUtils.debug.messageEnabled()) {
1028                FSUtils.debug.message("FSAuthnRequest(Element): invalid "
1029                        + "MajorVersion", e);
1030            }
1031            throw new FSMsgException("wrongInput",null);
1032        }
1033        
1034        if (majorVersion != IFSConstants.PROTOCOL_MAJOR_VERSION) {
1035            if (majorVersion > IFSConstants.PROTOCOL_MAJOR_VERSION) {
1036                if (FSUtils.debug.messageEnabled()) {
1037                    FSUtils.debug.message("FSAuthnRequest(Element): "
1038                            + "MajorVersion of the AuthnRequest is too high.");
1039                }
1040                throw new FSMsgException("requestVersionTooHigh",null);
1041            } else {
1042                if (FSUtils.debug.messageEnabled()) {
1043                    FSUtils.debug.message("FSAuthnRequest(Element): "
1044                            + "MajorVersion of the AuthnRequest is too low.");
1045                }
1046                throw new FSMsgException("requestVersionTooLow",null);
1047            }
1048        }
1049        
1050    }
1051    /**
1052     * Validates the the <code>MinorVersion</code> property in the 
1053     * <code>AuthnRequest</code>.
1054     * 
1055     * @param minorVer the value of <code>MinorVersion</code> property
1056     * @throws FSMsgException if the <code>MinorVersion</code>
1057     *         is null or is invalid.
1058     */
1059    private void parseMinorVersion(String minorVer) throws FSMsgException {
1060        try {
1061            minorVersion = Integer.parseInt(minorVer);
1062        } catch (NumberFormatException e) {
1063            if (FSUtils.debug.messageEnabled()) {
1064                FSUtils.debug.message("FSAuthnRequest(Element): invalid "
1065                        + "MinorVersion", e);
1066            }
1067            throw new FSMsgException("wrongInput",null);
1068        }
1069        if(minorVersion > IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
1070            if (FSUtils.debug.messageEnabled()) {
1071                FSUtils.debug.message("FSAuthnRequest.checkMinorVersion:"+
1072                        " Minor Version of the AuthnRequest is too high.");
1073            }
1074            throw new FSMsgException("requestVersionTooHigh",null);
1075        } else if (minorVersion < IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
1076            if (FSUtils.debug.messageEnabled()) {
1077                FSUtils.debug.message("FSAuthnRequest.checkMinorVersion:" +
1078                        " Minor Version of the AuthnRequest is too low.");
1079            }
1080            throw new FSMsgException("requestVersionTooLow",null);
1081        }
1082        
1083    }
1084
1085    /**
1086     * Checks the value of the <code>MajorVersion</code> property
1087     *  in the <code>AuthnRequest</code>.
1088     *
1089     * @param minorVer the value of <code>MajorVersion</code> property
1090     * @return integer value of <code>MajorVersion</code> property
1091     * @throws FSMsgException if the <code>MajorVersion</code>
1092     *         is null or invalid.
1093     */
1094    private static int checkMajorVersion(String majorVer) 
1095                        throws FSMsgException {
1096        int majorVersion;
1097        if (majorVer == null){
1098            throw new FSMsgException("nullMajorVersion",null);
1099        }
1100        try {
1101            majorVersion = Integer.parseInt(majorVer);
1102        } catch (NumberFormatException e) {
1103            if (FSUtils.debug.messageEnabled()) {
1104                FSUtils.debug.message("FSAuthnRequest.checkMajorVersion: "
1105                        + "invalid MajorVersion: " + e.getMessage());
1106            }
1107            throw new FSMsgException("wrongInput",null);
1108        }
1109        
1110        if (majorVersion != SAMLConstants.PROTOCOL_MAJOR_VERSION) {
1111            if (majorVersion > SAMLConstants.PROTOCOL_MAJOR_VERSION) {
1112                if (FSUtils.debug.messageEnabled()) {
1113                    FSUtils.debug.message("FSAuthnRequest.checkMajorVersion: "
1114                            + "MajorVersion of the AuthnRequest is too high"
1115                            + majorVersion);
1116                }
1117                throw new FSMsgException("requestVersionTooHigh",null);
1118            } else {
1119                if (FSUtils.debug.messageEnabled()) {
1120                    FSUtils.debug.message(
1121                            "FSAuthnRequest.checkMajorVersion:MajorVersion of "
1122                            + "the AuthnRequest is too low. " + majorVersion);
1123                }
1124                throw new FSMsgException("requestVersionTooLow",null);
1125            }
1126        }
1127        return majorVersion;
1128    }
1129    
1130    /**
1131     * Checks the value of the <code>MinorVersion</code> property
1132     *  in the <code>AuthnRequest</code>.
1133     *
1134     * @param minorVer the value of <code>MinorVersion</code> property
1135     * @return integer value of <code>MinorVersion</code> property
1136     * @throws FSMsgException if the <code>MinorVersion</code>
1137     *         is null or invalid.
1138     */
1139    private static int checkMinorVersion(String minorVer)
1140    throws FSMsgException {
1141        int minorVersion;
1142        if (minorVer == null){
1143            throw new FSMsgException("nullMinorVersion",null);
1144        }
1145        try {
1146            minorVersion = Integer.parseInt(minorVer);
1147        } catch (NumberFormatException e) {
1148            if (FSUtils.debug.messageEnabled()) {
1149                FSUtils.debug.message("FSAuthnRequest.checkMinorVersion: "
1150                        + "invalid MinorVersion", e);
1151            }
1152            throw new FSMsgException("wrongInput",null);
1153        }
1154        if(minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION ||
1155                minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
1156            return minorVersion;
1157        }
1158        if(minorVersion > IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
1159            if(FSUtils.debug.messageEnabled()) {
1160                FSUtils.debug.message("FSAuthnRequest.checkMinorVersion:"+
1161                        " Minor Version of the AuthnRequest is too high.");
1162            }
1163            throw new FSMsgException("requestVersionTooHigh",null);
1164        } else {
1165            if(FSUtils.debug.messageEnabled()) {
1166                FSUtils.debug.message("FSAuthnRequest.checkMinorVersion:" +
1167                        " Minor Version of the AuthnRequest is too low.");
1168            }
1169            throw new FSMsgException("requestVersionTooLow",null);
1170        }
1171    }
1172    
1173    /**
1174     * Returns an URL Encoded Query String.
1175     *
1176     * @return a url encoded query string.
1177     * @throws FSMsgException if there is an error.
1178     */
1179    public String toURLEncodedQueryString() throws FSMsgException {
1180        if ((providerId == null) || (providerId.length() == 0)) {
1181            FSUtils.debug.error("FSAuthnRequest.toURLEncodedQueryString: "
1182                    + "providerId is null in the request with requestId:"
1183                    + requestID);
1184            String[] args = { requestID }; 
1185            throw new FSMsgException("nullProviderIdWRequestId",args);
1186        }
1187        if ((requestID == null) || (requestID.length() == 0)){
1188            requestID = SAMLUtils.generateID();
1189            if (requestID == null) {
1190                FSUtils.debug.error("FSAuthnRequest.toURLEncodedQueryString: "
1191                        + "couldn't generate RequestID.");
1192                throw new FSMsgException("errorGenerateID",null);
1193            }
1194        }
1195        
1196        StringBuffer urlEncodedAuthnReq = new StringBuffer(300);
1197        
1198        urlEncodedAuthnReq.append(IFSConstants.AUTH_REQUEST_ID)
1199                          .append(IFSConstants.EQUAL_TO)
1200                          .append(URLEncDec.encode(requestID))
1201                          .append(IFSConstants.AMPERSAND)
1202                          .append(IFSConstants.MAJOR_VERSION)
1203                          .append(IFSConstants.EQUAL_TO)
1204                          .append(majorVersion)
1205                          .append(IFSConstants.AMPERSAND)
1206                          .append(IFSConstants.MINOR_VERSION)
1207                          .append(IFSConstants.EQUAL_TO)
1208                          .append(minorVersion)
1209                          .append(IFSConstants.AMPERSAND);
1210        if ((extensions != null) && (!extensions.isEmpty())) {
1211            Extension extension = (Extension)extensions.get(0);
1212            urlEncodedAuthnReq.append(extension.toURLEncodedQueryString(
1213                QUERY_STRING_EXTENSION_PREFIX)).append(IFSConstants.AMPERSAND);
1214
1215            if (extensions.size() > 1) {
1216                if (FSUtils.debug.warningEnabled()) {
1217                    FSUtils.debug.warning(
1218                        "FSAuthnRequest.toURLEncodedQueryString: " +
1219                        "only one Extension element is allowed and extras " +
1220                        " will be removed");
1221                }
1222            }
1223        }
1224
1225        urlEncodedAuthnReq.append(IFSConstants.PROVIDER_ID)
1226                          .append(IFSConstants.EQUAL_TO)
1227                          .append(URLEncDec.encode(providerId))
1228                          .append(IFSConstants.AMPERSAND);
1229
1230        if (consentURI != null) {
1231            urlEncodedAuthnReq.append(IFSConstants.CONSENT)
1232                              .append(IFSConstants.EQUAL_TO)
1233                              .append(URLEncDec.encode(consentURI))
1234                              .append(IFSConstants.AMPERSAND);
1235        }
1236
1237        if(affiliationID != null) {
1238            urlEncodedAuthnReq.append(IFSConstants.AFFILIATIONID)
1239                              .append(IFSConstants.EQUAL_TO)
1240                              .append(URLEncDec.encode(affiliationID))
1241                              .append(IFSConstants.AMPERSAND);
1242        }
1243        
1244        if (issueInstant != null){
1245            urlEncodedAuthnReq.append(IFSConstants.ISSUE_INSTANT)
1246                              .append(IFSConstants.EQUAL_TO)
1247                              .append(URLEncDec.encode(
1248                                  DateUtils.toUTCDateFormat(issueInstant)))
1249                              .append(IFSConstants.AMPERSAND);
1250        } else {
1251            FSUtils.debug.error("FSAuthnRequest.toURLEncodedQueryString: "
1252                    + "issueInstant missing");
1253            String[] args = { IFSConstants.ISSUE_INSTANT };
1254            throw new FSMsgException("missingAttribute",args);
1255        }
1256        
1257        String strForceAuthn = IFSConstants.FALSE;
1258        if (forceAuthn) {
1259            strForceAuthn = IFSConstants.TRUE;
1260        }
1261        
1262        urlEncodedAuthnReq.append(IFSConstants.FORCE_AUTHN_ELEM)
1263                          .append(IFSConstants.EQUAL_TO)
1264                          .append(strForceAuthn)
1265                          .append(IFSConstants.AMPERSAND);
1266        
1267        String strIsPassive =  IFSConstants.FALSE;
1268        if (isPassive) {
1269            strIsPassive = IFSConstants.TRUE;
1270        }
1271   
1272        urlEncodedAuthnReq.append(IFSConstants.IS_PASSIVE_ELEM)
1273                          .append(IFSConstants.EQUAL_TO)
1274                          .append(strIsPassive)
1275                          .append(IFSConstants.AMPERSAND);
1276        
1277        if (minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
1278            String strFederate = IFSConstants.NAME_ID_POLICY_NONE;
1279            if (federate) {
1280                strFederate = IFSConstants.NAME_ID_POLICY_FEDERATED;
1281                if (nameIDPolicy != null && nameIDPolicy.length() > 0) {
1282                    strFederate = nameIDPolicy;
1283                }
1284            }
1285            urlEncodedAuthnReq.append(IFSConstants.NAMEID_POLICY_ELEMENT)
1286                              .append(IFSConstants.EQUAL_TO)
1287                              .append(strFederate)
1288                              .append(IFSConstants.AMPERSAND);
1289        } else {
1290            String strFederate = IFSConstants.FALSE;
1291            if (federate) {
1292                strFederate = IFSConstants.TRUE;
1293            }
1294            urlEncodedAuthnReq.append(IFSConstants.FEDERATE)
1295                              .append(IFSConstants.EQUAL_TO)
1296                              .append(strFederate)
1297                              .append(IFSConstants.AMPERSAND);
1298        }
1299        
1300        if (protocolProfile != null && protocolProfile.length() != 0) {
1301            urlEncodedAuthnReq.append(IFSConstants.PROTOCOL_PROFILE)
1302                              .append(IFSConstants.EQUAL_TO)
1303                              .append(URLEncDec.encode(protocolProfile))
1304                              .append(IFSConstants.AMPERSAND);
1305        }
1306        
1307        if (authnContext != null) {
1308            authnContext.setMinorVersion(minorVersion);
1309            urlEncodedAuthnReq.append(authnContext.toURLEncodedQueryString());
1310        }
1311        
1312        if (relayState != null && relayState.length() != 0) {
1313            urlEncodedAuthnReq.append(IFSConstants.RELAY_STATE)
1314                              .append(IFSConstants.EQUAL_TO)
1315                              .append(URLEncDec.encode(relayState))
1316                              .append(IFSConstants.AMPERSAND);
1317        }
1318        
1319        if (scoping != null) {
1320            urlEncodedAuthnReq.append(scoping.toURLEncodedQueryString());
1321        }
1322        
1323        if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
1324            if (authContextCompType != null 
1325                       && authContextCompType.length() != 0) {
1326                urlEncodedAuthnReq.append(IFSConstants.AUTHN_CONTEXT_COMPARISON)
1327                                  .append(IFSConstants.EQUAL_TO)
1328                                  .append(URLEncDec.encode(authContextCompType))
1329                                  .append(IFSConstants.AMPERSAND);
1330            }
1331        }
1332        
1333        int len = urlEncodedAuthnReq.length() - 1;
1334        if (urlEncodedAuthnReq.charAt(len) == '&') {
1335            urlEncodedAuthnReq = urlEncodedAuthnReq.deleteCharAt(len);
1336        }
1337        
1338        return urlEncodedAuthnReq.toString();
1339    }
1340    
1341    /**
1342     * Returns a Base64 Encoded String.
1343     *
1344     * @return a Base64 Encoded String.
1345     * @throws FSMsgException if there is an error encoding 
1346     *         the string.
1347     */
1348    public String toBASE64EncodedString() throws FSMsgException {
1349        if((providerId == null) || (providerId.length() == 0)){
1350            FSUtils.debug.error("FSAuthnRequest.toBASE64EncodedString: "
1351                    + "providerId is null in the request with requestId:"
1352                    + requestID);
1353            String[] args = { requestID };
1354            throw new FSMsgException("nullProviderIdWRequestId",args);
1355        }
1356        if ((requestID == null) || (requestID.length() == 0)) {
1357            requestID = SAMLUtils.generateID();
1358            if (requestID == null) {
1359                FSUtils.debug.error("FSAuthnRequest.toBASE64EncodedString: "
1360                        + "couldn't generate RequestID.");
1361                throw new FSMsgException("errorGenerateID",null);
1362            }
1363        }
1364        return Base64.encode(this.toXMLString().getBytes());
1365    }
1366    
1367    /**
1368     * Returns <code>FSAuthnRequest</code> object. The
1369     * object is creating by parsing the <code>HttpServletRequest</code>
1370     * object.
1371     *
1372     * @param request the <code>HttpServletRequest</code> object.
1373     * @throws FSMsgException if there is an error
1374     *         creating <code>FSAuthnRequest</code> object.
1375     */
1376    public static FSAuthnRequest parseURLEncodedRequest(
1377                          HttpServletRequest request) throws FSMsgException {
1378        FSAuthnRequest retAuthnRequest = new FSAuthnRequest();
1379        String authReqID = request.getParameter(IFSConstants.AUTH_REQUEST_ID);
1380        if (authReqID == null || authReqID.length() == 0) {
1381            throw new FSMsgException("nullAuthnRequestID",null);
1382        }
1383        retAuthnRequest.requestID = authReqID;
1384        
1385        String instantString = 
1386            request.getParameter(IFSConstants.ISSUE_INSTANT);
1387        if (instantString == null || instantString.length() == 0) {
1388            String[] args = { IFSConstants.ISSUE_INSTANT };
1389            throw new FSMsgException("missingAttribute",args);
1390        }
1391        try{
1392            retAuthnRequest.issueInstant =
1393                    DateUtils.stringToDate(instantString);
1394        } catch (ParseException e){
1395            throw new FSMsgException("parseError",null);
1396        }
1397        
1398        retAuthnRequest.majorVersion =
1399                checkMajorVersion(request.getParameter(
1400                                          IFSConstants.MAJOR_VERSION));
1401        
1402        retAuthnRequest.minorVersion =
1403                checkMinorVersion(request.getParameter(
1404                                          IFSConstants.MINOR_VERSION));
1405        
1406        String providerId = request.getParameter(IFSConstants.PROVIDER_ID);
1407        if (providerId == null || providerId.length() == 0) {
1408            throw new FSMsgException("nullProviderIdInRequest",null);
1409        } else{
1410            FSUtils.debug.message("ProviderID of the sender: " + providerId);
1411            retAuthnRequest.providerId = providerId;
1412        }
1413        
1414        retAuthnRequest.affiliationID = 
1415            request.getParameter(IFSConstants.AFFILIATIONID);
1416        
1417        String forceAuthn = request.getParameter(IFSConstants.FORCE_AUTHN_ELEM);
1418        if ( forceAuthn != null && forceAuthn.length() != 0 
1419             && (forceAuthn.equals(IFSConstants.TRUE) 
1420             || forceAuthn.equals(IFSConstants.ONE))) {
1421            retAuthnRequest.forceAuthn = true;
1422        } else {
1423            retAuthnRequest.forceAuthn = false;
1424        }
1425        
1426        String isPassive = request.getParameter(IFSConstants.IS_PASSIVE_ELEM);
1427        if (isPassive != null && isPassive.length() != 0 &&
1428                (isPassive.equals(IFSConstants.TRUE) ||
1429                isPassive.equals(IFSConstants.ONE))) 
1430        {
1431            retAuthnRequest.isPassive = true;
1432        } else {
1433            retAuthnRequest.isPassive = false;
1434        }
1435
1436        if (retAuthnRequest.minorVersion
1437                == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
1438            String nameIDPolicy = 
1439                request.getParameter(IFSConstants.NAMEID_POLICY_ELEMENT);
1440            
1441            if (nameIDPolicy != null &&
1442                    (nameIDPolicy.equals(
1443                          IFSConstants.NAME_ID_POLICY_FEDERATED) ||
1444                    nameIDPolicy.equals(
1445                          IFSConstants.NAME_ID_POLICY_ONETIME))
1446                    ) {
1447                retAuthnRequest.federate = true;
1448            }
1449            retAuthnRequest.nameIDPolicy = nameIDPolicy;
1450        } else {
1451            String federate = request.getParameter(IFSConstants.FEDERATE);
1452            if (federate != null &&
1453                    federate.length() != 0 &&
1454                    (federate.equals(IFSConstants.TRUE)||
1455                    federate.equals(IFSConstants.ONE))) {
1456                retAuthnRequest.federate = true;
1457            } else {
1458                retAuthnRequest.federate = false;
1459            }
1460        }
1461        
1462        String protocolProfile = 
1463            request.getParameter(IFSConstants.PROTOCOL_PROFILE);
1464        if (protocolProfile != null && protocolProfile.length() != 0) {
1465            retAuthnRequest.protocolProfile = protocolProfile;
1466        }
1467        
1468        String relayState = request.getParameter(IFSConstants.RELAY_STATE);
1469        if(relayState != null && relayState.length() != 0) {
1470            retAuthnRequest.setRelayState(relayState);
1471        }
1472        
1473        String authnContextComparison = 
1474            request.getParameter(IFSConstants.AUTHN_CONTEXT_COMPARISON);
1475        if(authnContextComparison != null && 
1476                          authnContextComparison.length() != 0) {
1477            retAuthnRequest.setAuthContextCompType(authnContextComparison);
1478            String authType = retAuthnRequest.getAuthContextCompType();
1479            if(! (authType.equals(IFSConstants.MINIMUM) ||
1480                    authType.equals(IFSConstants.EXACT) ||
1481                    authType.equals(IFSConstants.MAXIMUM) ||
1482                    authType.equals(IFSConstants.BETTER)) ) {
1483                throw new FSMsgException("wrongInput",null);
1484            }
1485        }
1486        
1487        retAuthnRequest.authnContext =
1488                RequestAuthnContext.parseURLEncodedRequest(
1489                request, retAuthnRequest.getMinorVersion());
1490        
1491        retAuthnRequest.scoping = FSScoping.parseURLEncodedRequest(request);
1492
1493        Extension extension = Extension.parseURLEncodedRequest(request,
1494            QUERY_STRING_EXTENSION_PREFIX, retAuthnRequest.getMinorVersion());
1495        if (extension != null) {
1496            retAuthnRequest.extensions = new ArrayList();
1497            retAuthnRequest.extensions.add(extension);
1498        }
1499
1500        return retAuthnRequest;
1501    }
1502    
1503    /**
1504     * Returns <code>FSAuthnRequest</code> object. The object
1505     * is created by parsing an Base64 encode authentication
1506     * request string.
1507     *
1508     * @param encodedReq the encode string
1509     * @throws FSMsgException if there is an error
1510     *         creating <code>FSAuthnRequest</code> object.
1511     */
1512    public static FSAuthnRequest parseBASE64EncodedString(String encodedReq) 
1513                                     throws FSMsgException {
1514        if (encodedReq != null && encodedReq.length() != 0) {
1515            String decodedAuthnReq = new String(Base64.decode(encodedReq));
1516            if (FSUtils.debug.messageEnabled()) {
1517                FSUtils.debug.message(
1518                    "FSAuthnRequest.parseBASE64EncodedString: "
1519                    + "decoded input string: " + decodedAuthnReq);
1520            }
1521            return parseXML(decodedAuthnReq);
1522        } else{
1523            if (FSUtils.debug.messageEnabled()) {
1524                FSUtils.debug.message(
1525                        "FSAuthnRequest.parseBASE64EncodedString: "
1526                        + "null String passed in as argument.");
1527            }
1528            throw new FSMsgException("nullInput",null);
1529        }
1530    }
1531    
1532    /**
1533     * Signs the Request.
1534     *
1535     * @param certAlias the Certificate Alias.
1536     * @throws XMLSignatureException if <code>FSAuthnRequest</code>
1537     *         cannot be signed.
1538     */
1539
1540    public void signXML(String certAlias) throws SAMLException {
1541        FSUtils.debug.message("FSAuthnRequest.signXML: Called");
1542        if (signed) {
1543            if (FSUtils.debug.messageEnabled()) {
1544                FSUtils.debug.message("FSAuthnRequest.signXML: "
1545                        + "the assertion is "
1546                        + "already signed.");
1547            }
1548            throw new SAMLResponderException(FSUtils.BUNDLE_NAME,
1549                    "alreadySigned",null);
1550        }
1551        if (certAlias == null || certAlias.length() == 0) {
1552            throw new SAMLResponderException(
1553                    FSUtils.BUNDLE_NAME,"cannotFindCertAlias",null);
1554        }
1555        try{
1556            XMLSignatureManager manager = XMLSignatureManager.getInstance();
1557            if (minorVersion == IFSConstants.FF_11_PROTOCOL_MINOR_VERSION) {
1558                signatureString = manager.signXML(this.toXMLString(true, true),
1559                        certAlias, (String) null, IFSConstants.ID,
1560                        this.id, false);
1561            } else if(minorVersion == 
1562                            IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) {
1563                signatureString = 
1564                        manager.signXML(this.toXMLString(true, true),
1565                        certAlias, (String) null, IFSConstants.REQUEST_ID,
1566                        this.getRequestID(), false);
1567            } else {
1568                if (FSUtils.debug.messageEnabled()) {
1569                    FSUtils.debug.message("invalid minor version.");
1570                }
1571            }
1572            
1573            signature =
1574                    XMLUtils.toDOMDocument(signatureString, FSUtils.debug)
1575                    .getDocumentElement();
1576            
1577            signed = true;
1578            xmlString = this.toXMLString(true, true);
1579        } catch(Exception e){
1580            throw new SAMLResponderException(
1581                            FSUtils.BUNDLE_NAME,"signFailed",null);
1582        }
1583    }
1584    
1585    /**
1586     * Unsupported Method.
1587     */
1588    public void signXML() throws SAMLException {
1589        throw new SAMLException(
1590                 FSUtils.BUNDLE_NAME,"unsupportedOperation",null);
1591    }
1592    
1593    /**
1594     * Sets the Signature of the Element passed.
1595     *
1596     * @param elem the Document Element.
1597     * @return true if success otherwise false.
1598     */
1599    public boolean setSignature(Element elem) {
1600        signatureString = XMLUtils.print(elem);
1601        return super.setSignature(elem);
1602    }
1603}