/* * @(#)FilePolicyModule.java * * Copyright 2003-2006 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.support.finder; import com.sun.xacml.AbstractPolicy; import com.sun.xacml.ConfigurationStore; import com.sun.xacml.EvaluationCtx; import com.sun.xacml.ParsingException; import com.sun.xacml.finder.PolicyFinder; import com.sun.xacml.finder.PolicyFinderModule; import com.sun.xacml.finder.PolicyFinderResult; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * This module represents a collection of files containing polices, * each of which will be searched through when trying to find a * policy that is applicable to a specific request. It does not support * policy references. * <p> * Note that this class used to be provided in the * <code>com.sun.xacml.finder.impl</code> package with a warning that it * would move out of the core packages eventually. This is partly because * this class doesn't represent standard functionality, and partly because * it isn't designed to be generally useful as anything more than an * example. Because so many people have used this class, however, it stayed * in place until the 2.0 release. * <p> * As of the 2.0 release, you may still use this class (in its new location), * but you are encouraged to migrate to the new support modules that are * much richer and designed for general-purpose use. Also, note that the * <code>loadPolicy</code> methods that used to be available from this class * have been removed. That functionality has been replaced by the much more * useful <code>PolicyReader</code> class. If you need to load policies * directly, you should consider that new class. * * @since 1.0 * @author Seth Proctor */ public class FilePolicyModule extends PolicyFinderModule { // the schema file we're using, if any private File schemaFile = null; // the filenames for the files we'll load private Set<String> fileNames; // the actual loaded policies protected PolicyCollection policies; // the logger we'll use for all messages private static final Logger logger = Logger.getLogger(FilePolicyModule.class.getName()); // configuration: keep track of lines when loadig policies (slow! use only for debugging!) protected boolean useLines = false, enf_useLines = false; protected Map<String, String> confParams = new HashMap<String, String>(); protected static final String CONF_PREFIX = "conf:", FILE_PREFIX = "file:", CONF_USELINES = "useLines"; /** * Constructor which retrieves the schema file to validate policies against * from the <code>PolicyReader.POLICY_SCHEMA_PROPERTY</code>. If the * retrieved property is null, then no schema validation will occur. */ public FilePolicyModule() { this.fileNames = new HashSet<String>(); this.policies = new PolicyCollection(); String schemaName = System.getProperty(PolicyReader.POLICY_SCHEMA_PROPERTY); if (schemaName != null) { this.schemaFile = new File(schemaName); } } /** * Constructor that uses the specified <code>File</code> as the schema * file for XML validation. If schema validation is not desired, a null * value should be used. * * @param schemaFile the schema file to validate policies against, * or null if schema validation is not desired. */ public FilePolicyModule(File schemaFile) { this.fileNames = new HashSet<String>(); this.policies = new PolicyCollection(); this.schemaFile = schemaFile; } /** * Constructor that uses the specified <code>String</code> as the schema * file for XML validation. If schema validation is not desired, a null * value should be used. * * @param schemaFile the schema file to validate policies against, * or null if schema validation is not desired. */ public FilePolicyModule(String schemaFile) { this((schemaFile != null) ? new File(schemaFile) : null); } /** * Constructor that specifies a set of initial policy files to use. This * retrieves the schema file to validate policies against from the * <code>PolicyReader.POLICY_SCHEMA_PROPERTY</code>. If the retrieved * property is null, then no schema validation will occur. * * @param fileNames a <code>List</code> of <code>String</code>s that * identify policy files */ public FilePolicyModule(List<String> fileNames) { this(); if (fileNames != null) { for ( String fileName : fileNames ) { if ( fileName.startsWith(CONF_PREFIX) ) { String tmp = fileName.substring(5); try { String confId = tmp.substring(0, tmp.indexOf(":")); String value = tmp.substring(tmp.indexOf(":") + 1); confParams.put(confId, value); } catch(Exception e) { logger.warning("Could not add configuration: " + tmp); } } else { if ( fileName.startsWith(FILE_PREFIX) ) { this.fileNames.add(fileName.substring(5)); } else { this.fileNames.add(fileName); } } } } if ( enf_useLines ) { useLines = true; } else if ( confParams.containsKey(CONF_USELINES)) { useLines = getBool(confParams.get(CONF_USELINES)); } } /** * Constructor that specifies a set of initial policy files to use and * the schema file used to validate the policies. If schema validation is * not desired, a null value should be used. * * @param fileNames a <code>List</code> of <code>String</code>s that * identify policy files * @param schemaFile the schema file to validate policies against, * or null if schema validation is not desired. */ public FilePolicyModule(List<String> fileNames, String schemaFile) { this(schemaFile); if (fileNames != null) { this.fileNames.addAll(fileNames); } } /** * Adds a file (containing a policy) to the collection of filenames * associated with this module. Note that this doesn't actually load the * policy file. Policies aren't loaded from their files until the * module is initialized through the <code>init</code> method (which * is called automatically by the <code>PolicyFinder</code> when the * system comes up). * * @param filename the file to add to this module's collection of files * * @return true or false depending on the success of this operation. */ public boolean addPolicy(String filename) { return this.fileNames.add(filename); } /** * Indicates whether this module supports finding policies based on * a request (target matching). Since this module does support * finding policies based on requests, it returns true. * * @return true, since finding policies based on requests is supported */ public boolean isRequestSupported() { return true; } /** * Initializes the <code>FilePolicyModule</code> by loading * the policies contained in the collection of files associated * with this module. This method also uses the specified * <code>PolicyFinder</code> to help in instantiating PolicySets. * * @param finder a PolicyFinder used to help in instantiating PolicySets */ public void init(PolicyFinder finder) { Object o = finder.getPDPConfiguration().getCustomAttr(ConfigurationStore.BASEDIR); String baseDir = ""; if ( o != null) { baseDir = (String) o; } PolicyReader reader = new PolicyReader(finder, logger, this.schemaFile, this.useLines); for (String fname : this.fileNames ) { try { AbstractPolicy policy = reader.readPolicy(new FileInputStream(baseDir + fname), fname); this.policies.addPolicy(policy); } catch (FileNotFoundException fnfe) { if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, "File couldn't be read: " + fname, fnfe); } } catch (ParsingException pe) { if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, "Error reading policy from file " + fname, pe); } } } } /** * Finds a policy based on a request's context. If more than one * applicable policy is found, this will return an error. Note that * this is basically just a subset of the OnlyOneApplicable Policy * Combining Alg that skips the evaluation step. See comments in there * for details on this algorithm. * * @param context the representation of the request data * * @return the result of trying to find an applicable policy */ public PolicyFinderResult findPolicy(EvaluationCtx context) { try { context.newEvent(this); AbstractPolicy policy = this.policies.getPolicy(context); if (policy == null) { context.closeCurrentEvent(); return new PolicyFinderResult(); } context.closeCurrentEvent(policy.getId().toString()); return new PolicyFinderResult(policy); } catch (TopLevelPolicyException tlpe) { context.closeCurrentEvent(); return new PolicyFinderResult(tlpe.getStatus()); } } protected static boolean getBool(String value) { try { Boolean val = new Boolean(value); return val.booleanValue(); } catch (Exception e) { logger.log(Level.WARNING, "Could not read boolean value " + value + "; Using false as default"); return false; } } /** * this method can be used to enforce the usage of lines parsing * programatically * @param useLines */ public void enforceUseLines() { this.enf_useLines = true; this.useLines = true; } }