/* * @(#)Attribute.java * * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ package com.sun.xacml.ctx; import com.sun.xacml.Indenter; import com.sun.xacml.Constants; import com.sun.xacml.ParsingException; import com.sun.xacml.UnknownIdentifierException; import com.sun.xacml.PolicyMetaData; import com.sun.xacml.attr.AttributeFactory; import com.sun.xacml.attr.AttributeValue; import com.sun.xacml.attr.StandardAttributeFactory; import java.io.PrintStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.util.LinkedList; import java.util.List; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Represents the AttributeType XML type found in the context schema. * * @since 1.0 * @author Seth Proctor */ public class Attribute implements Cloneable { /** * The required attribute id, */ protected URI id; // optional issuer attribute private String issuer = null; // the single value associated with this attribute private AttributeValue value; // the XACML version of this attribute private int xacmlVersion = Constants.XACML_DEFAULT_VERSION; // a switch indicatig whether to include this attribute in the // result status. private boolean includeInResult = false; /** * Creates a new <code>Attribute</code> of the type specified in the * given <code>AttributeValue</code>. * * @param id the id of the attribute * @param issuer the attribute's issuer or null if there is none * @param value the actual value associated with the attribute meta-data, * ` must not be null. */ public Attribute(URI id, String issuer, AttributeValue value) { this(id, issuer, value, Constants.XACML_DEFAULT_VERSION, false); } /** * Creates a new <code>Attribute</code> of the type specified in the * given <code>AttributeValue</code>. * * @param id the id of the attribute * @param issuer the attribute's issuer or null if there is none * @param value the actual value associated with the attribute meta-data, * must not be null. * @param xacmlVersion The XACML version number for compatibility code. */ public Attribute(URI id, String issuer, AttributeValue value, int xacmlVersion) { this(id, issuer, value, xacmlVersion, false); } /** * Creates a new <code>Attribute</code> of the type specified in the * given <code>AttributeValue</code>. * * @param id the id of the attribute * @param issuer the attribute's issuer or null if there is none * @param value the actual value associated with the attribute meta-data, * must not be null. * @param xacmlVersion The XACML version number for compatibility code. * @param includeInResult A switch indicating that this attribute * should be included in the result. */ public Attribute(URI id, String issuer, AttributeValue value, int xacmlVersion, boolean includeInResult) { this.id = id; this.issuer = issuer; this.value = value; this.xacmlVersion = xacmlVersion; this.includeInResult = includeInResult; } /** * The clone method. * * @return a copy if this object. */ public Object clone() { try { Attribute clone = (Attribute)super.clone(); clone.id = this.id; clone.issuer = this.issuer; StandardAttributeFactory fac = StandardAttributeFactory.getFactory(); try { clone.value = fac.createValue(this.value.getType(), this.value.encode()); } catch (UnknownIdentifierException e) { throw new RuntimeException("Impossible exception"); } catch (ParsingException e) { throw new RuntimeException("Impossible exception"); } clone.xacmlVersion = this.xacmlVersion; clone.includeInResult = this.includeInResult; return clone; } catch (CloneNotSupportedException e1) {//this should never happen throw new RuntimeException("Couldn't clone Attribute"); } } /** * Creates an instances of <code>Attribute</code>s based on the root DOM * node of the XML data. This method returns a list of attributes since * the XACML syntax allows multi valued attributes in a single * AttributeType XML type. * * @param root the DOM root of the AttributeType XML type * * @return a list of attributes * *@throws ParsingException if the data is invalid */ public static List<Attribute> getInstances(Node root) throws ParsingException { // check if this really is an attribute if (root.getNodeType() != Node.ELEMENT_NODE || !root.getLocalName().equals("Attribute")) { throw new ParsingException("Can't create an Attribute from a " + root.getLocalName() + " element"); } URI id = null; URI type = null; String issuer = null; boolean includeInResult = false; List<Attribute> result = new LinkedList<Attribute>(); AttributeFactory attrFactory = AttributeFactory.getInstance(); // Now get the xacml version PolicyMetaData metaData = new PolicyMetaData(root.getNamespaceURI(), Constants.XPATH_1_0_IDENTIFIER); NamedNodeMap attrs = root.getAttributes(); try { id = new URI(attrs.getNamedItem("AttributeId").getNodeValue()); } catch (Exception e) { throw new ParsingException("Error parsing required attribute " + "AttributeId in AttributeType", e); } if (metaData.getXACMLVersion() < Constants.XACML_VERSION_3_0) { try { type = new URI(attrs.getNamedItem("DataType").getNodeValue()); } catch (Exception e) { throw new ParsingException("Error parsing required attribute " + "DataType in AttributeType", e); } } try { Node issuerNode = attrs.getNamedItem("Issuer"); if (issuerNode != null) { issuer = issuerNode.getNodeValue(); } } catch (Exception e) { // shouldn't happen, but just in case... throw new ParsingException("Error parsing optional AttributeType" + " attribute", e); } Node includeNode = attrs.getNamedItem("includeInResult"); if (includeNode != null) { if (includeNode.getNodeValue().equals("true")) { includeInResult = true; } else if (includeNode.getNodeValue().equals("false")){ includeInResult = false; } else { throw new ParsingException("Error parsing boolean value" + " includeInResult: " + includeNode.getNodeValue()); } } // now we get the attribute value NodeList nodes = root.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE && node.getLocalName().equals("AttributeValue")) { // get the type if (metaData.getXACMLVersion() > Constants.XACML_VERSION_2_0) { Node typeNode = node.getAttributes() .getNamedItem("DataType"); if (typeNode == null) { throw new ParsingException("No DataType xml-attribute " + "found in AttributeValue"); } String typeStr = typeNode.getNodeValue(); try { type = new URI(typeStr); } catch (Exception e) { throw new ParsingException("Error parsing required " + "attribute DataType in AttributeValue", e); } } // now get the value try { AttributeValue value = attrFactory.createValue(node, type); Attribute attr = new Attribute(id, issuer, value, metaData.getXACMLVersion(), includeInResult); result.add(attr); } catch (UnknownIdentifierException uie) { throw new ParsingException("Unknown DataType", uie); } } } if(result.isEmpty()) throw new ParsingException("Attribute must contain a value"); return result; } /** * Returns the id of this attribute * * @return the attribute id */ public URI getId() { return this.id; } /** * Returns the issuer of this attribute, or null if no issuer was named * * @return the issuer or null */ public String getIssuer() { return this.issuer; } /** * The value of this attribute, or null if no value was included * * @return the attribute's value or null */ public AttributeValue getValue() { return this.value; } /** * Returns the xacml version number for this attribute. * * @return The xacml version number as defined in * <code>PolicyMetaData</code>. */ public int getVersion() { return this.xacmlVersion; } /** * @return True if this attribute should be included in the result. */ public boolean includeInResult() { return this.includeInResult; } /** * Encodes this attribute into its XML representation and writes * this encoding to the given <code>OutputStream</code> with no * indentation. * * @param output a stream into which the XML-encoded data is written * @param charsetName the character set to use in encoding of strings. * This may be null in which case the platform * default character set will be used. * * @throws UnsupportedEncodingException */ public void encode(OutputStream output, String charsetName) throws UnsupportedEncodingException { encode(output, charsetName, new Indenter(0)); } /** * Encodes this attribute into its XML representation and writes * this encoding to the given <code>OutputStream</code> with * indentation. * * @param output a stream into which the XML-encoded data is written * @param charsetName the character set to use in encoding of strings. * This may be null in which case the platform * default character set will be used. * @param indenter an object that creates indentation strings * @throws UnsupportedEncodingException */ public void encode(OutputStream output, String charsetName, Indenter indenter) throws UnsupportedEncodingException { // setup the formatting & outstream stuff PrintStream out; if(charsetName == null) { out = new PrintStream(output); } else { out = new PrintStream(output, false, charsetName); } // write out the encoded form out.println(encode(indenter)); } /** * Encoding method that returns the text-encoded version of * this attribute with formatting. * * @return the text-encoded XML */ public String encode(Indenter indenter) { String indent = indenter.makeString(); indenter.in(); String innerIndent = indenter.makeString(); indenter.out(); String encoded = indent + "<Attribute AttributeId=\"" + this.id.toString() + "\""; if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { encoded += " DataType=\"" + this.value.getType().toString() + "\""; } if (this.issuer != null) { encoded += " Issuer=\"" + this.issuer + "\""; } if (this.xacmlVersion >= Constants.XACML_VERSION_3_0 && this.includeInResult == true) { encoded += " includeInResult=\"true\""; } encoded += ">" + Constants.nl; if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { encoded += innerIndent + this.value.encodeWithTags(false) + Constants.nl + indent + "</Attribute>"; } else { encoded += innerIndent + this.value.encodeWithTags(true) + Constants.nl + indent + "</Attribute>"; } return encoded; } /** * Simple encoding method that returns the text-encoded version of * this attribute with no formatting. * * @return the text-encoded XML */ public String encode() { String encoded = "<Attribute AttributeId=\"" + this.id.toString() + "\""; if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { encoded += " DataType=\"" + this.value.getType().toString() + "\""; } if (this.issuer != null) { encoded += " Issuer=\"" + this.issuer + "\""; } if (this.xacmlVersion >= Constants.XACML_VERSION_3_0 && this.includeInResult == true) { encoded += " includeInResult=\"true\""; } encoded += ">"; if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { encoded += this.value.encodeWithTags(false) + "</Attribute>"; } else { encoded += this.value.encodeWithTags(true) + "</Attribute>"; } return encoded; } }