/* 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.finder;
import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.tmatesoft.svn.core.SVNException;
import eu.aniketos.securebpmn.xacml.SVNPDPConfig;
import eu.aniketos.securebpmn.xacml.support.finder.IPDPStateEvaluationContext;
import com.sun.xacml.AbstractPolicy;
import com.sun.xacml.EvaluationCtx;
import com.sun.xacml.PolicyMetaData;
import com.sun.xacml.VersionConstraints;
import com.sun.xacml.ctx.Status;
import com.sun.xacml.finder.PolicyFinder;
import com.sun.xacml.finder.PolicyFinderResult;
/**
*
* This class retrieves, in contrast to the super class SVNPolicyFinderModule,
* the information which svn version to use from the context, which has to be
* a IPDPStateEvaluationContext. For this, a "main" instance manages all "sub"
* instances which hold a specific version.
* <br/>
* This class may be enhanced for productive usage, i.e., check if a new policy
* version will become active in a specific time frame, remove policies which will
* not be used any more from the cache, allow to trigger a load operation to
* circumvent delays for requests first using a new policy version.
*
*/
public class SVNStatePolicyFinderModule extends SVNPolicyFinderModule {
/*
* there typ "types" of this class: the main instance manages
* all sub instances, i.e., a instance has either the policyCache
* or the version set to a reasonable value
*/
private Map<Long, SVNStatePolicyFinderModule> policyCache = null;
private PolicyFinder finder;
private long version = -1;
private static final Logger logger = Logger.getLogger(SVNStatePolicyFinderModule.class);
@Override
public void init(PolicyFinder finder) {
logger.debug("Creating " + SVNStatePolicyFinderModule.class.getSimpleName() + " as main instance");
this.finder = finder;
policyCache = new HashMap<Long, SVNStatePolicyFinderModule>();
// do the init, e.g., get svn client
super.svnInit(finder);
}
protected synchronized SVNStatePolicyFinderModule loadVersion(Long version) {
if ( policyCache.containsKey(version)) {
return policyCache.get(version);
} else {
SVNStatePolicyFinderModule module = new SVNStatePolicyFinderModule(finder, svn, version.longValue());
policyCache.put(version, module);
return module;
}
}
protected SVNStatePolicyFinderModule(PolicyFinder finder, MySVNClient client, long version) {
logger.debug("Creating " + SVNStatePolicyFinderModule.class.getSimpleName() + " as sub instance");
super.svn = client;
super.svnInit(finder);
// create a buffer which can be used for all coming read operations
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
List<String> policyFileNames = null;
try {
policyFileNames = super.getPolicyFileNames(version, buffer);
} catch (SVNException e) {
logger.error("SVNException when reading file " + SVNPDPConfig.POLICY_FILE + " from repository: " + e.getMessage() + ", will not be able to retrieve policies from SVN storage");
policyFileNames = new Vector<String>();
}
List<AbstractPolicy> policies = getPolicies(finder, policyFileNames, version, buffer);
for ( AbstractPolicy policy : policies ) {
super.addPolicy(policy);
}
super.svn = null;
}
@Override
public PolicyFinderResult findPolicy(EvaluationCtx context) {
// check if we are the "main" finder which manages the policy cache
if ( policyCache != null ) {
if ( context instanceof IPDPStateEvaluationContext ) {
IPDPStateEvaluationContext stateContext = (IPDPStateEvaluationContext) context;
SVNStatePolicyFinderModule module = policyCache.get(new Long(stateContext.getVersion()));
if ( module == null ) {
module = loadVersion(new Long(version));
}
return module.findPolicy(context);
} else {
return new PolicyFinderResult(Status.createStatus(Status.STATUS_PROCESSING_ERROR, "SVNStatePolicyFinderModule requires IPDPStateEvaluationContext"));
}
} else {
// we are a "sub" finder, i.e., we can use our super class impl to find what we neeed
return super.findPolicy(context);
}
}
@Override
public PolicyFinderResult findPolicy(EvaluationCtx context,
URI idReference, int type,
VersionConstraints constraints,
PolicyMetaData parentMetaData) {
// check if we are the "main" finder which manages the policy cache
if ( policyCache != null ) {
// we do not need to do checks any more - they must have been failed when searching the main policy
return policyCache.get(new Long( ((IPDPStateEvaluationContext) context).getVersion())).
findPolicy(context, idReference, type, constraints, parentMetaData);
} else {
return super.findPolicy(context, idReference, type, constraints, parentMetaData);
}
}
// private long getCurrentPolicyVersion(AttributeFinder finder) {
// try {
// BasicEvaluationCtx ctx = new BasicEvaluationCtx(new RequestCtx(new HashSet<RequestElement>(), null, null));
// EvaluationResult evalResult = finder.findAttribute(Constants.ENVIRONMENT_CAT, TypeIdentifierConstants.INTEGER_URI, PDPSTATE_URI, null, ctx);
//
// return getCurrentPolicyVersion(evalResult);
// } catch (IllegalArgumentException e) {
// e.printStackTrace();
// } catch (ParsingException e) {
// e.printStackTrace();
// }
// return -1;
// }
//
// public static long getCurrentPolicyVersion(EvaluationCtx context) {
// return getCurrentPolicyVersion(
// context.getAttribute(
// Constants.ENVIRONMENT_CAT, TypeIdentifierConstants.INTEGER_URI, PDPSTATE_URI, null));
// }
//
// private static long getCurrentPolicyVersion(EvaluationResult evalResult) {
// if ( !evalResult.getAttributeValue().isBag() ||
// ((BagAttribute) evalResult.getAttributeValue()).size() != 1 ) {
// logger.error("Did not retreive a bag with one (" +((BagAttribute) evalResult.getAttributeValue()).size() +
// ") entry after attribute search for current svn policy version number " +
// "SVNStatePolicyFinderModule requires exactly one attribute to be defined");
// return -1;
// }
// IntegerAttribute attrVal = (IntegerAttribute) ((BagAttribute) evalResult.getAttributeValue()).iterator().next();
//
// return attrVal.getValue();
// }
//
//TODO create policy cache
// get policies in correct version from policy cache - key is svn ID
//
// TODO create a time stamp for when the active policy version was checked
}