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

Quick Search    Search Deep

Source code: com/sun/xacml/Rule.java


1   
2   /*
3    * @(#)Rule.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;
38  
39  import com.sun.xacml.attr.BooleanAttribute;
40  
41  import com.sun.xacml.cond.Apply;
42  import com.sun.xacml.cond.EvaluationResult;
43  
44  import com.sun.xacml.ctx.Result;
45  import com.sun.xacml.ctx.Status;
46  
47  import java.io.OutputStream;
48  import java.io.PrintStream;
49  
50  import java.net.URI;
51  import java.net.URISyntaxException;
52  
53  import java.util.ArrayList;
54  import java.util.Collections;
55  import java.util.List;
56  
57  import org.w3c.dom.NamedNodeMap;
58  import org.w3c.dom.Node;
59  import org.w3c.dom.NodeList;
60  
61  
62  /**
63   * Represents the RuleType XACML type. This has a target for matching, and
64   * encapsulates the condition and all sub-operations that make up the heart
65   * of most policies.
66   *
67   * @since 1.0
68   * @author Seth Proctor
69   */
70  public class Rule implements PolicyTreeElement
71  {
72  
73      // the attributes associated with this Rule
74      private URI idAttr;
75      private int effectAttr;
76  
77      // the elements in the rule, each of which is optional
78      private String description = null;
79      private Target target = null;
80      private Apply condition = null;
81  
82      /**
83       * Creates a new <code>Rule</code> object.
84       *
85       * @param id the rule's identifier
86       * @param effect the effect to return if the rule applies (either
87       *               Pemit or Deny) as specified in <code>Result</code>
88       * @param description a textual description, or null
89       * @param target the rule's target, or null if the target is to be
90       *               inherited from the encompassing policy
91       * @param condition the rule's condition, or null if there is none
92       */
93      public Rule(URI id, int effect, String description,  Target target,
94                  Apply condition) {
95          idAttr = id;
96          effectAttr = effect;
97          this.description = description;
98          this.target = target;
99          this.condition = condition;
100     }
101 
102     /**
103      * Returns a new instance of the <code>Rule</code> class based on a
104      * DOM node. The node must be the root of an XML RuleType.
105      *
106      * @param root the DOM root of a RuleType XML type
107      * @param xpathVersion the XPath version to use in any selectors or XPath
108      *                     functions, or null if this is unspecified (ie, not
109      *                     supplied in the defaults section of the policy)
110      *
111      * @throws ParsingException if the RuleType is invalid
112      */
113     public static Rule getInstance(Node root, String xpathVersion)
114         throws ParsingException
115     {
116         URI id = null;
117         String name = null;
118         int effect = 0;
119         String description = null;
120         Target target = null;
121         Apply condition = null;
122 
123         // first, get the attributes
124         NamedNodeMap attrs = root.getAttributes();
125 
126         try {
127             // get the two required attrs...
128             id = new URI(attrs.getNamedItem("RuleId").getNodeValue());
129         } catch (URISyntaxException use) {
130             throw new ParsingException("Error parsing required attribute " +
131                                        "RuleId", use);
132         }
133 
134         String str = attrs.getNamedItem("Effect").getNodeValue();
135         if (str.equals("Permit")) {
136             effect = Result.DECISION_PERMIT;
137         } else if (str.equals("Deny")) {
138             effect = Result.DECISION_DENY;
139         } else {
140             throw new ParsingException("Invalid Effect: " + effect);
141         }
142 
143         // next, get the elements
144         NodeList children = root.getChildNodes();
145         for (int i = 0; i < children.getLength(); i++) {
146             Node child = children.item(i);
147             String cname = child.getNodeName();
148 
149             if (cname.equals("Description")) {
150                 description = child.getFirstChild().getNodeValue();
151             } else if (cname.equals("Target")) {
152                 target = Target.getInstance(child, xpathVersion);
153             } else if (cname.equals("Condition")) {
154                 condition = Apply.getConditionInstance(child, xpathVersion);
155             }
156         }
157 
158         return new Rule(id, effect, description, target, condition);
159     }
160 
161     /**
162      * Returns the effect that this <code>Rule</code> will return from
163      * the evaluate method (Permit or Deny) if the request applies.
164      *
165      * @return a decision effect, as defined in <code>Result</code>
166      */
167     public int getEffect() {
168         return effectAttr;
169     }
170 
171     /**
172      * Returns the id of this <code>Rule</code>
173      *
174      * @return the rule id
175      */
176     public URI getId() {
177         return idAttr;
178     }
179 
180     /**
181      * Returns the given description of this <code>Rule</code> or null if 
182      * there is no description
183      *
184      * @return the description or null
185      */
186     public String getDescription() {
187         return description;
188     }
189 
190     /**
191      * Returns the target for this <code>Rule</code> or null if there
192      * is no target
193      *
194      * @return the rule's target
195      */
196     public Target getTarget() {
197         return target;
198     }
199 
200     /**
201      * Since a rule is always a leaf in a policy tree because it can have
202      * no children, this always returns an empty <code>List</code>.
203      *
204      * @return a <code>List</code> with no elements
205      */
206     public List getChildren() {
207         return Collections.EMPTY_LIST;
208     }
209 
210     /**
211      * Returns the condition for this <code>Rule</code> or null if there
212      * is no condition
213      *
214      * @return the rule's condition
215      */
216     public Apply getCondition() {
217         return condition;
218     }
219 
220     /**
221      * Given the input context sees whether or not the request matches this
222      * <code>Rule</code>'s <code>Target</code>. Note that unlike the matching
223      * done by the <code>evaluate</code> method, if the <code>Target</code>
224      * is missing than this will return Indeterminate. This lets you write
225      * your own custom matching routines for rules but lets evaluation
226      * proceed normally.
227      *
228      * @param context the representation of the request
229      *
230      * @return the result of trying to match this rule and the request
231      */
232     public MatchResult match(EvaluationCtx context) {
233         if (target == null) {
234             ArrayList code = new ArrayList();
235             code.add(Status.STATUS_PROCESSING_ERROR);
236             Status status = new Status(code, "no target available for " +
237                                        "matching a rule");
238 
239             return new MatchResult(MatchResult.INDETERMINATE, status);
240         }
241 
242         return target.match(context);
243     }
244 
245     /**
246      * Evaluates the rule against the supplied context. This will check that
247      * the target matches, and then try to evaluate the condition. If the
248      * target and condition apply, then the rule's effect is returned in
249      * the result.
250      * <p>
251      * Note that rules are not required to have targets. If no target is
252      * specified, then the rule inherits its parent's target. In the event
253      * that this <code>Rule</code> has no <code>Target</code> then the
254      * match is assumed to be true, since evaluating a policy tree to this
255      * level required the parent's target to match.
256      *
257      * @param context the representation of the request we're evaluating
258      *
259      * @return the result of the evaluation
260      */
261     public Result evaluate(EvaluationCtx context) {
262         // If the Target is null then it's supposed to inherit from the
263         // parent policy, so we skip the matching step assuming we wouldn't
264         // be here unless the parent matched
265         if (target != null) {
266             MatchResult match = target.match(context);
267             int result = match.getResult();
268 
269             // if the target didn't match, then this Rule doesn't apply
270             if (result == MatchResult.NO_MATCH)
271                 return new Result(Result.DECISION_NOT_APPLICABLE,
272                                   context.getResourceId().encode());
273 
274             // if the target was indeterminate, we can't go on
275             if (result == MatchResult.INDETERMINATE)
276                 return new Result(Result.DECISION_INDETERMINATE,
277                                   match.getStatus(),
278                                   context.getResourceId().encode());
279         }
280 
281         // if there's no condition, then we just return the effect...
282         if (condition == null)
283             return new Result(effectAttr, context.getResourceId().encode());
284 
285         // ...otherwise we evaluate the condition
286         EvaluationResult result = condition.evaluate(context);
287         
288         if (result.indeterminate()) {
289             // if it was INDETERMINATE, then that's what we return
290             return new Result(Result.DECISION_INDETERMINATE,
291                               result.getStatus(),
292                               context.getResourceId().encode());
293         } else {
294             // otherwise we return the effect on tue, and NA on false
295             BooleanAttribute bool =
296                 (BooleanAttribute)(result.getAttributeValue());
297 
298             if (bool.getValue())
299                 return new Result(effectAttr,
300                                   context.getResourceId().encode());
301             else
302                 return new Result(Result.DECISION_NOT_APPLICABLE,
303                                   context.getResourceId().encode());
304         }
305     }
306 
307     /**
308      * Encodes this <code>Rule</code> into its XML representation and writes
309      * this encoding to the given <code>OutputStream</code> with no
310      * indentation.
311      *
312      * @param output a stream into which the XML-encoded data is written
313      */
314     public void encode(OutputStream output) {
315         encode(output, new Indenter(0));
316     }
317 
318     /**
319      * Encodes this <code>Rule</code> into its XML representation and writes
320      * this encoding to the given <code>OutputStream</code> with
321      * indentation.
322      *
323      * @param output a stream into which the XML-encoded data is written
324      * @param indenter an object that creates indentation strings
325      */
326     public void encode(OutputStream output, Indenter indenter) {
327         PrintStream out = new PrintStream(output);
328         String indent = indenter.makeString();
329 
330         out.print(indent + "<Rule RuleId=\"" + idAttr.toString() +
331                   "\" Effect=\"" + Result.DECISIONS[effectAttr] + "\"");
332 
333         if ((description != null) || (target != null) || (condition != null)) {
334             // there is some content in the Rule
335             out.println(">");
336 
337             indenter.in();
338             String nextIndent = indenter.makeString();
339             
340             if (description != null)
341                 out.println(nextIndent + "<Description>" + description +
342                             "</Description>");
343             
344             if (target != null)
345                 target.encode(output, indenter);
346             
347             if (condition != null)
348                 condition.encode(output, indenter);
349 
350             indenter.out();
351             out.println(indent + "</Rule>");
352         } else {
353             // the Rule is empty, so close the tag and we're done
354             out.println("/>");
355         }
356     }
357 
358 }