package org.wso2.balana.finder.impl; /* * Copyright (c) WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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. */ import java.net.URI; import java.util.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.wso2.balana.AbstractPolicy; import org.wso2.balana.DOMHelper; import org.wso2.balana.MatchResult; import org.wso2.balana.ParsingException; import org.wso2.balana.Policy; import org.wso2.balana.PolicyMetaData; import org.wso2.balana.PolicyReference; import org.wso2.balana.PolicySet; import org.wso2.balana.VersionConstraints; 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; /** * An in-memory policy repository, in which policies are maintained in a static List. * */ public class InMemoryPolicyFinderModule extends PolicyFinderModule { private PolicyFinder finder = null; private PolicyCombiningAlgorithm combiningAlg; private Map<URI, AbstractPolicy> policies; private static Log log = LogFactory.getLog(InMemoryPolicyFinderModule.class); /** * Instantiate a repository using the specified collection of policy documents. * @param policyDocuments the list of policy documents */ public InMemoryPolicyFinderModule(List<Document> policyDocuments) { policies = new LinkedHashMap<URI, AbstractPolicy>(); for (Document d : policyDocuments) { AbstractPolicy p = loadPolicy(d); policies.put(p.getId(), p); } combiningAlg = new DenyOverridesPolicyAlg(); } /** * Instantiate a repository using the specified collection of policy documents. * @param policyDocuments the list of policy documents * @param combiningAlg policy combining algorithm <code>PolicyCombiningAlgorithm</code> */ public InMemoryPolicyFinderModule(List<Document> policyDocuments, PolicyCombiningAlgorithm combiningAlg) { policies = new HashMap<URI, AbstractPolicy>(); for (Document d : policyDocuments) { AbstractPolicy p = loadPolicy(d); policies.put(p.getId(), p); } this.combiningAlg = combiningAlg; } @Override public void init(PolicyFinder finder) { this.finder = finder; } @Override public boolean isIdReferenceSupported() { return true; } @Override public boolean isRequestSupported() { return true; } // TODO: Copied these 2 from the FileBasedPolicyFinderModule class; consider pulling these up into the abstract base? @Override public PolicyFinderResult findPolicy(EvaluationCtx context) { ArrayList<AbstractPolicy> selectedPolicies = new ArrayList<AbstractPolicy>(); 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 policy = entry.getValue(); MatchResult match = policy.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.size() > 0)) { // we found a match before, so this is an error ArrayList<String> code = new ArrayList<String>(); 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(policy); } } // no errors happened during the search, so now take the right // action based on how many policies we found switch (selectedPolicies.size()) { case 0: if (log.isDebugEnabled()) { log.debug("No matching XACML policy found"); } return new PolicyFinderResult(); case 1: return new PolicyFinderResult((selectedPolicies.get(0))); default: return new PolicyFinderResult(new PolicySet(null, combiningAlg, null, selectedPolicies)); } } @Override public PolicyFinderResult findPolicy(URI idReference, int type, VersionConstraints constraints, PolicyMetaData parentMetaData) { AbstractPolicy policy = policies.get(idReference); if (policy != null) { if (type == PolicyReference.POLICY_REFERENCE) { if (policy instanceof Policy) { return new PolicyFinderResult(policy); } } else { if (policy instanceof PolicySet) { return new PolicyFinderResult(policy); } } } // if there was an error loading the policy, return the error ArrayList<String> code = new ArrayList<String>(); code.add(Status.STATUS_PROCESSING_ERROR); Status status = new Status(code, "couldn't load referenced policy"); log.info("No policy found, code=" + code); return new PolicyFinderResult(status); } private AbstractPolicy loadPolicy(Document policyDocument) { // based this largely on the FileBasedPolicyFinderModule implementation...strong potential for refactoring / pull-up here... AbstractPolicy policy = null; Element root = policyDocument.getDocumentElement(); String name = DOMHelper.getLocalName(root); try { if (name.equals("Policy")) { policy = Policy.getInstance(root); } else if (name.equals("PolicySet")) { policy = PolicySet.getInstance(root, finder); } } catch (ParsingException e) { // just only logs log.error("Fail to load policy : " + policyDocument.getDocumentElement().getNodeName(), e); } return policy; } }