/* * 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. */ package org.wso2.carbon.identity.entitlement.policy.finder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.balana.AbstractPolicy; 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.ctx.EvaluationCtx; import org.wso2.balana.ctx.Status; import org.wso2.balana.finder.PolicyFinder; import org.wso2.balana.finder.PolicyFinderResult; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.identity.entitlement.EntitlementException; import org.wso2.carbon.identity.entitlement.PDPConstants; import org.wso2.carbon.identity.entitlement.PolicyOrderComparator; import org.wso2.carbon.identity.entitlement.cache.PolicyStatus; import org.wso2.carbon.identity.entitlement.common.EntitlementConstants; import org.wso2.carbon.identity.entitlement.dto.PolicyDTO; import org.wso2.carbon.identity.entitlement.internal.EntitlementServiceComponent; import org.wso2.carbon.identity.entitlement.pdp.EntitlementEngine; import org.wso2.carbon.identity.entitlement.policy.PolicyReader; import org.wso2.carbon.identity.entitlement.policy.collection.PolicyCollection; import org.wso2.carbon.identity.entitlement.policy.collection.SimplePolicyCollection; import org.wso2.carbon.identity.entitlement.policy.store.DefaultPolicyDataStore; import org.wso2.carbon.identity.entitlement.policy.store.PolicyDataStore; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; /** * Policy finder of the WSO2 entitlement engine. This an implementation of <code>PolicyFinderModule</code> * of Balana engine. Extensions can be plugged with this. */ public class CarbonPolicyFinder extends org.wso2.balana.finder.PolicyFinderModule { private static Log log = LogFactory.getLog(CarbonPolicyFinder.class); public PolicyReader policyReader; private List<PolicyFinderModule> finderModules = null; private PolicyCollection policyCollection; private List<PolicyDTO> policyCollectionOrder = new ArrayList<PolicyDTO>(); private PolicyFinder finder; /** * this is a flag to keep whether init it has finished or not. */ private volatile boolean initFinish; private LinkedHashMap<URI, AbstractPolicy> policyReferenceCache = null; private int maxReferenceCacheEntries = PDPConstants.MAX_NO_OF_IN_MEMORY_POLICIES; @Override public void init(PolicyFinder finder) { initFinish = false; this.finder = finder; init(); policyReferenceCache.clear(); } private synchronized void init() { if (initFinish) { return; } log.info("Initializing of policy store is started at : " + new Date()); String maxEntries = EntitlementServiceComponent.getEntitlementConfig().getEngineProperties(). getProperty(PDPConstants.MAX_POLICY_REFERENCE_ENTRIES); if (maxEntries != null) { try { maxReferenceCacheEntries = Integer.parseInt(maxEntries.trim()); } catch (Exception e) { //ignore } } policyReferenceCache = new LinkedHashMap<URI, AbstractPolicy>() { @Override protected boolean removeEldestEntry(Map.Entry eldest) { // oldest entry of the cache would be removed when max cache size become, i.e 50 return size() > maxReferenceCacheEntries; } }; PolicyCombiningAlgorithm policyCombiningAlgorithm = null; // get registered finder modules Map<PolicyFinderModule, Properties> finderModules = EntitlementServiceComponent. getEntitlementConfig().getPolicyFinderModules(); if (finderModules != null) { this.finderModules = new ArrayList<PolicyFinderModule>(finderModules.keySet()); } PolicyCollection tempPolicyCollection = null; // get policy collection Map<PolicyCollection, Properties> policyCollections = EntitlementServiceComponent. getEntitlementConfig().getPolicyCollections(); if (policyCollections != null && policyCollections.size() > 0) { tempPolicyCollection = policyCollections.entrySet().iterator().next().getKey(); } else { tempPolicyCollection = new SimplePolicyCollection(); } // get policy reader policyReader = PolicyReader.getInstance(finder); if (this.finderModules != null && this.finderModules.size() > 0) { // find policy combining algorithm. // here we can get policy data store by using EntitlementAdminEngine. But we are not // use it here. As we need not to have a dependant on EntitlementAdminEngine PolicyDataStore policyDataStore; Map<PolicyDataStore, Properties> dataStoreModules = EntitlementServiceComponent. getEntitlementConfig().getPolicyDataStore(); if (dataStoreModules != null && dataStoreModules.size() > 0) { policyDataStore = dataStoreModules.entrySet().iterator().next().getKey(); } else { policyDataStore = new DefaultPolicyDataStore(); } policyCombiningAlgorithm = policyDataStore.getGlobalPolicyAlgorithm(); tempPolicyCollection.setPolicyCombiningAlgorithm(policyCombiningAlgorithm); for (PolicyFinderModule finderModule : this.finderModules) { log.info("Start retrieving policies from " + finderModule + " at : " + new Date()); String[] policies = finderModule.getActivePolicies(); for (int a = 0; a < policies.length; a++) { String policy = policies[a]; AbstractPolicy abstractPolicy = policyReader.getPolicy(policy); if (abstractPolicy != null) { PolicyDTO policyDTO = new PolicyDTO(); policyDTO.setPolicyId(abstractPolicy.getId().toString()); policyDTO.setPolicyOrder(a); policyCollectionOrder.add(policyDTO); tempPolicyCollection.addPolicy(abstractPolicy); } } log.info("Finish retrieving policies from " + finderModule + " at : " + new Date()); } } else { log.warn("No Carbon policy finder modules are registered"); } policyCollection = tempPolicyCollection; initFinish = true; log.info("Initializing of policy store is finished at : " + new Date()); } @Override public String getIdentifier() { return super.getIdentifier(); } @Override public boolean isRequestSupported() { return true; } @Override public boolean isIdReferenceSupported() { return true; } private void orderPolicyCache() { LinkedHashMap<URI, AbstractPolicy> policyMap = policyCollection.getPolicyMap(); Collections.sort(policyCollectionOrder, new PolicyOrderComparator()); LinkedHashMap<URI, AbstractPolicy> newPolicyMap = new LinkedHashMap<URI, AbstractPolicy>(); Iterator<PolicyDTO> policyDTOIterator = policyCollectionOrder.iterator(); while (policyDTOIterator.hasNext()) { try { URI policyURI = new URI(policyDTOIterator.next().getPolicyId()); newPolicyMap.put(policyURI, policyMap.get(policyURI)); } catch (URISyntaxException e) { e.printStackTrace(); } } } @Override public PolicyFinderResult findPolicy(EvaluationCtx context) { if (EntitlementEngine.getInstance().getPolicyCache().isInvalidate()) { init(this.finder); policyReferenceCache.clear(); EntitlementEngine.getInstance().clearDecisionCache(); if (log.isDebugEnabled()) { int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); log.debug("Invalidation cache message is received. " + "Re-initialized policy finder module of current node and invalidate decision " + "caching for tenantId : " + tenantId); } } else { Collection<PolicyStatus> policies = EntitlementEngine.getInstance().getPolicyCache().getInvalidatedPolicies(); if (policies != null) { if (policies.size() > 0) { synchronized (policies) { boolean isReorder = false; policyReferenceCache.clear(); EntitlementEngine.getInstance().clearDecisionCache(); for (PolicyStatus policyStatus : policies) { if (EntitlementConstants.PolicyPublish.ACTION_DELETE .equals(policyStatus.getPolicyAction())) { policyCollection.deletePolicy(policyStatus.getPolicyId()); policyCollectionOrder.remove(new PolicyDTO(policyStatus.getPolicyId())); } else if (EntitlementConstants.PolicyPublish.ACTION_UPDATE .equals(policyStatus.getPolicyAction())) { AbstractPolicy abstractPolicy = loadPolicy(policyStatus.getPolicyId()); policyCollection.addPolicy(abstractPolicy); } else if (EntitlementConstants.PolicyPublish.ACTION_CREATE .equals(policyStatus.getPolicyAction())) { AbstractPolicy abstractPolicy = loadPolicy(policyStatus.getPolicyId()); policyCollection.addPolicy(abstractPolicy); isReorder = true; } else if (EntitlementConstants.PolicyPublish.ACTION_ORDER .equals(policyStatus.getPolicyAction())) { int order = getPolicyOrder(policyStatus.getPolicyId()); if (order != -1) { PolicyDTO policyDTO = new PolicyDTO(policyStatus.getPolicyId()); if (policyCollectionOrder.indexOf(policyDTO) != -1) { policyCollectionOrder.get(policyCollectionOrder.indexOf(policyDTO)) .setPolicyOrder(order); isReorder = true; } } } } if (isReorder) { orderPolicyCache(); } policies.clear(); } } } } try { AbstractPolicy policy = policyCollection.getEffectivePolicy(context); if (policy == null) { return new PolicyFinderResult(); } else { return new PolicyFinderResult(policy); } } catch (EntitlementException e) { ArrayList<String> code = new ArrayList<String>(); code.add(Status.STATUS_PROCESSING_ERROR); Status status = new Status(code, e.getMessage()); return new PolicyFinderResult(status); } } private AbstractPolicy loadPolicy(String policyId) { if (this.finderModules != null) { for (PolicyFinderModule finderModule : this.finderModules) { String policyString = finderModule.getPolicy(policyId); if (policyString != null) { AbstractPolicy policy = policyReader.getPolicy(policyString); if (policy != null) { return policy; } } } } return null; } private int getPolicyOrder(String policyId) { int order = -1; if (this.finderModules != null) { for (PolicyFinderModule finderModule : this.finderModules) { if ((order = finderModule.getPolicyOrder(policyId)) != -1) { break; } } } return order; } @Override public PolicyFinderResult findPolicy(URI idReference, int type, VersionConstraints constraints, PolicyMetaData parentMetaData) { AbstractPolicy policy = policyReferenceCache.get(idReference); if (policy == null) { if (this.finderModules != null) { for (PolicyFinderModule finderModule : this.finderModules) { String policyString = finderModule.getReferencedPolicy(idReference.toString()); if (policyString != null) { policy = policyReader.getPolicy(policyString); if (policy != null) { policyReferenceCache.put(idReference, policy); break; } } } } } if (policy != null) { // we found a valid version, so see if it's the right kind, // and if it is then we return it if (type == PolicyReference.POLICY_REFERENCE) { if (policy instanceof Policy) { return new PolicyFinderResult(policy); } } else { if (policy instanceof PolicySet) { return new PolicyFinderResult(policy); } } } return new PolicyFinderResult(); } public void clearPolicyCache() { EntitlementEngine.getInstance().getPolicyCache().clear(); } }