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/FilePolicyModule.java


1   
2   /*
3    * @(#)FilePolicyModule.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.MatchResult;
42  import com.sun.xacml.Policy;
43  import com.sun.xacml.PolicySet;
44  
45  import com.sun.xacml.ctx.Status;
46  
47  import com.sun.xacml.finder.PolicyFinder;
48  import com.sun.xacml.finder.PolicyFinderModule;
49  import com.sun.xacml.finder.PolicyFinderResult;
50  
51  import java.io.File;
52  import java.io.FileInputStream;
53  
54  import java.util.ArrayList;
55  import java.util.HashSet;
56  import java.util.Iterator;
57  import java.util.List;
58  import java.util.Set;
59  
60  import java.util.logging.Level;
61  import java.util.logging.Logger;
62  
63  import javax.xml.parsers.DocumentBuilder;
64  import javax.xml.parsers.DocumentBuilderFactory;
65  
66  import org.w3c.dom.Document;
67  import org.w3c.dom.Element;
68  import org.w3c.dom.NamedNodeMap;
69  import org.w3c.dom.Node;
70  import org.w3c.dom.NodeList;
71  
72  import org.xml.sax.ErrorHandler;
73  import org.xml.sax.SAXException;
74  import org.xml.sax.SAXParseException;
75  
76  
77  /**
78   * This module represents a collection of files containing polices,
79   * each of which will be searched through when trying to find a
80   * policy that is applicable to a specific request.
81   * <p>
82   * Note: this module is provided only as an example and for testing
83   * purposes. It is not part of the standard, and it should not be
84   * relied upon for production systems. In the future, this will likely
85   * be moved into a package with other similar example and testing
86   * code.
87   *
88   * @since 1.0
89   * @author Seth Proctor
90   */
91  public class FilePolicyModule extends PolicyFinderModule
92      implements ErrorHandler
93  {
94  
95      /**
96       * The property which is used to specify the schema
97       * file to validate against (if any)
98       */
99      public static final String POLICY_SCHEMA_PROPERTY =
100         "com.sun.xacml.PolicySchema";
101 
102 
103     public static final String JAXP_SCHEMA_LANGUAGE =
104         "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
105     
106     public static final String W3C_XML_SCHEMA =
107         "http://www.w3.org/2001/XMLSchema";
108 
109     public static final String JAXP_SCHEMA_SOURCE =
110         "http://java.sun.com/xml/jaxp/properties/schemaSource";
111     
112 
113     // the finder that is using this module
114     private PolicyFinder finder;
115 
116     //
117     private File schemaFile;
118 
119     //
120     private Set fileNames;
121 
122     //
123     private Set policies;
124 
125     // the logger we'll use for all messages
126     private static final Logger logger =
127         Logger.getLogger(FilePolicyModule.class.getName());
128 
129     /**
130      * Constructor which retrieves the schema file to validate policies against
131      * from the POLICY_SCHEMA_PROPERTY. If the retrieved property
132      * is null, then no schema validation will occur.
133      */
134     public FilePolicyModule() {
135         fileNames = new HashSet();
136         policies = new HashSet();
137 
138         String schemaName = System.getProperty(POLICY_SCHEMA_PROPERTY);
139 
140         if (schemaName == null)
141             schemaFile = null;
142         else
143             schemaFile = new File(schemaName);
144     }
145 
146     /**
147      * Constructor that uses the specified input as the schema file to
148      * validate policies against. If schema validation is not desired,
149      * a null value should be used.
150      *
151      * @param schemaFile the schema file to validate policies against,
152      *                   or null if schema validation is not desired.
153      */
154     public FilePolicyModule(File schemaFile) {
155         fileNames = new HashSet();
156         policies = new HashSet();
157 
158         this.schemaFile = schemaFile;
159     }
160 
161     /**
162      * Constructor that specifies a set of initial policy files to use.
163      * No schema validation is performed.
164      *
165      * @param fileNames a <code>List</code> of <code>String</code>s that
166      *                  identify policy files
167      */
168     public FilePolicyModule(List fileNames) {
169         this();
170 
171         if (fileNames != null)
172             this.fileNames.addAll(fileNames);
173     }
174 
175     /**
176      * Indicates whether this module supports finding policies based on
177      * a request (target matching). Since this module does support
178      * finding policies based on requests, it returns true.
179      *
180      * @return true, since finding policies based on requests is supported
181      */
182     public boolean isRequestSupported() {
183         return true;
184     }
185 
186     /**
187      * Initializes the <code>FilePolicyModule</code> by loading
188      * the policies contained in the collection of files associated
189      * with this module. This method also uses the specified 
190      * <code>PolicyFinder</code> to help in instantiating PolicySets.
191      *
192      * @param finder a PolicyFinder used to help in instantiating PolicySets
193      */
194     public void init(PolicyFinder finder) {
195         this.finder = finder;
196 
197         Iterator it = fileNames.iterator();
198         while (it.hasNext()) {
199             String fname = (String)(it.next());
200             AbstractPolicy policy = loadPolicy(fname, finder,
201                                                schemaFile, this);
202             if (policy != null)
203                 policies.add(policy);
204         }
205     }
206 
207     /**
208      * Adds a file (containing a policy) to the collection of filenames
209      * associated with this module. 
210      *
211      * @param filename the file to add to this module's collection of files
212      */
213     public boolean addPolicy(String filename) {
214         return fileNames.add(filename);
215     }
216 
217     /**
218      * Loads a policy from the specified filename and uses the specified
219      * <code>PolicyFinder</code> to help with instantiating PolicySets.
220      *
221      * @param filename the file to load the policy from
222      * @param finder a PolicyFinder used to help in instantiating PolicySets
223      *
224      * @return a (potentially schema-validated) policy associated with the 
225      *         specified filename, or null if there was an error
226      */
227     public static AbstractPolicy loadPolicy(String filename,
228                                             PolicyFinder finder) {
229         return loadPolicy(filename, finder, null, null);
230     }
231 
232     /**
233      * Loads a policy from the specified filename, using the specified
234      * <code>PolicyFinder</code> to help with instantiating PolicySets,
235      * and using the specified input as the schema file to validate
236      * policies against. If schema validation is not desired, a null
237      * value should be used for schemaFile
238      * 
239      * @param filename the file to load the policy from
240      * @param finder a PolicyFinder used to help in instantiating PolicySets
241      * @param schemaFile the schema file to validate policies against, or
242      *                   null if schema validation is not desired
243      * @param handler an error handler used to print warnings and errors
244      *                during parsing
245      *
246      * @return a (potentially schema-validated) policy associated with the 
247      *         specified filename, or null if there was an error
248      */
249     public static AbstractPolicy loadPolicy(String filename,
250                                             PolicyFinder finder,
251                                             File schemaFile,
252                                             ErrorHandler handler) {
253         try {
254             // create the factory
255             DocumentBuilderFactory factory =
256                 DocumentBuilderFactory.newInstance();
257             factory.setIgnoringComments(true);
258 
259             DocumentBuilder db = null;
260 
261             // as of 1.2, we always are namespace aware
262             factory.setNamespaceAware(true);
263 
264             // set the factory to work the way the system requires
265             if (schemaFile == null) {
266                 // we're not doing any validation
267                 factory.setValidating(false);
268 
269                 db = factory.newDocumentBuilder();
270             } else {
271                 // we're using a validating parser
272                 factory.setValidating(true);
273 
274                 factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
275                 factory.setAttribute(JAXP_SCHEMA_SOURCE, schemaFile);
276                 
277                 db = factory.newDocumentBuilder();
278                 db.setErrorHandler(handler);
279             }
280 
281             // try to load the policy file
282             Document doc = db.parse(new FileInputStream(filename));
283             
284             // handle the policy, if it's a known type
285             Element root = doc.getDocumentElement();
286             String name = root.getTagName();
287 
288             if (name.equals("Policy")) {
289                 return Policy.getInstance(root);
290             } else if (name.equals("PolicySet")) {
291                 return PolicySet.getInstance(root, finder);
292             } else {
293                 // this isn't a root type that we know how to handle
294                 throw new Exception("Unknown root document type: " + name);
295             }
296 
297         } catch (Exception e) {
298             if (logger.isLoggable(Level.WARNING))
299                 logger.log(Level.WARNING, "Error reading policy from file " +
300                            filename, e);
301         }
302 
303         // a default fall-through in the case of an error
304         return null;
305     }
306 
307     /**
308      * Finds a policy based on a request's context. This may involve using
309      * the request data as indexing data to lookup a policy. This will always
310      * do a Target match to make sure that the given policy applies. If more
311      * than one applicable policy is found, this will return an error.
312      * NOTE: this is basically just a subset of the OnlyOneApplicable Policy
313      * Combining Alg that skips the evaluation step. See comments in there
314      * for details on this algorithm.
315      *
316      * @param context the representation of the request data
317      *
318      * @return the result of trying to find an applicable policy
319      */
320     public PolicyFinderResult findPolicy(EvaluationCtx context) {
321         AbstractPolicy selectedPolicy = null;
322         Iterator it = policies.iterator();
323 
324         while (it.hasNext()) {
325             AbstractPolicy policy = (AbstractPolicy)(it.next());
326 
327             // see if we match
328             MatchResult match = policy.match(context);
329             int result = match.getResult();
330             
331             // if there was an error, we stop right away
332             if (result == MatchResult.INDETERMINATE)
333                 return new PolicyFinderResult(match.getStatus());
334 
335             if (result == MatchResult.MATCH) {
336                 // if we matched before, this is an error...
337                 if (selectedPolicy != null) {
338                     ArrayList code = new ArrayList();
339                     code.add(Status.STATUS_PROCESSING_ERROR);
340                     Status status = new Status(code, "too many applicable top-"
341                                                + "level policies");
342                     return new PolicyFinderResult(status);
343                 }
344 
345                 // ...otherwise remember this policy
346                 selectedPolicy = policy;
347             }
348         }
349 
350         // if we found a policy, return it, otherwise we're N/A
351         if (selectedPolicy != null)
352             return new PolicyFinderResult(selectedPolicy);
353         else
354             return new PolicyFinderResult();
355     }
356 
357     /**
358      * Standard handler routine for the XML parsing.
359      *
360      * @param exception information on what caused the problem
361      */
362     public void warning(SAXParseException exception) throws SAXException {
363         if (logger.isLoggable(Level.WARNING))
364             logger.warning("Warning on line " + exception.getLineNumber() +
365                            ": " + exception.getMessage());
366     }
367 
368     /**
369      * Standard handler routine for the XML parsing.
370      *
371      * @param exception information on what caused the problem
372      *
373      * @throws SAXException always to halt parsing on errors
374      */
375     public void error(SAXParseException exception) throws SAXException {
376         if (logger.isLoggable(Level.WARNING))
377             logger.warning("Error on line " + exception.getLineNumber() +
378                            ": " + exception.getMessage() + " ... " +
379                            "Policy will not be available");
380 
381         throw new SAXException("error parsing policy");
382     }
383 
384     /**
385      * Standard handler routine for the XML parsing.
386      *
387      * @param exception information on what caused the problem
388      *
389      * @throws SAXException always to halt parsing on errors
390      */
391     public void fatalError(SAXParseException exception) throws SAXException {
392         if (logger.isLoggable(Level.WARNING))
393             logger.warning("Fatal error on line " + exception.getLineNumber() +
394                            ": " + exception.getMessage() + " ... " +
395                            "Policy will not be available");
396 
397         throw new SAXException("fatal error parsing policy");
398     }
399 
400 }