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: SubjectImpl.java,v 1.3 2008/06/25 05:48:13 qcheng Exp $ 026 * 027 */ 028 029package com.sun.identity.xacml.context.impl; 030 031import com.sun.identity.shared.xml.XMLUtils; 032import com.sun.identity.xacml.common.XACMLConstants; 033import com.sun.identity.xacml.common.XACMLException; 034import com.sun.identity.xacml.common.XACMLSDKUtils; 035import com.sun.identity.xacml.context.Attribute; 036import com.sun.identity.xacml.context.ContextFactory; 037import com.sun.identity.xacml.context.Subject; 038 039import java.util.List; 040import java.net.URI; 041import java.util.ArrayList; 042import org.w3c.dom.Document; 043import org.w3c.dom.Element; 044import org.w3c.dom.Node; 045import org.w3c.dom.NodeList; 046 047/** 048 * The <code>Subject</code> element specifies information about a 049 * subject of the <code>Request</code> context by listing a 050 * sequence of <code>Attribute</code> elements associated with the 051 * subject. A subject is an entity associated with the access request. 052 * <p> 053 * <pre> 054 * <xs:complexType name="SubjectType"> 055 * <xs:sequence> 056 * <xs:element ref="xacml-context:Attribute" minOccurs="0" 057 * maxOccurs="unbounded"/> 058 * <xs:sequence> 059 * <xs:attribute name="SubjectCategory" type="xs:anyURI" 060 * default="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"/> 061 * <xs:complexType> 062 * </pre> 063 *@supported.all.api 064 */ 065public class SubjectImpl implements Subject { 066 private List attributes ; 067 private URI subjectCategory; 068 private Attribute subjectCategoryAttribute; 069 private boolean isMutable = true; 070 private boolean needToCreateSubjectCategory = false; 071 072 /** 073 * Default constructor 074 */ 075 public SubjectImpl() { 076 } 077 078 /** 079 * This constructor is used to build <code>Subject</code> object from a 080 * XML string. 081 * 082 * @param xml A <code>java.lang.String</code> representing 083 * a <code>Subject</code> object 084 * @exception XACMLException if it could not process the XML string 085 */ 086 public SubjectImpl(String xml) throws XACMLException { 087 Document document = XMLUtils.toDOMDocument(xml, XACMLSDKUtils.debug); 088 if (document != null) { 089 Element rootElement = document.getDocumentElement(); 090 processElement(rootElement); 091 makeImmutable(); 092 } else { 093 XACMLSDKUtils.debug.error( 094 "SubjectImpl.processElement(): invalid XML input"); 095 throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString( 096 "errorObtainingElement")); 097 } 098 } 099 100 /** 101 * This constructor is used to build <code>Subject</code> object from a 102 * block of existing XML that has already been built into a DOM. 103 * 104 * @param element A <code>org.w3c.dom.Element</code> representing 105 * DOM tree for <code>Subject</code> object 106 * @exception XACMLException if it could not process the Element 107 */ 108 public SubjectImpl(Element element) throws XACMLException { 109 processElement(element); 110 makeImmutable(); 111 } 112 113 private void processElement(Element element) throws XACMLException { 114 if (element == null) { 115 XACMLSDKUtils.debug.error( 116 "SubjectImpl.processElement(): invalid root element"); 117 throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString( 118 "invalid_element")); 119 } 120 String elemName = element.getLocalName(); 121 if (elemName == null) { 122 XACMLSDKUtils.debug.error( 123 "SubjectImpl.processElement(): local name missing"); 124 throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString( 125 "missing_local_name")); 126 } 127 128 if (!elemName.equals(XACMLConstants.SUBJECT)) { 129 XACMLSDKUtils.debug.error( 130 "SubjectImpl.processElement(): invalid local name " + 131 elemName); 132 throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString( 133 "invalid_local_name")); 134 } 135 // starts processing subelements 136 NodeList nodes = element.getChildNodes(); 137 int numOfNodes = nodes.getLength(); 138 if (numOfNodes >= 1) { 139 ContextFactory factory = ContextFactory.getInstance(); 140 for (int nextElem = 0; nextElem < numOfNodes; nextElem++) { 141 Node child = (Node)nodes.item(nextElem); 142 if ((child.getNodeType() == Node.ELEMENT_NODE) || 143 (child.getNodeType() == Node.ATTRIBUTE_NODE )) { 144 // The child nodes should be <Attribute> 145 // or <SubjectCategory> 146 String attrChildName = child.getLocalName(); 147 if (attrChildName.equals(XACMLConstants.ATTRIBUTE)) { 148 if (this.attributes == null) { 149 this.attributes = new ArrayList(); 150 } 151 Attribute attribute = factory.getInstance(). 152 createAttribute((Element)child); 153 attributes.add(attribute); 154 } else if (attrChildName.equals( 155 XACMLConstants.SUBJECT_CATEGORY)) { 156 try { 157 subjectCategory = new URI (child.getNodeValue()); 158 } catch ( Exception e) { 159 throw new XACMLException( 160 XACMLSDKUtils.xacmlResourceBundle.getString( 161 "attribute_not_uri")); 162 } 163 } else { 164 XACMLSDKUtils.debug.error("RequestImpl." 165 +"processElement(): Invalid element :" 166 +attrChildName); 167 throw new XACMLException( 168 XACMLSDKUtils.xacmlResourceBundle.getString( 169 "invalid_element")); 170 } 171 } 172 } 173 } 174 } 175 /** 176 * Returns zero to many <code>Attribute</code> elements of this object 177 * If no attributes and present, empty <code>List</code> will be returned. 178 * Typically a <code>Subject</code> element will contain an <code> 179 * Attribute</code> with an <code>AttributeId</code> of 180 * "urn:oasis:names:tc:xacml:1.0:subject:subject-id", containing 181 * the identity of the <code>Subject</code> 182 * 183 * @return the <code>Attribute</code> elements of this object 184 */ 185 public List getAttributes() { 186 return attributes; 187 } 188 189 /** 190 * Sets the <code>Attribute</code> elements of this object 191 * 192 * @param attributes <code>Attribute</code> elements of this object 193 * attributes could be an empty <code>List</code>, if no attributes 194 * are present. 195 * 196 * @exception XACMLException if the object is immutable 197 * An object is considered <code>immutable</code> if <code> 198 * makeImmutable()</code> has been invoked on it. It can 199 * be determined by calling <code>isMutable</code> on the object. 200 */ 201 public void setAttributes(List attributes) throws XACMLException { 202 if (!isMutable) { 203 throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString( 204 "objectImmutable")); 205 } 206 if (attributes != null && !attributes.isEmpty()) { 207 if (this.attributes == null) { 208 this.attributes = new ArrayList(); 209 } 210 this.attributes.addAll(attributes); 211 } 212 } 213 214 /** 215 * Returns the <code>SubjectCategory</code> of this object. 216 * This is optional so could be null if not defined. 217 * This attribute indicates the role that the parent <code>Subject</code> 218 * played in the formation of the access request. If this attribute is not 219 * present in the <code>Subject</code> element, then the 220 * default value of 221 * urn:oasis:names:tc:xacml:1.0:subject-category:access-subject SHALL be 222 * used, indicating that the <code>Subject</code> represents the entity 223 * ultimately responsible for initiating the access request. 224 * 225 * @return <code>URI</code> representing the 226 * <code>SubjectCategory</code> of this object. 227 */ 228 public URI getSubjectCategory() { 229 try { 230 if (subjectCategory == null) { 231 subjectCategory = new URI(XACMLConstants.ACCESS_SUBJECT); 232 } 233 } catch (Exception e) { // cant do anything, return null 234 } 235 return subjectCategory; 236 } 237 238 /** 239 * Sets the <code>SubjectCategory</code> of this object 240 * 241 * @param subjectCategory <code>URI</code> 242 * 243 * @exception XACMLException if the object is immutable 244 * An object is considered <code>immutable</code> if <code> 245 * makeImmutable()</code> has been invoked on it. It can 246 * be determined by calling <code>isMutable</code> on the object. 247 */ 248 public void setSubjectCategory(URI subjectCategory) throws 249 XACMLException 250 { 251 if (!isMutable) { 252 throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString( 253 "objectImmutable")); 254 } 255 if (subjectCategory != null) { 256 this.subjectCategory = subjectCategory; 257 } /*else { 258 needToCreateSubjectCategory = true; 259 try { 260 subjectCategory = new URI(SUBJECT_CATEGORY_DEFAULT); 261 List values = new ArrayList(); 262 values.add(subjectCategory.toString()); 263 subjectCategoryAttribute = 264 XACMLSDKUtils.createAttribute(values, new URI( 265 SUBJECT_CATEGORY_ID), new URI(URI_DATATYPE), null); 266 } catch ( Exception e) { 267 throw new XACMLException(e); 268 } 269 }*/ 270 } 271 272 /** 273 * Returns a <code>String</code> representation of this object 274 * @param includeNSPrefix Determines whether or not the namespace qualifier 275 * is prepended to the Element when converted 276 * @param declareNS Determines whether or not the namespace is declared 277 * within the Element. 278 * @return a string representation of this object 279 * @exception XACMLException if conversion fails for any reason 280 */ 281 public String toXMLString(boolean includeNSPrefix, boolean declareNS) 282 throws XACMLException 283 { 284 StringBuffer sb = new StringBuffer(2000); 285 StringBuffer NS = new StringBuffer(100); 286 287 //TODO: remove the 2 following line 288 includeNSPrefix = false; 289 declareNS = false; 290 291 String appendNS = ""; 292 if (declareNS) { 293 NS.append(XACMLConstants.CONTEXT_NS_DECLARATION) 294 .append(XACMLConstants.SPACE); 295 NS.append(XACMLConstants.XSI_NS_URI) 296 .append(XACMLConstants.SPACE) 297 .append(XACMLConstants.CONTEXT_SCHEMA_LOCATION); 298 } 299 if (includeNSPrefix) { 300 appendNS = XACMLConstants.CONTEXT_NS_PREFIX + ":"; 301 } 302 sb.append("<").append(appendNS).append(XACMLConstants.SUBJECT) 303 .append(NS); 304 if (subjectCategory != null) { 305 sb.append(" ").append(XACMLConstants.SUBJECT_CATEGORY).append("="); 306 sb.append("\"").append(subjectCategory.toString()).append("\""); 307 } 308 sb.append(">"); 309 int length = 0; 310 if (attributes != null) { 311 sb.append("\n"); 312 length = attributes.size(); 313 for (int i = 0; i < length; i++) { 314 Attribute attr = (Attribute)attributes.get(i); 315 sb.append(attr.toXMLString(includeNSPrefix, false)); 316 } 317 } 318 /* if (needToCreateSubjectCategory && subjectCategoryAttribute != null) { 319 sb.append(subjectCategoryAttribute.toXMLString( 320 includeNSPrefix, false)); 321 }// its already covered in the previous list of attrs. 322 */ 323 sb.append("</").append(appendNS).append(XACMLConstants.SUBJECT); 324 sb.append(">\n"); 325 return sb.toString(); 326 } 327 328 /** 329 * Returns a string representation of this object 330 * 331 * @return a string representation of this object 332 * @exception XACMLException if conversion fails for any reason 333 */ 334 public String toXMLString() throws XACMLException { 335 return toXMLString(true, false); 336 } 337 338 /** 339 * Makes the object immutable 340 */ 341 public void makeImmutable() {} 342 343 /** 344 * Checks if the object is mutable 345 * 346 * @return <code>true</code> if the object is mutable, 347 * <code>false</code> otherwise 348 */ 349 public boolean isMutable() { 350 return isMutable; 351 } 352 353}