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: Subject.java,v 1.2 2008/06/25 05:47:33 qcheng Exp $
026 *
027 */
028
029package com.sun.identity.saml.assertion;
030
031import com.sun.identity.saml.common.SAMLUtilsCommon;
032import com.sun.identity.saml.common.SAMLConstants;
033import com.sun.identity.saml.common.SAMLException;
034import com.sun.identity.saml.common.SAMLRequesterException;
035import org.w3c.dom.Element;
036import org.w3c.dom.NodeList;
037import org.w3c.dom.Node;
038
039/**
040 *The <code>Subject</code> element specifies one or more subjects. It contains 
041 *either or both of the following elements: 
042 *<code>NameIdentifier</code>
043 *An identification of a subject by its name and security domain.
044 *<code>SubjectConfirmation</code>
045 *Information that allows the subject to be authenticated.
046 *
047 *If a <code>Subject</code> element contains more than one subject 
048 *specification, the issuer is asserting that the surrounding statement is 
049 *true for all of the subjects specified. For example, if both a 
050 *<code>NameIdentifier</code> and a <code>SubjectConfirmation</code> element 
051 *are present, the issuer is asserting that the statement is true of both  
052 *subjects being identified. A <code>Subject</code> element SHOULD NOT identify
053 *more than one principal.
054 *@supported.all.api 
055 */
056
057
058public class Subject {
059    static SAMLConstants sc;
060    protected SubjectConfirmation _subjectConfirmation;
061    protected NameIdentifier _nameIdentifier;
062
063    /**
064     *Default constructor
065     */
066    protected Subject() {}
067   
068    /** 
069     * Constructs a Subject object from a <code>NameIdentifier</code>
070     * object and a <code>SubjectConfirmation</code> object.
071     *
072     * @param nameIdentifier <code>NameIdentifier</code> object.
073     * @param subjectConfirmation <code>SubjectConfirmation</code> object.
074     * @exception SAMLException if it could not process the 
075     *            Element properly, implying that there is an error in the
076     *            sender or in the element definition.
077     */     
078    public Subject(NameIdentifier nameIdentifier, SubjectConfirmation 
079        subjectConfirmation)  throws SAMLException 
080    {
081        if ((nameIdentifier == null) && (subjectConfirmation == null)) {
082            if (SAMLUtilsCommon.debug.messageEnabled()) {
083                SAMLUtilsCommon.debug.message(
084                    "Subject:  null NameIdentifier and SubjectConfirmation "
085                        + " specified");
086            }
087            throw new SAMLRequesterException(
088                    SAMLUtilsCommon.bundle.getString("nullInput")) ;   
089        }
090        if (nameIdentifier != null) {
091            _nameIdentifier = nameIdentifier;
092        }
093        if (subjectConfirmation != null) {
094            _subjectConfirmation = subjectConfirmation;
095        }
096    }
097
098    /**
099     * Checks for equality between this object and the Subject
100     * passed down as parameter. If <code>NameIdentifier</code> is present,
101     * checks for its equality by calling <code>Nameidentifier.equals()</code>.
102     * if <code>SubjectConfirmation</code> is present calls
103     * <code>equals()</code> method of <code>SubjectConfirmation</code> too
104     * passing in the subject's <code>SubjectConfirmation</code> element.
105     *
106     * @param subject Subject to be checked.
107     * @return true if this object and <code>subject</code> are equals.
108     */
109    public boolean equals(Subject subject) {
110        boolean nidEqual=false;
111        boolean scEqual=false;
112        if (subject != null) { // the ones passed as a parameter is not null
113            NameIdentifier nid = subject.getNameIdentifier();
114            if (_nameIdentifier != null) { // this subject's nid
115                // compare this nid and the passed as parameter one
116                nidEqual = _nameIdentifier.equals(nid);
117            } else  if (nid == null) {
118                nidEqual= true; // passed one is null also stored nid is null
119            }
120            // nid is done so lets see subject confirmation now
121            SubjectConfirmation sc = subject.getSubjectConfirmation();
122            if (_subjectConfirmation != null ) { // this subject's SC
123                scEqual = _subjectConfirmation.equals(sc);
124            } else if (sc == null ) {
125                scEqual= true;
126            }
127            if (!(nidEqual) || !(scEqual)) {
128                return false;
129            }
130            return true; // reached here then they are equal
131        }
132        return false;
133    }     
134                
135    /** 
136     * Constructs a Subject object from a <code>NameIdentifier</code> object.
137     *
138     * @param nameIdentifier <code>NameIdentifier</code> object.
139     * @exception SAMLException if it could not process the <code>Element</code>
140     *            properly, implying that there is an error in the sender or in
141     *            the element definition.
142    */     
143    public Subject(NameIdentifier nameIdentifier)  throws SAMLException { 
144        if (nameIdentifier == null) {
145            if (SAMLUtilsCommon.debug.messageEnabled()) {
146                SAMLUtilsCommon.debug.message("Subject:  null NameIdentifier "
147                    + "specified");
148            }
149            throw new SAMLRequesterException(SAMLUtilsCommon.bundle.getString(
150                "nullInput")) ;   
151        }
152        _nameIdentifier = nameIdentifier;
153    }
154                
155    /** 
156     * Constructs a subject element from an existing XML block
157     * which has already been built into a DOM.
158     *
159     * @param subjectElement An Element representing DOM tree for Subject object
160     * @exception SAMLException if it could not process the Element properly,
161     *            implying that there is an error in the sender or in the 
162     *            element definition.
163     */     
164    public Subject(org.w3c.dom.Element subjectElement)  throws SAMLException {
165        int elementCount=0;
166        Element elt = (Element)subjectElement;
167        String eltName = elt.getLocalName();
168        if (eltName == null)  {
169            if (SAMLUtilsCommon.debug.messageEnabled()) {
170                SAMLUtilsCommon.debug.message("Subject: local name missing");
171            }
172            throw new SAMLRequesterException(SAMLUtilsCommon.bundle.getString
173                ("nullInput")) ;   
174        }
175        if (!(eltName.equals("Subject")))  {
176            if (SAMLUtilsCommon.debug.messageEnabled()) {
177                SAMLUtilsCommon.debug.message("Subject: invalid root element");
178            }
179            throw new SAMLRequesterException(SAMLUtilsCommon.bundle.getString(
180                "invalidElement")) ;   
181        }
182        NodeList nl = subjectElement.getChildNodes();
183        int length = nl.getLength();
184        if (length == 0 ) {
185            if (SAMLUtilsCommon.debug.messageEnabled()) {
186                SAMLUtilsCommon.debug.message("Subject: No sub elements found");
187            }
188            throw new SAMLRequesterException(SAMLUtilsCommon.bundle.getString(
189                "emptyElement")) ;   
190        }
191        // TODO: sequence is not checked as yet
192        for (int n=0; n < length; n++) {
193            Node child = (Node)nl.item(n);
194            if (child.getNodeType() != Node.ELEMENT_NODE) {
195                continue; 
196            }
197            String childName = child.getLocalName();
198            if (childName.equals("NameIdentifier"))  {
199                _nameIdentifier = createNameIdentifier((Element)child);
200                elementCount++;
201            }
202            else if (childName.equals("SubjectConfirmation"))  {
203                _subjectConfirmation = 
204                    createSubjectConfirmation((Element)child);
205                elementCount++;
206            }
207            else {
208                if (SAMLUtilsCommon.debug.messageEnabled()) {
209                    SAMLUtilsCommon.debug.message("Subject: Invalid element "
210                        + "encountered.");
211                }
212                throw new SAMLRequesterException(
213                    SAMLUtilsCommon.bundle.getString("invalidElement")) ;   
214            }
215        }      
216        if (elementCount > 2 ) {
217            if (SAMLUtilsCommon.debug.messageEnabled()) {
218                SAMLUtilsCommon.debug.message("Subject: more than allowed " +
219                    "elements passed");
220            }
221            throw new SAMLRequesterException(SAMLUtilsCommon.bundle.getString(
222                "moreElement")) ;   
223        }
224    }
225
226    /** 
227     * Constructs a Subject object from a <code>SubjectConfirmation</code>
228     * object. 
229     *
230     * @param subjectConfirmation <code>SubjectConfirmation</code> object to
231     *        be added to the object.
232     * @exception SAMLException if <code>subjectConfirmation</code> is null.
233     */     
234    public Subject(SubjectConfirmation subjectConfirmation)   
235        throws SAMLException 
236    {
237        if (subjectConfirmation == null) {
238            if (SAMLUtilsCommon.debug.messageEnabled()) {
239                SAMLUtilsCommon.debug.message("Subject:  null " + 
240                    "SubjectConfirmation specified");
241            }
242            throw new SAMLRequesterException(
243                SAMLUtilsCommon.bundle.getString("nullInput")) ;   
244        }
245        _subjectConfirmation = subjectConfirmation;
246    }
247                 
248    /** 
249     * Sets the subject confirmation to the subject
250     *
251     * @param subjectConfirmation <code>SubjectConfirmation</code> to be set.
252     * @return true if operation succeed.
253     */
254    public boolean setSubjectConfirmation(SubjectConfirmation 
255        subjectConfirmation)  
256    {
257        if (subjectConfirmation == null)  {
258            if (SAMLUtilsCommon.debug.messageEnabled())  {
259                SAMLUtilsCommon.debug.message("Subject:  null " +
260                    "SubjectConfirmation specified");
261            }
262            return false;
263        }
264        _subjectConfirmation = subjectConfirmation;
265        return true;
266    }
267 
268    /** 
269     * Removes subject confirmation from the subject.
270     *
271     * @return true if the operation succeeds.
272    */
273    public boolean removeSubjectConfirmation()  {
274        if (_nameIdentifier == null) {
275            if (SAMLUtilsCommon.debug.messageEnabled())  {
276                SAMLUtilsCommon.debug.message("Subject:At least one of " + 
277                    "NameIdentifier and SubjectConfirmation is mandatory");
278                
279            }
280            return false;
281        }
282        _subjectConfirmation = null;
283        return true;
284    }
285 
286    /** 
287     * Sets the <code>NameIdentifier</code> to the subject.
288     *
289     * @param nameIdentifier <code>NameIdentifier</code> to be set.
290     * @return true if the operation succeeds.
291    */
292    public boolean setNameIdentifier(NameIdentifier 
293        nameIdentifier)  
294    {
295        if (nameIdentifier == null)  {
296            if (SAMLUtilsCommon.debug.messageEnabled())  {
297                SAMLUtilsCommon.debug.message("Subject:  null nameIdentifier "
298                    + "specified");
299            }
300            return false;
301        }
302        _nameIdentifier = nameIdentifier;
303        return true;
304    }
305 
306    /** 
307     * Removes <code>NameIdentifier</code> from the subject.
308     *
309     * @return true if operation succeeds.
310    */
311    public boolean removeNameIdentifier()  {
312        if (_subjectConfirmation == null) {
313            if (SAMLUtilsCommon.debug.messageEnabled())  {
314                SAMLUtilsCommon.debug.message("Subject:At least one of " +
315                    "NameIdentifier and SubjectConfirmation is mandatory");
316                
317            }
318            return false;
319        }
320        _nameIdentifier = null;
321        return true;
322    }
323
324    /**
325     *Gets the <code>NameIdentifier</code> within the Subject element 
326     *@return <code>NameIdentifier</code> object, within this Subject.
327     */
328    public NameIdentifier getNameIdentifier() {
329        return _nameIdentifier;
330    }
331   
332    /**
333     *Gets the <code>SubjectConfirmation</code> within the Subject element 
334     *@return <code>SubjectConfirmation</code> object, within this Subject if 
335     *exists else null
336     */
337    public SubjectConfirmation getSubjectConfirmation() {
338        return _subjectConfirmation;
339    }
340
341    /**
342     * Returns a String representation of the element.
343     *
344     * @return A string containing the valid XML for this element
345     *         By default name space name is prepended to the element name
346     *         example <code>&lt;saml:Subject&gt;</code>
347     */
348    public java.lang.String toString() {
349        // call toString() with includeNS true by default and declareNS false
350        String xml = this.toString(true, false);
351        return xml;
352    }
353
354   
355    /**
356     * Returns a String representation of the <code>&lt;Subject&gt;</code>
357     * element.
358     *
359     * @param includeNS if true prepends all elements by their Namespace 
360     *        name example <code>&lt;saml:Subject&gt;</code>.
361     * @param declareNS if true includes the namespace within the 
362     *        generated XML.
363     * @return A string containing the valid XML for this element.
364     */
365    public java.lang.String toString(boolean includeNS, boolean declareNS) {
366        StringBuffer xml = new StringBuffer(3000);
367        String o = SAMLUtilsCommon.makeStartElementTagXML(
368                    "Subject", includeNS, declareNS);
369        xml.append(o).append(sc.NL);
370        if (_nameIdentifier != null ) {
371            xml.append(_nameIdentifier.toString(includeNS, false));
372            // false above as we dont want to have nested multiple 
373            // declarations of namespace
374        }
375        if (_subjectConfirmation != null)  {
376            xml.append(_subjectConfirmation.toString(includeNS, false));
377        }
378        o = SAMLUtilsCommon.makeEndElementTagXML("Subject",includeNS);
379        xml.append(o);
380        return xml.toString();
381    }       
382
383    protected NameIdentifier
384        createNameIdentifier(Element nameIdentifierElement)
385        throws SAMLException {
386        return new NameIdentifier(nameIdentifierElement);
387    }
388    
389    protected SubjectConfirmation
390        createSubjectConfirmation(Element subjectConfirmationElement)
391        throws SAMLException {
392        return new SubjectConfirmation(subjectConfirmationElement);
393    }
394
395}
396