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: AuthenticationStatement.java,v 1.3 2008/06/25 05:47:31 qcheng Exp $
026 *
027 */
028
029
030package com.sun.identity.saml.assertion;
031
032import java.text.*; 
033import java.util.*;
034import org.w3c.dom.*;
035import com.sun.identity.shared.DateUtils;
036import com.sun.identity.saml.common.SAMLUtilsCommon;
037import com.sun.identity.saml.common.SAMLConstants;
038import com.sun.identity.saml.common.SAMLException;
039import com.sun.identity.saml.common.SAMLRequesterException;
040
041/**
042 * The <code>AuthenticationStatement</code> element supplies a 
043 * statement by the issuer that its subject was authenticated by a
044 * particular means at a particular time. The
045 * <code>AuthenticationStatement</code> element is of type 
046 * <code>AuthenticationStatementType</code>, which extends the
047 * <code>SubjectStatementAbstractType</code> with the additional element and
048 * attributes.
049 * @supported.all.api
050 */
051public class AuthenticationStatement extends SubjectStatement {
052    //The AuthenticationMethod attribute specifies the type of Authentication
053    //that took place. 
054    protected String  _authenticationMethod = null;
055    
056    //The AuthenticationInstant attribute specifies the time at which the 
057    //authentication took place.
058    protected Date  _authenticationInstant = null;
059   
060    //The SubjectLocality specifies the DNS domain name and IP address 
061    //for the system entity from which the Subject was apparently authenticated.
062    protected SubjectLocality  _subjectLocality = null ; 
063    
064    //The authority binding specifies the type of authority that performed 
065    //the authentication. 
066    protected List  _authorityBinding = null;  
067    
068    /**
069     *Default constructor
070     */
071    protected AuthenticationStatement() {
072    }
073  
074    /**
075     * Constructs an authentication statement element from an
076     * existing XML block.
077     *
078     * @param element representing a DOM tree element.
079     * @exception SAMLException if there is an error in the sender or in the
080     *            element definition.
081     */
082    public AuthenticationStatement(Element element) throws SAMLException {
083        // make sure input is not null
084        if (element == null) {
085            SAMLUtilsCommon.debug.message(
086                "AuthenticationStatement: null input.");
087            throw new SAMLRequesterException(
088                SAMLUtilsCommon.bundle.getString("nullInput"));
089        }
090        // check if it's an AuthenticationStatement
091        boolean valid = SAMLUtilsCommon.checkStatement(element,
092                            "AuthenticationStatement");
093        if (!valid) {
094            SAMLUtilsCommon.debug.message(
095                "AuthenticationStatement: Wrong input.");
096            throw new SAMLRequesterException(
097                SAMLUtilsCommon.bundle.getString("wrongInput"));
098        }
099
100        int i = 0; 
101        //handle the attributes of AuthenticationStatement 
102        NamedNodeMap atts = ((Node)element).getAttributes(); 
103        int attCount = atts.getLength(); 
104        for (i = 0; i < attCount; i++) {
105            Node att = atts.item(i);
106            if (att.getNodeType() == Node.ATTRIBUTE_NODE) {
107                String attName = att.getLocalName();
108                if (attName == null || attName.length() == 0) {
109                    if (SAMLUtilsCommon.debug.messageEnabled()) {
110                        SAMLUtilsCommon.debug.message(
111                            "AuthenticationStatement:" +
112                            "Attribute name is either null or empty.");
113                    }
114                    continue;
115                    //throw new SAMLRequesterException(
116                      //  SAMLUtilsCommon.bundle.getString("nullInput"));
117                }
118                if (attName.equals("AuthenticationMethod")) {
119                    _authenticationMethod = ((Attr)att).getValue().trim();
120                } else if (attName.equals("AuthenticationInstant")) {
121                    try {
122                        _authenticationInstant =
123                            DateUtils.stringToDate(((Attr)att).getValue());   
124                    } catch (ParseException pe ) {
125                        SAMLUtilsCommon.debug.error(
126                            "AuthenticationStatement:StringToDate", pe);
127                        throw new SAMLRequesterException(
128                            SAMLUtilsCommon.bundle.getString(
129                            "wrongDateFormat"));
130                    } // end of try...catch
131                }
132            }
133        } // end of for loop 
134        //Handle the children elements of AuthenticationStatement  
135        NodeList nodes = element.getChildNodes();
136        int nodeCount = nodes.getLength();
137        if (nodeCount > 0) {
138            for (i = 0; i < nodeCount; i++) {
139                Node currentNode = nodes.item(i);
140                if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
141                    String tagName = currentNode.getLocalName();
142                    String tagNS = currentNode.getNamespaceURI(); 
143                    if ((tagName == null) || tagName.length() == 0 ||
144                        tagNS == null || tagNS.length() == 0) {
145                        if (SAMLUtilsCommon.debug.messageEnabled()) {
146                            SAMLUtilsCommon.debug.message(
147                                "AuthenticationStatement: The" +
148                                " tag name or tag namespace of child" +
149                                " element is either null or empty.");
150                        }
151                        throw new SAMLRequesterException(
152                            SAMLUtilsCommon.bundle.getString("nullInput"));
153                    }
154                    if (tagName.equals("Subject") &&
155                        tagNS.equals(SAMLConstants.assertionSAMLNameSpaceURI)) {
156                        if (this._subject != null) {
157                            if (SAMLUtilsCommon.debug.messageEnabled()) {
158                                SAMLUtilsCommon.debug.message("Authentication" +
159                                   "Statement:should only contain one subject");
160                            }
161                            throw new SAMLRequesterException(
162                                SAMLUtilsCommon.bundle.getString("oneElement"));
163                        } else { 
164                            this._subject =
165                                createSubject((Element)currentNode); 
166                        }
167                    } else if (tagName.equals("SubjectLocality") &&
168                        tagNS.equals(SAMLConstants.assertionSAMLNameSpaceURI)) {
169                        if (_subjectLocality != null) {
170                            if (SAMLUtilsCommon.debug.messageEnabled()) {
171                                SAMLUtilsCommon.debug.message("Authentication"+
172                                            "Statement: should at most " +
173                                            "contain one SubjectLocality.");
174                             }
175                             throw new SAMLRequesterException(
176                                 SAMLUtilsCommon.bundle.getString(
177                                     "oneElement"));        
178                        } else {
179                             _subjectLocality = 
180                                    createSubjectLocality((Element)currentNode);
181                        }
182                    } else if (tagName.equals("AuthorityBinding") &&
183                        tagNS.equals(SAMLConstants.assertionSAMLNameSpaceURI)) {
184                         if (_authorityBinding == null) {
185                             _authorityBinding = new ArrayList(); 
186                         }
187                         if ((_authorityBinding.add(createAuthorityBinding(
188                             (Element)currentNode))) == false) {
189                             if (SAMLUtilsCommon.debug.messageEnabled()) {
190                                 SAMLUtilsCommon.debug.message(
191                                     "Authentication Statment: failed to" +
192                                     " add to the AuthorityBinding list.");
193                             }
194                             throw new SAMLRequesterException(
195                                 SAMLUtilsCommon.bundle.getString(
196                                     "addListError"));   
197                         }
198                    } else {
199                         if (SAMLUtilsCommon.debug.messageEnabled()) {
200                             SAMLUtilsCommon.debug.message(
201                                 "AuthenticationStatement:"+
202                                 "Wrong element " + tagName + "included."); 
203                         }  
204                         throw new SAMLRequesterException(
205                             SAMLUtilsCommon.bundle.getString("wrongInput"));
206                    }
207                } // end of if (currentNode.getNodeType() == Node.ELEMENT_NODE) 
208            } // end of for loop 
209        }  // end of if (nodeCount > 0)
210        
211        // check if the subject is null 
212        if (this._subject == null) {
213            if (SAMLUtilsCommon.debug.messageEnabled()) {
214                SAMLUtilsCommon.debug.message(
215                    "AuthenticationStatement should " +
216                    "contain one subject.");
217            }
218            throw new SAMLRequesterException(
219                        SAMLUtilsCommon.bundle.getString("missingElement"));
220        }
221    }
222    
223    /**
224     * Constructs <code>Authentication statement</code>
225     *
226     * @param authMethod (optional) A String specifies the type of
227     *        authentication that took place. 
228     * @param authInstant (optional) A String specifies the time at which
229     *        the authentication took place.
230     * @param subject (required) A Subject object 
231     * @exception SAMLException if there is an error in the sender.
232     */   
233    public AuthenticationStatement(String authMethod, Date authInstant,
234        Subject subject) throws SAMLException {
235        _authenticationMethod = authMethod;    
236        _authenticationInstant = authInstant; 
237        
238        // check if the subject is null 
239        if (subject == null) {
240            if (SAMLUtilsCommon.debug.messageEnabled()) {
241                SAMLUtilsCommon.debug.message(
242                    "AuthenticationStatement:missing the subject.");
243            }
244            throw new SAMLRequesterException(
245                SAMLUtilsCommon.bundle.getString("missingElement"));
246        } else 
247            this._subject = subject; 
248    }
249          
250    /**
251     * Constructs <code>AuthenticationStatement</code>
252     *
253     * @param authMethod (optional) A String specifies the type of
254     *        authentication that took place. 
255     * @param authInstant (optional) A String specifies the time at which the 
256     *        authentication that took place.
257     * @param subject (required) A Subject object 
258     * @param subjectLocality (optional) A <code>SubjectLocality</code> object.
259     * @param authorityBinding (optional) A List of
260     *        <code>AuthorityBinding</code> objects.
261     * @exception SAMLException if there is an error in the sender.
262     */   
263    public AuthenticationStatement(String authMethod, Date authInstant, 
264        Subject subject, SubjectLocality subjectLocality,
265        List authorityBinding) throws SAMLException {
266        _authenticationMethod = authMethod;    
267        _authenticationInstant = authInstant; 
268        // check if the subject is null 
269        if (subject == null) {
270            if (SAMLUtilsCommon.debug.messageEnabled()) {
271                SAMLUtilsCommon.debug.message(
272                    "AuthenticationStatement: should" +
273                    " contain one subject.");
274            }
275            throw new SAMLRequesterException(
276                SAMLUtilsCommon.bundle.getString("oneElement"));
277        } else {
278            this._subject = subject; 
279        }
280        _subjectLocality = subjectLocality;  
281
282        if (authorityBinding != null && !authorityBinding.isEmpty()) {
283            if (_authorityBinding == null) {
284                _authorityBinding = new ArrayList(); 
285            }
286            _authorityBinding = authorityBinding; 
287        }
288    }      
289  
290    /**
291     * Returns the <code>SubjectLocality</code> from
292     * <code>AuthenticationStatement</code>
293     *
294     * @return The <code>SubjectLocality</code> object within the authentication
295     *         statement.
296     */
297    public SubjectLocality getSubjectLocality() {
298        return _subjectLocality ; 
299    }
300    
301    /**
302     * Sets the <code>SubjectLocality</code> for
303     * <code>AuthenticationStatement</code>.
304     *
305     * @param subjectlocality The <code>SubjectLocality</code> object within
306     *        the <code>AuthenticationStatement</code>.
307     * @return true if the operation is successful.
308     */
309    public boolean setSubjectLocality(SubjectLocality subjectlocality) {
310        if (subjectlocality == null) {
311            if (SAMLUtilsCommon.debug.messageEnabled()) {
312                SAMLUtilsCommon.debug.message("AuthenticationStatement: " +
313                                        "setSubjectLocality:Input is null.");
314            }
315            return false; 
316        }
317        _subjectLocality = subjectlocality ; 
318        return true; 
319    }
320    
321    /**
322     * Returns <code>AuthenticationMethod</code> from authentication statement
323     * @return A String representing the authentication method of the
324     *         authentication statement.
325     */
326    public String getAuthenticaionMethod() {
327        return _authenticationMethod; 
328    }
329    
330    /**
331     * Sets <code>AuthenticationMethod</code> for
332     * <code>AuthenticationStatement</code>.
333     *
334     * @param authenticationmethod input authentication method 
335     * @return true if the operation is successful. Otherwise return false.
336     */
337    public boolean setAuthenticaionMethod(String authenticationmethod) {
338        if (authenticationmethod == null || 
339            authenticationmethod.length() == 0) {
340            if (SAMLUtilsCommon.debug.messageEnabled()) {
341                SAMLUtilsCommon.debug.message("AuthenticationStatement: " +
342                                      "setAuthenticationMethod:Input is null.");
343            }
344            return false; 
345        }
346        _authenticationMethod = authenticationmethod; 
347        return true;  
348    }
349    
350    /**
351     * Returns <code>AuthenticationInstant</code> from authentication statement.
352     * @return The date/time when the authentication statement is created.
353     */
354    public Date getAuthenticationInstant() {
355        return _authenticationInstant;
356    }
357    
358    /**
359     * Sets <code>AuthenticationInstant</code> for
360     * <code>AuthenticationStatement</code>.
361     *
362     * @param authenticationinstant The date/time when the authentication
363     *        statement is created.
364     * @return true if the operation is successful.
365     */
366    public boolean setAuthenticationInstant(Date authenticationinstant) {
367        if (authenticationinstant == null) {
368            if (SAMLUtilsCommon.debug.messageEnabled()) {
369                SAMLUtilsCommon.debug.message("AuthenticationStatement: " +
370                                     "setAuthenticationInstant:Input is null.");
371            }
372            return false; 
373        }
374        _authenticationInstant = authenticationinstant;
375        return true;
376    }
377    
378    /**
379     * Returns the <code>AuthorityBinding</code> from
380     * <code>AuthenticationStatement</code>.
381     *
382     * @return A list of the <code>AuthorityBinding</code> objects
383     */
384    public List getAuthorityBinding() { 
385        return  _authorityBinding; 
386    } 
387    
388    /**
389     * Sets the <code>AuthorityBinding</code> for
390     * <code>AuthenticationStatement</code>.
391     *
392     * @param authoritybinding A list of the <code>AuthorityBinding</code>
393     *        objects.
394     * @return true if the operation is successful.
395     */
396    public boolean setAuthorityBinding(List authoritybinding) { 
397        if (authoritybinding == null || authoritybinding.isEmpty()) {
398            if (SAMLUtilsCommon.debug.messageEnabled()) {
399                SAMLUtilsCommon.debug.message("AuthenticationStatement: " +
400                                        "setAuthorityBinding:Input is null.");
401            }
402            return false; 
403        }
404        _authorityBinding = authoritybinding; 
405        return true;   
406    }
407    
408    /**
409     *Gets the real type of the Statement. 
410     *This method returns Statement.AUTHENTICATION_STATEMENT. 
411     *@return an integer which is Statement.AUTHENTICATION_STATEMENT. 
412     */
413    public int getStatementType() {
414        return Statement.AUTHENTICATION_STATEMENT; 
415    }
416    
417    /** 
418     * Returns a String representation of the Authentication Statement.
419     * 
420     * @return A String representation of the
421     *         <code>&lt;saml:AuthenticationStatement&gt;</code>
422     *         element.
423     */
424    public String toString()  {
425        return (toString(true, false)); 
426    }
427   
428    /** 
429     * Returns a String representation of the
430     * <code>AuthenticationStatement</code>
431     * @param includeNS Determines whether or not the namespace qualifier is 
432     *        prepended  to the Element when converted
433     * @param declareNS Determines whether or not the namespace is declared 
434     *        within the Element.
435     * @return A String representation of the 
436     *         <code>&lt;saml:AuthenticationStatement&gt;</code> element.
437     */                             
438    public  String  toString(boolean includeNS, boolean declareNS)  {
439        StringBuffer result = new StringBuffer(1000);
440        String prefix = "";
441        String uri = "";
442        if (includeNS) {
443            prefix = SAMLConstants.ASSERTION_PREFIX;
444        }
445        if (declareNS) {
446            uri = SAMLConstants.assertionDeclareStr;
447        }
448        result.append("<").append(prefix).append("AuthenticationStatement").
449               append(uri); 
450
451        if (_authenticationMethod != null &&
452            _authenticationMethod.length() != 0){
453            result.append(" AuthenticationMethod=\"").
454                   append(_authenticationMethod).append("\""); 
455        }
456
457        if (_authenticationInstant != null &&
458            _authenticationInstant.toString().length() != 0
459        ) {
460            result.append(" AuthenticationInstant=\"")
461                .append(DateUtils.toUTCDateFormat(_authenticationInstant))
462                .append("\""); 
463        }
464
465        result.append(">\n").append(this._subject.toString(includeNS, false));
466        if (_subjectLocality != null) {
467            result.append(_subjectLocality.toString(includeNS, false));
468        }
469        if (_authorityBinding != null && !_authorityBinding.isEmpty()) {
470                Iterator iter = this.getAuthorityBinding().iterator(); 
471                while (iter.hasNext()) {
472                    AuthorityBinding authBinding= 
473                        (AuthorityBinding)iter.next(); 
474                    result.append(authBinding.toString(includeNS, false)); 
475                }
476        }
477        result.append("</").append(prefix).append("AuthenticationStatement>\n");
478        return(result.toString());
479    }
480
481    protected Subject createSubject(Element subjectElement)
482        throws SAMLException {
483        return new Subject(subjectElement);
484    }
485    
486    protected SubjectLocality createSubjectLocality(
487        Element subjectLocalityElement)
488        throws SAMLException {
489        return new SubjectLocality(subjectLocalityElement);
490    }
491   
492    protected AuthorityBinding createAuthorityBinding(
493        Element authorityBindingElement) throws SAMLException {
494        return new AuthorityBinding(authorityBindingElement);
495    }
496}