/* Copyright 2012-2015 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.aniketos.securebpmn.xacml.support.finder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.log4j.Logger;
import com.sun.xacml.AbstractPolicy;
import com.sun.xacml.ConfigurationStore;
import com.sun.xacml.EvaluationCtx;
import com.sun.xacml.MatchResult;
import com.sun.xacml.ParsingException;
import com.sun.xacml.PolicyMetaData;
import com.sun.xacml.VersionConstraints;
import com.sun.xacml.ctx.Result;
import com.sun.xacml.ctx.Status;
import com.sun.xacml.finder.PolicyFinder;
import com.sun.xacml.finder.PolicyFinderModule;
import com.sun.xacml.finder.PolicyFinderResult;
import com.sun.xacml.support.finder.PolicyReader;
/**
*
* PolicyFinderModule which allows to load policies by filename and folder
* <br/>
* When searching for policies, only main (entry) policies are searched,
* i.e., only policies with an "main" at the end are loaded
*
*/
public class FilePolicyModule extends PolicyFinderModule {
private File schemaFile;
// the filenames for the files we'll load
private Set<String> fileNames;
private Set<String> folders;
private Map<URI, AbstractPolicy> policies;
private Map<URI, AbstractPolicy> mainPolicies;
private static final Logger logger = Logger.getLogger(FilePolicyModule.class);
// 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:",
FOLDER_PREFIX = "folder:",
FILE_PREFIX = "file:",
CONF_USELINES = "useLines";
public FilePolicyModule() {
fileNames = new HashSet<String>();
folders = new HashSet<String>();
policies = new HashMap<URI, AbstractPolicy>();
mainPolicies = new HashMap<URI, AbstractPolicy>();
String schemaName =
System.getProperty(PolicyReader.POLICY_SCHEMA_PROPERTY);
if (schemaName != null) {
this.schemaFile = new File(schemaName);
}
}
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.warn("Could not add configuration: " + tmp);
}
} else if ( fileName.startsWith(FOLDER_PREFIX)) {
this.folders.add(fileName.substring(7));
} 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));
}
}
@Override
public boolean isRequestSupported() {
return true;
}
@Override
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,
java.util.logging.Logger.getLogger(FilePolicyModule.class.getName()),
this.schemaFile, this.useLines);
for (String fname : this.fileNames ) {
try {
AbstractPolicy policy =
reader.readPolicy(new FileInputStream(baseDir + fname), fname);
addPolicy(policy);
} catch (FileNotFoundException fnfe) {
logger.warn("File couldn't be read: "+ fname, fnfe);
} catch (ParsingException e) {
logger.warn("Error reading policy from file " + fname + ": " + e.getMessage(), e);
}
}
for ( String sFolder : this.folders ) {
File folder = new File(baseDir + sFolder);
File[] files = folder.listFiles();
for ( File f : files ) {
String name_lower = f.getName().toLowerCase();
if ( name_lower.endsWith(".xacml")) {
try {
AbstractPolicy policy = reader.readPolicy(new FileInputStream(f), f.getName());
addPolicy(policy);
} catch (FileNotFoundException e) {
logger.warn("File couldn't be read: "+ f.getName(), e);
} catch (ParsingException e) {
logger.warn("Error reading policy from file " + f.getName(), e);
}
}
}
}
logger.info("Loaded " + policies.size() + " policies, " + mainPolicies.size() + " main policies");
}
@Override
public PolicyFinderResult findPolicy(EvaluationCtx context) {
logger.debug("FilePolicyModule.findPolicy");
context.newEvent(this);
AbstractPolicy match = null;
for ( AbstractPolicy policy : this.mainPolicies.values() ) {
context.newEvent(policy);
logger.debug("Check match for Policy "+ policy.getId());
MatchResult mResult = policy.match(context);
int iResult = mResult.getResult();
if ( iResult == MatchResult.NO_MATCH ) {
context.closeCurrentEvent(new Result(Result.DECISION_NOT_APPLICABLE));
} else if ( iResult == MatchResult.MATCH ) {
context.closeCurrentEvent();
if ( match == null ) {
match = policy;
} else {
logger.error("Multiple main policies are matching: first: " + match.getId() + " - " + policy.getId());
List<String> statusCodes = new Vector<String>();
statusCodes.add(Status.STATUS_PROCESSING_ERROR);
Status errorStatus = new Status(statusCodes, "Error in PDP Configuration: Multiple matching main policies");
context.closeCurrentEvent(Result.INDETERMINATE);
return new PolicyFinderResult(errorStatus);
//throw new TopLevelPolicyException(mResult.getStatus(), "Multiple main policies are matching");
}
} else if ( iResult == MatchResult.INDETERMINATE ) {
context.closeCurrentEvent();
context.closeCurrentEvent(new Result(Result.DECISION_INDETERMINATE, context));
return new PolicyFinderResult(mResult.getStatus());
}
}
if (match == null) {
context.closeCurrentEvent();
logger.debug("Found no matching main policy");
return new PolicyFinderResult();
}
context.closeCurrentEvent(match.getId().toString());
logger.debug("Found one matching main policy: " + match.getId());
return new PolicyFinderResult(match);
// } catch (TopLevelPolicyException e) {
// logger.error("Could not find Policy (TopLevelPolicyException): " + e.getMessage());
// e.printStackTrace();
// context.closeCurrentEvent();
// return new PolicyFinderResult(e.getStatus());
// }
}
public boolean addPolicy(String filename) {
return this.fileNames.add(filename);
}
protected void addPolicy(AbstractPolicy policy) {
URI policyId = policy.getId();
this.policies.put(policyId,policy);
if ( policyId.toString().endsWith("main") ) {
this.mainPolicies.put(policyId, policy);
}
}
protected static boolean getBool(String value) {
try {
Boolean val = new Boolean(value);
return val.booleanValue();
} catch (Exception e) {
logger.warn( "Could not read boolean value " + value + "; Using false as default");
return false;
}
}
@Override
public boolean isIdReferenceSupported() {
return true;
}
@Override
public PolicyFinderResult findPolicy(EvaluationCtx context,
URI idReference, int type,
VersionConstraints constraints,
PolicyMetaData parentMetaData) {
if ( policies.containsKey(idReference)) {
AbstractPolicy policy = policies.get(idReference);
if ( constraints.meetsConstraint(policy.getVersion())) {
return new PolicyFinderResult(policy);
} else {
logger.warn("Found policy with right ID " + idReference + ", but version contraints do not match");
}
}
return new PolicyFinderResult();
}
/**
* 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;
}
public void setConfigurationStore(ConfigurationStore confStore) {
// save confStore if needed
}
}