/* * Copyright (c) 2005-2010, 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.pip; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Node; import org.wso2.balana.attr.AttributeValue; import org.wso2.balana.ctx.EvaluationCtx; import org.wso2.balana.finder.ResourceFinderModule; import org.wso2.balana.finder.ResourceFinderResult; import org.wso2.carbon.identity.entitlement.EntitlementException; import org.wso2.carbon.identity.entitlement.EntitlementUtil; import org.wso2.carbon.identity.entitlement.PDPConstants; import org.wso2.carbon.identity.entitlement.cache.EntitlementBaseCache; import org.wso2.carbon.identity.entitlement.cache.IdentityCacheEntry; import org.wso2.carbon.identity.entitlement.cache.IdentityCacheKey; import org.wso2.carbon.identity.entitlement.internal.EntitlementServiceComponent; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.StringWriter; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; /** * CarbonResourceFinder implements the ResourceFinderModule in the sum-xacml. This class would find * children and descendant resources in the Registry resources which is running on the WSO2 Identity * Server */ public class CarbonResourceFinder extends ResourceFinderModule { private static Log log = LogFactory.getLog(CarbonResourceFinder.class); boolean isResourceCachingEnabled = false; private int tenantId; private Set<PIPResourceFinder> resourceFinders = new HashSet<PIPResourceFinder>(); //private Cache<IdentityCacheKey,IdentityCacheEntry> resourceCache = null; private EntitlementBaseCache<IdentityCacheKey, IdentityCacheEntry> resourceCache = null; public CarbonResourceFinder(int tenantId) { this.tenantId = tenantId; } /** * initializes the Carbon resource finder by listing the registered resource finders */ public void init() { Map<PIPResourceFinder, Properties> resourceConfigs = EntitlementServiceComponent.getEntitlementConfig() .getResourceFinders(); if (resourceConfigs != null && !resourceConfigs.isEmpty()) { resourceFinders = resourceConfigs.keySet(); } Properties properties = EntitlementServiceComponent.getEntitlementConfig().getEngineProperties(); if ("true".equals(properties.getProperty(PDPConstants.RESOURCE_CACHING))) { resourceCache = EntitlementUtil .getCommonCache(PDPConstants.PIP_RESOURCE_CACHE); isResourceCachingEnabled = true; } } @Override public boolean isChildSupported() { return true; } @Override public boolean isDescendantSupported() { return true; } @Override public ResourceFinderResult findDescendantResources(AttributeValue parentResourceId, EvaluationCtx context) { ResourceFinderResult resourceFinderResult = null; Set<AttributeValue> resources = null; String dataType = parentResourceId.getType().toString(); for (PIPResourceFinder finder : resourceFinders) { try { Set<String> resourceNames = null; if (isResourceCachingEnabled && !finder.overrideDefaultCache()) { IdentityCacheKey cacheKey = null; String key = PDPConstants.RESOURCE_DESCENDANTS + parentResourceId.encode() + domToString(context.getRequestRoot()); cacheKey = new IdentityCacheKey(tenantId, key); IdentityCacheEntry cacheEntry = (IdentityCacheEntry) resourceCache.getValueFromCache(cacheKey); if (cacheEntry != null) { String[] values = cacheEntry.getCacheEntryArray(); resourceNames = new HashSet<String>(Arrays.asList(values)); if (log.isDebugEnabled()) { log.debug("Carbon Resource Cache Hit"); } } if (resourceNames != null) { resourceNames = finder.findDescendantResources(parentResourceId.encode(), context); if (log.isDebugEnabled()) { log.debug("Carbon Resource Cache Miss"); } cacheEntry = new IdentityCacheEntry(resourceNames.toArray(new String[resourceNames.size()])); resourceCache.addToCache(cacheKey, cacheEntry); } } else { resourceNames = finder.findDescendantResources(parentResourceId.encode(), context); } if (resourceNames != null && !resourceNames.isEmpty()) { resources = new HashSet<AttributeValue>(); for (String resourceName : resourceNames) { resources.add(EntitlementUtil.getAttributeValue(resourceName, dataType)); } } } catch (EntitlementException e) { log.error("Error while finding descendant resources", e); } catch (TransformerException e) { log.error("Error while finding descendant resources", e); } catch (Exception e) { log.error("Error while finding descendant resources", e); } } if (resources != null) { resourceFinderResult = new ResourceFinderResult(resources); } else { resourceFinderResult = new ResourceFinderResult(); } return resourceFinderResult; } @Override public ResourceFinderResult findChildResources(AttributeValue parentResourceId, EvaluationCtx context) { ResourceFinderResult resourceFinderResult = null; Set<AttributeValue> resources = null; String dataType = parentResourceId.getType().toString(); for (PIPResourceFinder finder : resourceFinders) { try { Set<String> resourceNames = null; if (isResourceCachingEnabled && !finder.overrideDefaultCache()) { IdentityCacheKey cacheKey = null; String key = PDPConstants.RESOURCE_CHILDREN + parentResourceId.encode() + domToString(context.getRequestRoot()); cacheKey = new IdentityCacheKey(tenantId, key); IdentityCacheEntry cacheEntry = (IdentityCacheEntry) resourceCache.getValueFromCache(cacheKey); if (cacheEntry != null) { String cacheEntryString = cacheEntry.getCacheEntry(); String[] attributes = cacheEntryString.split(PDPConstants.ATTRIBUTE_SEPARATOR); if (attributes != null && attributes.length > 0) { List<String> list = Arrays.asList(attributes); resourceNames = new HashSet<String>(list); } if (log.isDebugEnabled()) { log.debug("Carbon Resource Cache Hit"); } } else { resourceNames = finder.findChildResources(parentResourceId.encode(), context); if (log.isDebugEnabled()) { log.debug("Carbon Resource Cache Miss"); } String cacheEntryString = ""; if (resourceNames != null && resourceNames.size() > 0) { for (String attribute : resourceNames) { if (cacheEntryString.equals("")) { cacheEntryString = attribute; } else { cacheEntryString = cacheEntryString + PDPConstants.ATTRIBUTE_SEPARATOR + attribute; } } } cacheEntry = new IdentityCacheEntry(cacheEntryString); resourceCache.addToCache(cacheKey, cacheEntry); } } else { resourceNames = finder.findChildResources(parentResourceId.encode(), context); } if (resourceNames != null && !resourceNames.isEmpty()) { resources = new HashSet<AttributeValue>(); for (String resourceName : resourceNames) { resources.add(EntitlementUtil.getAttributeValue(resourceName, dataType)); } } } catch (EntitlementException e) { log.error("Error while finding child resources", e); } catch (TransformerException e) { log.error("Error while finding child resources", e); } catch (Exception e) { log.error("Error while finding child resources", e); } } if (resources != null) { resourceFinderResult = new ResourceFinderResult(resources); } else { resourceFinderResult = new ResourceFinderResult(); } return resourceFinderResult; } /** * Disables resource Caches */ public void disableAttributeCache() { resourceCache = null; } /** * Enables resource caches */ public void enableAttributeCache() { resourceCache = EntitlementUtil .getCommonCache(PDPConstants.PIP_RESOURCE_CACHE); } /** * Clears attribute cache */ public void clearAttributeCache() { if (resourceCache != null) { resourceCache.clear(); if (log.isDebugEnabled()) { log.debug("Resource cache is cleared for tenant " + tenantId); } } } /** * Converts DOM object to String. This is a helper method for creating cache key * * @param node Node value * @return String Object * @throws javax.xml.transform.TransformerException Exception throws if fails */ private String domToString(Node node) throws TransformerException { TransformerFactory transFactory = TransformerFactory.newInstance(); Transformer transformer = transFactory.newTransformer(); StringWriter buffer = new StringWriter(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.transform(new DOMSource(node), new StreamResult(buffer)); return buffer.toString(); } }