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><saml:Subject></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><Subject></code> 357 * element. 358 * 359 * @param includeNS if true prepends all elements by their Namespace 360 * name example <code><saml:Subject></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