Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/sun/xacml/finder/impl/SelectorModule.java


1   
2   /*
3    * @(#)SelectorModule.java
4    *
5    * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions are met:
9    *
10   *   1. Redistribution of source code must retain the above copyright notice,
11   *      this list of conditions and the following disclaimer.
12   * 
13   *   2. Redistribution in binary form must reproduce the above copyright
14   *      notice, this list of conditions and the following disclaimer in the
15   *      documentation and/or other materials provided with the distribution.
16   *
17   * Neither the name of Sun Microsystems, Inc. or the names of contributors may
18   * be used to endorse or promote products derived from this software without
19   * specific prior written permission.
20   * 
21   * This software is provided "AS IS," without a warranty of any kind. ALL
22   * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
23   * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
24   * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
25   * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
26   * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
27   * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
28   * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
29   * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
30   * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
31   * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32   *
33   * You acknowledge that this software is not designed or intended for use in
34   * the design, construction, operation or maintenance of any nuclear facility.
35   */
36  
37  package com.sun.xacml.finder.impl;
38  
39  import com.sun.xacml.AbstractPolicy;
40  import com.sun.xacml.EvaluationCtx;
41  import com.sun.xacml.ParsingException;
42  import com.sun.xacml.UnknownIdentifierException;
43  
44  import com.sun.xacml.attr.AttributeFactory;
45  import com.sun.xacml.attr.BagAttribute;
46  
47  import com.sun.xacml.cond.EvaluationResult;
48  
49  import com.sun.xacml.ctx.Status;
50  
51  import com.sun.xacml.finder.AttributeFinderModule;
52  
53  import java.net.URI;
54  
55  import java.util.ArrayList;
56  
57  import org.apache.xpath.XPathAPI;
58  
59  import org.w3c.dom.NamedNodeMap;
60  import org.w3c.dom.Node;
61  import org.w3c.dom.NodeList;
62  
63  
64  /**
65   * This module implements the basic behavior of the AttributeSelectorType,
66   * looking for attribute values in the physical request document using the
67   * given XPath expression. This is implemented as a separate module (instead
68   * of being implemented directly in <code>AttributeSelector</code> so that
69   * programmers can remove this functionality if they want (it's optional in
70   * the spec), so they can replace this code with more efficient, specific
71   * code as needed, and so they can easily swap in different XPath libraries.
72   * <p>
73   * Note that if no matches are found, this module will return an empty bag
74   * (unless some error occurred). The <code>AttributeSelector</code> is still
75   * deciding what to return to the policy based on the MustBePresent
76   * attribute.
77   * <p>
78   * This module uses the Xalan XPath implementation, and supports only version
79   * 1.0 of XPath. It is a fully functional, correct implementation of XACML's
80   * AttributeSelector functionality, but is not designed for environments
81   * that make significant use of XPath queries. Developers for any such
82   * environment should consider implementing their own module.
83   *
84   * @since 1.0
85   * @author Seth Proctor
86   */
87  public class SelectorModule extends AttributeFinderModule
88  {
89  
90      /**
91       * Returns true since this module supports retrieving attributes based on
92       * the data provided in an AttributeSelectorType.
93       *
94       * @return true
95       */
96      public boolean isSelectorSupported() {
97          return true;
98      }
99  
100     /**
101      * Private helper to create a new processing error status result
102      */
103     private EvaluationResult createProcessingError(String msg) {
104         ArrayList code = new ArrayList();
105         code.add(Status.STATUS_PROCESSING_ERROR);
106         return new EvaluationResult(new Status(code, msg));
107     }
108 
109     /**
110      * Tries to find attribute values based on the given selector data.
111      * The result, if successful, always contains a <code>BagAttribute</code>,
112      * even if only one value was found. If no values were found, but no other
113      * error occurred, an empty bag is returned.
114      *
115      * @param path the XPath expression to search against
116      * @param namespaceNode the DOM node defining namespace mappings to use,
117      *                      or null if mappings come from the context root
118      * @param type the datatype of the attributes to find
119      * @param context the representation of the request data
120      * @param xpathVersion the XPath version to use
121      *
122      * @return the result of attribute retrieval, which will be a bag of
123      *         attributes or an error
124      */
125     public EvaluationResult findAttribute(String path, Node namespaceNode,
126                                           URI type, EvaluationCtx context,
127                                           String xpathVersion) {
128         // we only support 1.0
129         if (! xpathVersion.equals(AbstractPolicy.XPATH_1_0_VERSION))
130             return new EvaluationResult(BagAttribute.createEmptyBag(type));
131 
132         // get the DOM root of the request document
133         Node root = context.getRequestRoot();
134 
135         // if we were provided with a non-null namespace node, then use it
136         // to resolve namespaces, otherwise use the context root node
137         Node nsNode = (namespaceNode != null) ? namespaceNode : root;
138 
139         // setup the root path (pre-pended to the context path), which...
140         String rootPath = "";
141 
142         // ...only has content if the context path is relative
143         if (path.charAt(0) != '/') {
144             String rootName = root.getLocalName();
145 
146             // see if the request root is in a namespace
147             String namespace = root.getNamespaceURI();
148             
149             if (namespace == null) {
150                 // no namespacing, so we're done
151                 rootPath = "/" + rootName + "/";
152             } else {
153                 // namespaces are used, so we need to lookup the correct
154                 // prefix to use in the search string
155                 NamedNodeMap nmap = namespaceNode.getAttributes();
156                 rootPath = null;
157 
158                 for (int i = 0; i < nmap.getLength(); i++) {
159                     Node n = nmap.item(i);
160                     if (n.getNodeValue().equals(namespace)) {
161                         // we found the matching namespace, so get the prefix
162                         // and then break out
163                         String name = n.getNodeName();
164                         int pos = name.indexOf(':');
165 
166                         if (pos == -1) {
167                             // the namespace was the default namespace
168                             rootPath = "/";
169                         } else {
170                             // we found a prefixed namespace
171                             rootPath = "/" + name.substring(pos + 1);
172                         }
173 
174                         // finish off the string
175                         rootPath += ":" + rootName + "/";
176 
177                         break;
178                     }
179                 }
180 
181                 // if the rootPath is still null, then we don't have any
182                 // definitions for the namespace
183                 if (rootPath == null)
184                     return createProcessingError("Failed to map a namespace" +
185                                                  " in an XPath expression");
186             }
187         }
188 
189         // now do the query, pre-pending the root path to the context path
190         NodeList matches = null;
191         try {
192             // NOTE: see comments in XALAN docs about why this is slow
193             matches = XPathAPI.selectNodeList(root, rootPath + path, nsNode);
194         } catch (Exception e) {
195             // in the case of any exception, we need to return an error
196             return createProcessingError("error in XPath: " + e.getMessage());
197         }
198 
199         if (matches.getLength() == 0) {
200             // we didn't find anything, so we return an empty bag
201             return new EvaluationResult(BagAttribute.createEmptyBag(type));
202         }
203 
204         // there was at least one match, so try to generate the values
205         try {
206             ArrayList list = new ArrayList();
207             AttributeFactory attrFactory = AttributeFactory.getInstance();
208             
209             for (int i = 0; i < matches.getLength(); i++) {
210                 String text = null;
211                 Node node = matches.item(i);
212                 short nodeType = node.getNodeType();
213 
214                 // see if this is straight text, or a node with data under
215                 // it and then get the values accordingly
216                 if ((nodeType == Node.CDATA_SECTION_NODE) ||
217                     (nodeType == Node.COMMENT_NODE) ||
218                     (nodeType == Node.TEXT_NODE) ||
219                     (nodeType == Node.ATTRIBUTE_NODE)) {
220                     // there is no child to this node
221                     text = node.getNodeValue();
222                 } else {
223                     // the data is in a child node
224                     text = node.getFirstChild().getNodeValue();
225                 }
226 
227                 list.add(attrFactory.createValue(type, text));
228             }
229             
230             return new EvaluationResult(new BagAttribute(type, list));
231         } catch (ParsingException pe) {
232             return createProcessingError(pe.getMessage());
233         } catch (UnknownIdentifierException uie) {
234             return createProcessingError("unknown attribute type: " + type);
235         }
236     }
237 
238 }