InputStreamBasedPolicyFinderModule.java
/*
* THIS IS POLICY FINDER MODULE implemented by CNR for supporting DATA USAGE
* CONTROL CHANGED by CNR-IIT : THIS SHOULD BE MOVED TO PDP (CORE)
*/
package it.cnr.iit.ucs.pdp;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.wso2.balana.AbstractPolicy;
import org.wso2.balana.MatchResult;
import org.wso2.balana.Policy;
import org.wso2.balana.PolicySet;
import org.wso2.balana.combine.PolicyCombiningAlgorithm;
import org.wso2.balana.combine.xacml2.DenyOverridesPolicyAlg;
import org.wso2.balana.ctx.EvaluationCtx;
import org.wso2.balana.ctx.Status;
import org.wso2.balana.finder.PolicyFinder;
import org.wso2.balana.finder.PolicyFinderModule;
import org.wso2.balana.finder.PolicyFinderResult;
/**
* This is file based policy repository. Policies can be inside the directory in
* a file system. Then you can set directory location using
* "org.wso2.balana.PolicyDirectory" JAVA property
*
* @author Fabio Bindi Filippo Lauria
*
*/
class InputStreamBasedPolicyFinderModule extends PolicyFinderModule {
private static final Logger log = Logger.getLogger( InputStreamBasedPolicyFinderModule.class.getName() );
private PolicyFinder finder = null;
private Map<URI, AbstractPolicy> policies = new HashMap<>();
// the policy is stored here
private String policy = "";
private PolicyCombiningAlgorithm combiningAlg;
private DocumentBuilderFactory documentBuilderFactory;
public InputStreamBasedPolicyFinderModule( String policy ) {
try {
this.policy = policy;
documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setFeature( XMLConstants.FEATURE_SECURE_PROCESSING, true );
documentBuilderFactory.setIgnoringComments( true );
documentBuilderFactory.setNamespaceAware( true );
documentBuilderFactory.setValidating( false );
} catch( Exception e ) {
log.severe( e.getMessage() );
throw new IllegalStateException( "Unable to protect against XXE" );
}
}
@Override
public void init( PolicyFinder finder ) {
this.finder = finder;
loadPolicies();
combiningAlg = new DenyOverridesPolicyAlg();
}
@Override
public PolicyFinderResult findPolicy( EvaluationCtx context ) {
ArrayList<AbstractPolicy> selectedPolicies = new ArrayList<>();
Set<Map.Entry<URI, AbstractPolicy>> entrySet = policies.entrySet();
// iterate through all the policies we currently have loaded
for( Map.Entry<URI, AbstractPolicy> entry : entrySet ) {
AbstractPolicy abstractPolicy = entry.getValue();
MatchResult match = abstractPolicy.match( context );
int result = match.getResult();
// if target matching was indeterminate, then return the error
if( result == MatchResult.INDETERMINATE ) {
return new PolicyFinderResult( match.getStatus() );
}
// see if the target matched
if( result == MatchResult.MATCH ) {
if( ( combiningAlg == null ) && ( selectedPolicies.isEmpty() ) ) {
// we found a match before, so this is an error
ArrayList<String> code = new ArrayList<>();
code.add( Status.STATUS_PROCESSING_ERROR );
Status status = new Status( code, "too many applicable " + "top-level policies" );
return new PolicyFinderResult( status );
}
// this is the first match we've found, so remember it
selectedPolicies.add( abstractPolicy );
}
}
// no errors happened during the search, so now take the right
// action based on how many policies we found
switch( selectedPolicies.size() ) {
case 0:
return new PolicyFinderResult();
case 1:
return new PolicyFinderResult( ( selectedPolicies.get( 0 ) ) );
default:
return new PolicyFinderResult( new PolicySet( null, combiningAlg, null, selectedPolicies ) );
}
}
@Override
public boolean isIdReferenceSupported() {
return true;
}
@Override
public boolean isRequestSupported() {
return true;
}
public void loadPolicies() {
policies.clear();
loadPolicy( finder );
}
/**
* Private helper that tries to load the given file-based policy, and returns
* null if any error occurs.
*/
private AbstractPolicy loadPolicy( PolicyFinder finder ) {
AbstractPolicy abstractPolicy = null;
try (InputStream stream = new ByteArrayInputStream( policy.getBytes() )) {
DocumentBuilder db = documentBuilderFactory.newDocumentBuilder();
Document doc = db.parse( stream );
Element root = doc.getDocumentElement();
String name = root.getLocalName();
if( name.equals( "Policy" ) ) {
abstractPolicy = Policy.getInstance( root );
} else if( name.equals( "PolicySet" ) ) {
abstractPolicy = PolicySet.getInstance( root, finder );
}
} catch( Exception e ) {
log.warning( "fail to load UXACML policy : " + e.getLocalizedMessage() );
}
if( abstractPolicy != null ) {
policies.put( abstractPolicy.getId(), abstractPolicy );
}
return abstractPolicy;
}
}