/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: ResourceManager.java,v 1.7 2009/06/30 17:46:02 veiming Exp $
*
* Portions Copyrighted 2011-2015 ForgeRock AS.
*/
package com.sun.identity.policy;
import java.io.ByteArrayInputStream;
import java.security.AccessController;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import com.iplanet.am.util.Cache;
import com.iplanet.sso.SSOException;
import com.iplanet.sso.SSOToken;
import com.sun.identity.policy.interfaces.Referral;
import com.sun.identity.policy.plugins.OrgReferral;
import com.sun.identity.security.AdminTokenAction;
import com.sun.identity.shared.debug.Debug;
import com.sun.identity.shared.xml.XMLUtils;
import com.sun.identity.sm.SMSException;
import com.sun.identity.sm.SMSSchema;
import com.sun.identity.sm.ServiceConfig;
import com.sun.identity.sm.ServiceConfigManager;
import com.sun.identity.sm.ServiceManager;
import org.forgerock.openam.ldap.LDAPUtils;
import org.forgerock.opendj.ldap.DN;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* The class <code>ResourceManager</code> manages an index to the
* resources managed by policies in a specific organization/realm.
*
*/
public class ResourceManager {
private String org = "/";
private SSOToken token = null;
private ServiceConfigManager scm = null;
private boolean canCreateNewRes = false;
ServiceTypeManager stm = null;
// resources service config
private ServiceConfig rConfig = null;
// key: service type name, value: ServiceType object
private Hashtable serviceTypeHash = new Hashtable();
private static final String RESOURCES_XML = "xmlresources";
private static final String RESOURCE_PREFIXES = "resourceprefixes";
static final String EMPTY_RESOURCE_NAME = "---EMPTY---";
static Debug debug = Debug.getInstance("amPolicy");
//Constants to build XML representation
static final String LTS = "<";
static final String LTSS = "</";
static final String GTS = ">";
static final String SGTS = "/>";
static final String SPACE = " ";
static final String QUOTE = "\"";
static final String EQUALS = "=";
static final String NEW_LINE = "\n";
static final String RESOURCE_PREFIXES_XML = "resourcePrefixesXml";
static final String ATTRIBUTE_VALUE_PAIR = "AttributValuePair";
static final String PREFIX = "Prefix";
static final String NAME = "name";
static final String COUNT = "count";
// Cache to store the policy names
Cache policyNames = new Cache(1000);
/**
* this constructor is called by PolicyManager
*/
ResourceManager(String orgName)
throws SSOException, SMSException {
this.token = (SSOToken) AccessController.doPrivileged(
AdminTokenAction.getInstance());
org = orgName;
this.scm = new ServiceConfigManager(PolicyManager.POLICY_SERVICE_NAME,
token);
stm = ServiceTypeManager.getServiceTypeManager();
canCreateNewRes = LDAPUtils.dnEquals(org, ServiceManager.getBaseDN());
}
/**
* Returns a set of all managed resource names for all the
* service types
*
* @return names of the resources managed
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
*/
public Set getManagedResourceNames()throws PolicyException {
Set managedResources = null;
ServiceConfig resources = getResourcesServiceConfig(false);
if (resources == null) {
managedResources = Collections.EMPTY_SET;
} else {
Set resourceTypes = null;
try {
resourceTypes = resources.getSubConfigNames();
} catch (SMSException e1) {
throw new PolicyException(e1);
}
if ( (resourceTypes == null) || (resourceTypes.isEmpty()) ) {
managedResources = Collections.EMPTY_SET;
} else {
managedResources = new HashSet();
Iterator rtIter = resourceTypes.iterator();
while ( rtIter.hasNext() ) {
String resourceType = (String) rtIter.next();
managedResources.addAll(
getManagedResourceNames(resourceType));
}
}
}
return managedResources;
}
/**
* Returns a set of all managed resource names for the given
* service type.
*
* @param serviceType the service type for which the resource
* names should be returned.
*
* @return names of the resources.
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
*/
public Set getManagedResourceNames(String serviceType)
throws PolicyException {
ServiceConfig resources = getResourcesServiceConfig(false);
if (resources == null) {
return Collections.EMPTY_SET;
}
ServiceConfig leafConfig = null;
try {
leafConfig = resources.getSubConfig(serviceType);
} catch (SMSException e1) {
throw new PolicyException(e1);
} catch (SSOException e1) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
if (leafConfig == null) {
// no resource node for this service type
return Collections.EMPTY_SET;
}
// else, see if the attribute is there and non-empty
Map existingAttrs = null;
existingAttrs = leafConfig.getAttributes();
if ((existingAttrs == null) ||
(!existingAttrs.containsKey(RESOURCE_PREFIXES))) {
return Collections.EMPTY_SET;
}
// else, need to look into the attribute
Set existingRes = (Set) existingAttrs.get(RESOURCE_PREFIXES);
Set resourcePrefixes = existingRes;
if ( (existingRes != null) && (!existingRes.isEmpty()) ) {
String xmlPrefix = (String) (existingRes.iterator().next());
resourcePrefixes
= xmlToResourcePrefixes(xmlPrefix).keySet();
}
return resourcePrefixes;
}
/**
* Determines that with the given organization (or, sub-organization,
* or container) name, if a new resource can be created or not.
* Only root level organization/realm has the privilege to create
* any resource.
*
* @param ServiceType the service type
*
* @return <code>true</code> if new resources can be created,
* else <code>false</code>
*
* @exception PolicyException problem with configuration store
*/
public boolean canCreateNewResource(String ServiceType)
throws PolicyException {
return canCreateNewRes;
}
/**
* Returns a set of valid service names that are applicable for
* the organization. The result will depended if new resources
* can be created for the organization and also if the organization
* has managed resources.
*
* @return set of service names that are valid for the organization
*
* @exception SSOException if the caller's single sign on token has expired
* @exception PolicyException if not able to get list of services
* defined for the organization
*/
public Set getValidServiceNames() throws SSOException, PolicyException {
Set answer = null;
Iterator serviceNames = stm.getServiceTypeNames().iterator();
while (serviceNames.hasNext()) {
String serviceName = (String) serviceNames.next();
if (canCreateNewResource(serviceName) ||
!getManagedResourceNames(serviceName).isEmpty()) {
if (answer == null) {
answer = new HashSet();
}
answer.add(serviceName);
}
}
return ((answer == null) ? Collections.EMPTY_SET : answer);
}
/**
* Returns a set of names of all the policies for the given resource
* of the given service.
*
* @param serviceType the service type which the resource is associated
* with
* @param resource the resource for which policies should be returned
* @param includePoliciesForSuperResources indicating whether the
* policies for all the super-resources in addition to the ultimate
* (sub)resource should be returned
*
* @return set of names of the policies.
*
* @exception InvalidFormatException the retrieved resources
* from the data store have been corrupted or do not have a
* valid format.
* @exception NoPermissionException the user does not have sufficient
* privileges.
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
* @exception SSOException single-sign-on token invalid or expired
*/
public Set getPolicyNames(String serviceType,
String resource,
boolean includePoliciesForSuperResources)
throws InvalidFormatException, NoPermissionException,
PolicyException, SSOException {
// %%% Need to flush the cache when policy's are changed
StringBuilder cacheNameBuffer = new StringBuilder();
String cacheName = cacheNameBuffer.append(serviceType)
.append(resource)
.append(includePoliciesForSuperResources).toString();
Set answer = null;
if ((answer = (Set) policyNames.get(cacheName)) != null) {
return (answer);
}
// This line may impact performance, try to optimize it later
Node rootNode = getXMLRootNode(serviceType);
if (rootNode == null) {
return Collections.EMPTY_SET;
}
ServiceType st = getServiceType(serviceType);
answer = getPolicyNames(rootNode, null, st, resource,
includePoliciesForSuperResources);
// add it to the cache
policyNames.put(cacheName, answer);
return (answer);
}
private ServiceType getServiceType(String serviceType)
throws SSOException, NameNotFoundException {
ServiceType st = (ServiceType)serviceTypeHash.get(serviceType);
if (st == null) {
st = stm.getServiceType(serviceType);
serviceTypeHash.put(serviceType, st);
}
return st;
}
/**
* Adds the resource names of the policy to the resource tree.
*
* @param policy the policy to be added
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
* @exception SSOException single-sign-on token invalid or expired
*/
void addPolicyToResourceTree(Policy policy)
throws PolicyException, SSOException {
Set ruleNames = policy.getRuleNames();
Iterator i = ruleNames.iterator();
// iterating through each rule
String ruleName = null;
Rule rule = null;
while (i.hasNext()) {
ruleName = (String) i.next();
rule = policy.getRule(ruleName);
addRuleToResourceTree(policy.getName(), rule);
}
//Process Referrals
Referrals referrals = policy.getReferrals();
if ( referrals != null ) {
Set referralNames = referrals.getReferralNames();
if ( (referralNames != null) && (!referralNames.isEmpty()) ) {
Iterator referralIter = referralNames.iterator();
while ( referralIter.hasNext() ) {
String referralName= (String) referralIter.next();
Referral referral = referrals.getReferral(referralName);
if ( referral instanceof OrgReferral ) {
Set values = referral.getValues();
if ( (values != null) && (!values.isEmpty()) ) {
Iterator valueIter = values.iterator();
while ( valueIter.hasNext() ) {
String value = (String) valueIter.next();
PolicyManager pm
= new PolicyManager(token, value);
ResourceManager rm = pm.getResourceManager();
Set ruleNames1 = policy.getRuleNames();
Iterator ruleIter = ruleNames1.iterator();
while ( ruleIter.hasNext() ) {
String ruleName1
= (String) ruleIter.next();
Rule rule1 = policy.getRule(ruleName1);
String resourceName =
rule1.getResourceName();
if ( resourceName != null ) {
String serviceTypeName
= rule1.getServiceTypeName();
Set resourceNames = new HashSet();
resourceNames.add(resourceName);
rm.addResourcePrefixes(serviceTypeName,
resourceNames);
}
}
}
}
}
}
}
}
}
/**
* Removes the resource names of the policy from the resource tree.
*
* @param policy the policy to be removed
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
* @exception SSOException single-sign-on token invalid or expired
*/
void removePolicyFromResourceTree(Policy policy)
throws PolicyException, SSOException {
Set ruleNames = policy.getRuleNames();
Iterator i = ruleNames.iterator();
// iterating through each rule
String ruleName = null;
Rule rule = null;
while (i.hasNext()) {
ruleName = (String) i.next();
rule = policy.getRule(ruleName);
removeRuleFromResourceTree(policy.getName(),
rule.getResourceName(),
rule.getServiceTypeName(),
rule.getServiceType());
}
//Process Referrals
Referrals referrals = policy.getReferrals();
if ( referrals != null ) {
Set referralNames = referrals.getReferralNames();
if ( (referralNames != null) && (!referralNames.isEmpty()) ) {
Iterator referralIter = referralNames.iterator();
while ( referralIter.hasNext() ) {
String referralName = (String) referralIter.next();
Referral referral = referrals.getReferral(referralName);
if ( referral instanceof OrgReferral ) {
Set values = referral.getValues();
if ( (values != null) && (!values.isEmpty()) ) {
Iterator valueIter = values.iterator();
while ( valueIter.hasNext() ) {
String value = (String) valueIter.next();
PolicyManager pm
= new PolicyManager(token, value);
ResourceManager rm = pm.getResourceManager();
Iterator ruleIter =
policy.getRuleNames().iterator();
while ( ruleIter.hasNext() ) {
String ruleName1
= (String) ruleIter.next();
Rule rule1 = policy.getRule(ruleName);
String resourceName =
rule1.getResourceName();
if ( resourceName != null ) {
String serviceTypeName
= rule1.getServiceTypeName();
Set resourceNames = new HashSet();
resourceNames.add(resourceName);
rm.removeResourcePrefixes(
serviceTypeName, resourceNames);
}
}
}
}
}
}
}
}
}
/**
* Replaces resource names of a policy in the resource tree.
*
* @param oldPolicy the policy to be replaced
* @param newPolicy the policy to replace the existins policy with
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
* @exception SSOException single-sign-on token invalid or expired
*/
void replacePolicyInResourceTree(Policy oldPolicy, Policy newPolicy)
throws PolicyException, SSOException {
removePolicyFromResourceTree(oldPolicy);
addPolicyToResourceTree(newPolicy);
}
private ServiceConfig getResourcesServiceConfig(boolean create)
throws PolicyException {
if (rConfig == null) {
try {
if (create) {
rConfig = PolicyManager.createOrGetPolicyConfig(
PolicyManager.RESOURCES_POLICY,
PolicyManager.RESOURCES_POLICY, scm, org);
} else {
//rConfig = scm.getOrganizationConfig(org, null);
ServiceConfig oConfig = scm.getOrganizationConfig(org,
null);
rConfig = (oConfig == null) ? null :
oConfig.getSubConfig(PolicyManager.RESOURCES_POLICY);
}
} catch (SMSException e) {
throw new PolicyException(e);
} catch (SSOException e) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
}
if (!rConfig.isValid()) {
if (debug.messageEnabled()) {
debug.message("ResourceManager.getResourcesServiceConfig():"
+ "rConfig is not valid");
}
try {
scm = new ServiceConfigManager(
PolicyManager.POLICY_SERVICE_NAME, token);
ServiceConfig oConfig = scm.getOrganizationConfig(org, null);
rConfig = (oConfig == null) ? null :
oConfig.getSubConfig(PolicyManager.RESOURCES_POLICY);
} catch (SMSException e) {
throw new PolicyException(e);
} catch (SSOException e) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
}
return rConfig;
}
private void addRuleToResourceTree(String policyName, Rule rule)
throws PolicyException, SSOException {
// to do: investigate this
String resourceName = rule.getResourceName();
String serviceTypeName = rule.getServiceTypeName();
ServiceType st = rule.getServiceType();
if (resourceName == null || resourceName.length() == 0) {
resourceName = EMPTY_RESOURCE_NAME;
}
ServiceConfig resources = getResourcesServiceConfig(true);
if (resources == null) {
return;
}
ServiceConfig leafConfig = null;
try {
leafConfig = resources.getSubConfig(serviceTypeName);
} catch (SMSException e1) {
throw new PolicyException(e1);
}
if (leafConfig == null) {
// no resource node for this service type
try {
String newResourcesXml = rule.toResourcesXml(policyName);
Map newAttrs = new HashMap();
Set newSet = new HashSet();
newSet.add(newResourcesXml);
newAttrs.put(RESOURCES_XML, newSet);
resources.addSubConfig(
serviceTypeName,
PolicyManager.RESOURCES_POLICY_ID,
0,
newAttrs);
} catch (SMSException e2) {
throw new PolicyException(e2);
}
return;
}
// else, see if the attribute is there and non-empty
Map existingAttrs = null;
existingAttrs = leafConfig.getAttributes();
if ((existingAttrs == null) ||
(!existingAttrs.containsKey(RESOURCES_XML))) {
try {
String newResourcesXml = rule.toResourcesXml(policyName);
Set newSet = new HashSet();
newSet.add(newResourcesXml);
leafConfig.addAttribute(RESOURCES_XML, newSet);
} catch (SMSException e4) {
throw new PolicyException(e4);
}
return;
}
// else, need to look into the attribute
Set existingRes = (Set) existingAttrs.get(RESOURCES_XML);
if (existingRes.isEmpty()) {
try {
String newResourcesXml = rule.toResourcesXml(policyName);
Map newAttrs = new HashMap();
Set newSet = new HashSet();
newSet.add(newResourcesXml);
newAttrs.put(RESOURCES_XML, newSet);
leafConfig.setAttributes(newAttrs);
} catch (SMSException e5) {
throw new PolicyException(e5);
}
return;
}
// else, the attribute really contains something
Object[] retVal = getXMLRootNode(existingRes);
Node rootNode = (Node)retVal[0];
Document doc = (Document)retVal[1];
boolean modified =
matchAndAddReferenceNode(
doc, rootNode, resourceName, policyName, st);
if (!modified) {
return;
}
// finally reset the modified xml content
String modifiedResourcesXml =
SMSSchema.nodeToString(rootNode);
Map modifiedAttrs = new HashMap();
Set modifiedSet = new HashSet();
modifiedSet.add(modifiedResourcesXml);
modifiedAttrs.put(RESOURCES_XML, modifiedSet);
try {
leafConfig.setAttributes(modifiedAttrs);
} catch (SMSException e6) {
throw new PolicyException(e6);
}
}
private void removeRuleFromResourceTree(
String policyName, String resourceName,
String serviceTypeName, ServiceType st)
throws PolicyException, SSOException {
if (resourceName == null || resourceName.length() == 0) {
resourceName = EMPTY_RESOURCE_NAME;
}
ServiceConfig resources = getResourcesServiceConfig(false);
if (resources == null) {
return;
}
ServiceConfig leafConfig = null;
try {
leafConfig =
resources.getSubConfig(serviceTypeName);
} catch (SMSException e1) {
throw new PolicyException(e1);
}
if (leafConfig == null) {
// no resource node for this service type
return;
}
// else, see if the attribute is there and non-empty
Map existingAttrs = null;
existingAttrs = leafConfig.getAttributes();
if ((existingAttrs == null) ||
(!existingAttrs.containsKey(RESOURCES_XML))) {
return;
}
// else, need to look into the attribute
int n = existingAttrs.size();
Set existingRes = (Set) existingAttrs.get(RESOURCES_XML);
if (existingRes.isEmpty()) {
return;
}
// else, the attribute really contains something
Object[] retVal = getXMLRootNode(existingRes);
Node rootNode = (Node)retVal[0];
boolean modified =
matchAndRemoveReferenceNode(
rootNode, resourceName, policyName,
st, new Stack());
if (!modified) {
return;
}
if (!rootNode.hasChildNodes()) {
try {
leafConfig.removeAttribute(RESOURCES_XML);
if (n == 1) {
resources.removeSubConfig(serviceTypeName);
}
return;
} catch (SMSException e3) {
throw new PolicyException(e3);
}
}
// finally reset the modified xml content
String modifiedResourcesXml =
SMSSchema.nodeToString(rootNode);
Map modifiedAttrs = new HashMap();
Set modifiedSet = new HashSet();
modifiedSet.add(modifiedResourcesXml);
modifiedAttrs.put(RESOURCES_XML, modifiedSet);
try {
leafConfig.setAttributes(modifiedAttrs);
} catch (SMSException e4) {
throw new PolicyException(e4);
}
}
private boolean matchAndAddReferenceNode(
Document doc, Node node, String resource,
String policyName, ServiceType st)
throws PolicyException {
boolean modified = true;
Set referenceNodes = XMLUtils.getChildNodes(
node, PolicyManager.POLICY_INDEX_REFERENCE_NODE);
if (referenceNodes == null ||
referenceNodes.isEmpty()) {
addReferenceNodes(
doc, node, resource, policyName, st);
return modified;
}
Iterator items = referenceNodes.iterator();
Node referenceNode = null;
String referenceName = null;
ResourceMatch matchResult = null;
boolean hasMatch = false;
// iterating through each reference node
while (items.hasNext()) {
referenceNode = (Node) items.next();
referenceName =
XMLUtils.getNodeAttributeValue(
referenceNode,
PolicyManager.POLICY_INDEX_REFERENCE_NODE_NAME_ATTR);
matchResult = st.compare(resource, referenceName);
if (matchResult.equals(ResourceMatch.EXACT_MATCH)) {
hasMatch = true;
Set pNames = getPolicyNames(referenceNode);
if (pNames.contains(policyName)) {
modified = false;
break;
}
// else
addPolicyNameNode(doc, referenceNode, policyName);
break;
}
if (matchResult.equals(ResourceMatch.SUPER_RESOURCE_MATCH)) {
hasMatch = true;
String subResource = st.getSubResource(resource, referenceName);
modified = matchAndAddReferenceNode(doc, referenceNode,
subResource, policyName, st);
break;
}
}
if (!hasMatch) {
// didn't find any match, need to add (a) reference node(s)
addReferenceNodes(doc, node, resource, policyName, st);
}
return modified;
}
private boolean matchAndRemoveReferenceNode(
Node node, String resource,
String policyName, ServiceType st, Stack stack)
throws PolicyException {
Set referenceNodes = XMLUtils.getChildNodes(
node, PolicyManager.POLICY_INDEX_REFERENCE_NODE);
if (referenceNodes == null || referenceNodes.isEmpty()) {
return false;
}
Iterator items = referenceNodes.iterator();
Node referenceNode = null;
String referenceName = null;
ResourceMatch matchResult = null;
// iterating through each reference node
while (items.hasNext()) {
referenceNode = (Node) items.next();
referenceName =
XMLUtils.getNodeAttributeValue(
referenceNode,
PolicyManager.POLICY_INDEX_REFERENCE_NODE_NAME_ATTR);
matchResult = st.compare(resource, referenceName);
if (matchResult.equals(ResourceMatch.EXACT_MATCH)) {
stack.push(node);
return removePolicyNameNode(referenceNode, policyName,
stack);
}
if (matchResult.equals(ResourceMatch.SUPER_RESOURCE_MATCH)) {
String subResource = st.getSubResource(resource, referenceName);
stack.push(node);
return matchAndRemoveReferenceNode(
referenceNode, subResource,
policyName, st, stack);
}
}
return false;
}
private void addPolicyNameNode(Document doc,
Node referenceNode,
String policyName)
throws PolicyException {
Element element =
doc.createElement(
PolicyManager.POLICY_INDEX_POLICYNAME_NODE);
element.setAttribute(
PolicyManager.POLICY_INDEX_POLICYNAME_NODE_NAME_ATTR,
policyName);
referenceNode.appendChild(element);
}
private boolean removePolicyNameNode(Node referenceNode,
String policyName,
Stack stack)
throws PolicyException {
Set policyNameNodes =
XMLUtils.getChildNodes(
referenceNode,
PolicyManager.POLICY_INDEX_POLICYNAME_NODE);
Iterator items = policyNameNodes.iterator();
Node policyNameNode = null;
String policyNameAttr = null;
while (items.hasNext()) {
policyNameNode = (Node) items.next();
policyNameAttr =
XMLUtils.getNodeAttributeValue(
policyNameNode,
PolicyManager.POLICY_INDEX_POLICYNAME_NODE_NAME_ATTR);
if (policyNameAttr.equals(policyName)) {
referenceNode.removeChild(policyNameNode);
removeReferenceNodes(referenceNode, stack);
return true;
}
}
return false;
}
private void addReferenceNodes(Document doc,
Node parentNode,
String resourceName,
String policyName,
ServiceType st)
throws PolicyException {
String[] resources = st.split(resourceName);
int n = resources.length;
if ( n < 1 ) {
return;
}
Element[] nodes = new Element[n];
Element policyNameNode =
doc.createElement(
PolicyManager.POLICY_INDEX_POLICYNAME_NODE);
policyNameNode.setAttribute(
PolicyManager.POLICY_INDEX_POLICYNAME_NODE_NAME_ATTR,
policyName);
nodes[n-1] =
doc.createElement(
PolicyManager.POLICY_INDEX_REFERENCE_NODE);
nodes[n-1].setAttribute(
PolicyManager.POLICY_INDEX_REFERENCE_NODE_NAME_ATTR,
resources[n-1]);
nodes[n-1].appendChild(policyNameNode);
for (int i=n-2; i>=0; i--) {
nodes[i] =
doc.createElement(
PolicyManager.POLICY_INDEX_REFERENCE_NODE);
nodes[i].setAttribute(
PolicyManager.POLICY_INDEX_REFERENCE_NODE_NAME_ATTR,
resources[i]);
nodes[i].appendChild(nodes[i+1]);
}
parentNode.appendChild(nodes[0]);
}
private void removeReferenceNodes(Node referenceNode,
Stack stack) {
if (!referenceNode.hasChildNodes() && !stack.empty()) {
Node parentRefNode = (Node) stack.pop();
parentRefNode.removeChild(referenceNode);
removeReferenceNodes(parentRefNode, stack);
}
}
/**
* Returns the xml root node for the service type's resources xml blob
*
* @param serviceType the service type which the resources xml blob is
* associated with
*
* @return root node for the resources xml content.
*
* @exception InvalidFormatException the retrieved resources
* from the data store have been corrupted or do not have a
* valid format.
* @exception NoPermissionException the user does not have sufficient
* privileges.
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
*/
Node getXMLRootNode(String serviceType)
throws InvalidFormatException, NoPermissionException,
PolicyException {
if (PolicyManager.debug.messageEnabled()) {
PolicyManager.debug.message(
"searching for resources of the service type: " +
serviceType + " in organization: " + org);
}
try {
ServiceConfig policyResources = getResourcesServiceConfig(false);
if (policyResources == null) {
if (PolicyManager.debug.messageEnabled()) {
PolicyManager.debug.message(
"Resources branch is non-existent" +
" in organization: " + org);
}
return null;
}
ServiceConfig serviceResources =
policyResources.getSubConfig(serviceType);
if (serviceResources == null) {
if (PolicyManager.debug.warningEnabled()) {
PolicyManager.debug.warning(
serviceType + " branch under Resources is null" +
" in organization: " + org);
}
return null;
}
// Obtain the attributes
Map attrs = serviceResources.getAttributes();
Set res = null;
if (attrs != null) {
res = (Set) attrs.get(RESOURCES_XML);
}
if (res == null) {
if (PolicyManager.debug.warningEnabled()){
PolicyManager.debug.warning(
"Unable to find resources attribute for the service: "+
serviceType + " under Resources in organization: "+
org);
}
return null;
}
// Get the XML blob
if (res.isEmpty()) {
if (PolicyManager.debug.warningEnabled()) {
PolicyManager.debug.warning(
"Unable to find resources attribute value for " +
"the service: " + serviceType + " in organization: " +
org);
}
return null;
}
Object[] retVal = getXMLRootNode(res);
return ((Node)retVal[0]);
} catch (SMSException se) {
PolicyManager.debug.error(
"Unable to get resources of the service type: " +
serviceType + " in organization" + org);
String objs[] = { serviceType, org };
if (se.getExceptionCode() == SMSException.STATUS_NO_PERMISSION) {
throw new NoPermissionException(ResBundleUtils.rbName,
"unable_to_get_resources_for_service", objs);
} else {
throw new PolicyException(se);
}
} catch (SSOException ssoe) {
throw new PolicyException(
ResBundleUtils.rbName,"invalid_sso_token", null, null);
}
}
private Object[] getXMLRootNode(Set xmlBlob)
throws PolicyException {
Iterator it = xmlBlob.iterator();
String resourcesXml = (String) it.next();
Document doc = null;
try {
doc = XMLUtils.getXMLDocument(
new ByteArrayInputStream(resourcesXml.getBytes("UTF8")));
} catch (Exception xmle) {
debug.error("XML parsing error for resourcesXml");
throw (new PolicyException(xmle));
}
Node rootNode = XMLUtils.getRootNode(
doc, PolicyManager.POLICY_INDEX_ROOT_NODE);
if (rootNode == null) {
PolicyManager.debug.error(
"invalid (no root node) xml resources blob: " +
resourcesXml);
throw new InvalidFormatException(
ResBundleUtils.rbName, "invalid_resources_blob_no_root",
null, "",
PolicyException.SERVICE);
}
/*****
if (!rootNode.getNodeName().equalsIgnoreCase(
PolicyManager.POLICY_INDEX_ROOT_NODE))
throw (new InvalidFormatException());
******/
String referenceType = XMLUtils.getNodeAttributeValue(
rootNode,
PolicyManager.POLICY_INDEX_ROOT_NODE_TYPE_ATTR);
if (!referenceType.equals(
PolicyManager.POLICY_INDEX_ROOT_NODE_TYPE_ATTR_RESOURCES_VALUE)) {
PolicyManager.debug.error(
"invalid (no type attr for PolicyCrossReference element) "+
"xml resources blob: " + resourcesXml);
throw new InvalidFormatException(
ResBundleUtils.rbName, "invalid_resources_blob_no_type",
null, "", PolicyException.SERVICE);
}
if (PolicyManager.debug.messageEnabled())
PolicyManager.debug.message("returning XML root node");
Object[] retVal = new Object[2];
retVal[0] = rootNode;
retVal[1] = doc;
return retVal;
}
/**
* this method recursively finds the names of the policies corresponding
* to the resource. Depending on the boolean input parameter, it would
* either returns all the policies including those for super resources,
* or, just returns the policies at the final level with exact match or
* the closest match
*/
private Set getPolicyNames(Node node,
String superRes,
ServiceType st,
String resource,
boolean includePoliciesForSuperResources) {
Set referenceNodes =
XMLUtils.getChildNodes(
node,
PolicyManager.POLICY_INDEX_REFERENCE_NODE);
Iterator items = referenceNodes.iterator();
Node referenceNode = null;
String referenceName = null;
String combinedName = null;
ResourceMatch matchResult = null;
while (items.hasNext()) {
referenceNode = (Node) items.next();
referenceName =
XMLUtils.getNodeAttributeValue(
referenceNode,
PolicyManager.POLICY_INDEX_REFERENCE_NODE_NAME_ATTR);
if (superRes == null) {
combinedName = referenceName;
} else {
combinedName = st.append(superRes, referenceName);
}
matchResult = st.compare(resource, combinedName);
if (matchResult.equals(ResourceMatch.EXACT_MATCH)) {
return getPolicyNames(referenceNode);
}
if (matchResult.equals(ResourceMatch.SUPER_RESOURCE_MATCH)) {
if (!includePoliciesForSuperResources) {
return getPolicyNames(referenceNode, combinedName,
st, resource, false);
}
Set policyNamesForTheReferenceNode =
getPolicyNames(referenceNode);
Set policyNamesForChildrenNodes =
getPolicyNames(referenceNode, combinedName,
st, resource, true);
if (policyNamesForChildrenNodes.isEmpty()) {
return policyNamesForTheReferenceNode;
}
if (policyNamesForTheReferenceNode.isEmpty()) {
return policyNamesForChildrenNodes;
}
policyNamesForTheReferenceNode.addAll(
policyNamesForChildrenNodes);
return policyNamesForTheReferenceNode;
}
}
// didn't find exact match, return policies for the last
// super-resource match
if ( !includePoliciesForSuperResources && superRes!=null ) {
return getPolicyNames(referenceNode);
}
return Collections.EMPTY_SET;
}
/**
* this method finds the names of policies in the first
* level of the node,
*/
private Set getPolicyNames(Node referenceNode) {
if ( referenceNode == null ) {
return Collections.EMPTY_SET;
}
Set policyNameNodes =
XMLUtils.getChildNodes(
referenceNode,
PolicyManager.POLICY_INDEX_POLICYNAME_NODE);
Iterator items = policyNameNodes.iterator();
Node policyNameNode = null;
String policyName = null;
Set retVal = new HashSet();
while (items.hasNext()) {
policyNameNode = (Node) items.next();
policyName =
XMLUtils.getNodeAttributeValue(
policyNameNode,
PolicyManager.POLICY_INDEX_POLICYNAME_NODE_NAME_ATTR);
retVal.add(policyName);
}
return retVal;
}
/**
* Adds specified resource prefixes for a certain service type
*
* @param serviceTypeName the service type name the resource prefixes are
* associated with
* @param resourcePrefixes the prefixes to be added
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
*/
void addResourcePrefixes(String serviceTypeName, Set resourcePrefixes)
throws PolicyException {
ServiceConfig resources = getResourcesServiceConfig(true);
if (resources == null) {
return;
}
ServiceConfig leafConfig = null;
try {
leafConfig = resources.getSubConfig(serviceTypeName);
} catch (SMSException e1) {
throw new PolicyException(e1);
} catch (SSOException e1) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
if (leafConfig == null) {
// no resource node for this service type
try {
Map newAttrs = new HashMap();
Set newSet = new HashSet();
Map prefixMap
= addResourcePrefixes(resourcePrefixes, new HashMap());
newSet.clear();
newSet.add(resourcePrefixesToXml(prefixMap));
//newSet.addAll(resourcePrefixes);
newAttrs.put(RESOURCE_PREFIXES, newSet);
resources.addSubConfig(
serviceTypeName,
PolicyManager.RESOURCES_POLICY_ID,
0,
newAttrs);
} catch (SMSException e2) {
throw new PolicyException(e2);
} catch (SSOException e) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
return;
}
// else, see if the attribute is there and non-empty
Map existingAttrs = null;
existingAttrs = leafConfig.getAttributes();
if ((existingAttrs == null) ||
(!existingAttrs.containsKey(RESOURCE_PREFIXES))) {
try {
Set newSet = new HashSet();
Map prefixMap
= addResourcePrefixes(resourcePrefixes, new HashMap());
newSet.clear();
newSet.add(resourcePrefixesToXml(prefixMap));
//newSet.addAll(resourcePrefixes);
leafConfig.addAttribute(RESOURCE_PREFIXES, newSet);
} catch (SMSException e4) {
throw new PolicyException(e4);
} catch (SSOException e) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
return;
}
// else, need to look into the attribute
Set existingRes = (Set) existingAttrs.get(RESOURCE_PREFIXES);
try {
Map newAttrs = new HashMap();
//existingRes.addAll(resourcePrefixes);
Map prefixMap = null;
if ( (existingRes != null) && (!existingRes.isEmpty()) ) {
String prefixXml = (String) (existingRes.iterator().next());
prefixMap = xmlToResourcePrefixes(prefixXml);
} else {
prefixMap = new HashMap();
}
prefixMap = addResourcePrefixes(resourcePrefixes, prefixMap);
Set newSet = new HashSet(1);
newSet.add(resourcePrefixesToXml(prefixMap));
newAttrs.put(RESOURCE_PREFIXES, newSet);
//newAttrs.put(RESOURCE_PREFIXES, existingRes);
leafConfig.setAttributes(newAttrs);
} catch (SMSException e5) {
throw new PolicyException(e5);
} catch (SSOException e) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
}
/**
* Removed specified resource prefixes for a certain service type
*
* @param serviceTypeName the service type name the resource prefixes are
* associated with
* @param resourcePrefixes the prefixes to be removed
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
*/
void removeResourcePrefixes(String serviceTypeName, Set resourcePrefixes)
throws PolicyException {
ServiceConfig resources = getResourcesServiceConfig(false);
if (resources == null) {
return;
}
ServiceConfig leafConfig = null;
try {
leafConfig = resources.getSubConfig(serviceTypeName);
} catch (SMSException e1) {
throw new PolicyException(e1);
} catch (SSOException e) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
if (leafConfig == null) {
// no resource node for this service type
return;
}
// else, see if the attribute is there and non-empty
Map existingAttrs = null;
existingAttrs = leafConfig.getAttributes();
if ((existingAttrs == null) ||
(!existingAttrs.containsKey(RESOURCE_PREFIXES))) {
return;
}
// else, need to look into the attribute
int n = existingAttrs.size();
Set existingSet = (Set) existingAttrs.get(RESOURCE_PREFIXES);
Map prefixMap = null;
if ( (existingSet != null) && (!existingSet.isEmpty()) ) {
String prefixXml = (String) (existingSet.iterator().next());
prefixMap = xmlToResourcePrefixes(prefixXml);
} else {
prefixMap = new HashMap();
}
Map newAttrs = new HashMap();
prefixMap = removeResourcePrefixes(resourcePrefixes, prefixMap);
Set newSet = new HashSet(1);
newSet.add(resourcePrefixesToXml(prefixMap));
newAttrs.put(RESOURCE_PREFIXES, newSet);
try {
/*
existingSet.removeAll(resourcePrefixes);
if (existingSet.isEmpty()) {
leafConfig.removeAttribute(RESOURCE_PREFIXES);
if (n == 1)
resources.removeSubConfig(serviceTypeName);
} else {
newAttrs.put(RESOURCE_PREFIXES, existingSet);
leafConfig.setAttributes(newAttrs);
}
*/
leafConfig.setAttributes(newAttrs);
} catch (SMSException e5) {
throw new PolicyException(e5);
} catch (SSOException e) {
throw (new PolicyException(ResBundleUtils.rbName,
"invalid_sso_token", null, null));
}
}
/**
* Returns the resource prefix (super-resource) and the rest of the
* resource name (sub-resource)
*
* @param serviceTypeName the service type which the resource is
* associated with
* @param resourceName the resource name to be split
*
* @return array of two strings, the first being the super-resource
* the second being the sub-resource
*
* @exception PolicyException if unable to get the policy services,
* and will contain the exception thrown by SMS.
* @exception NameNotFoundException service for the given <code>
* serviceTypeName</code> does not exist
* @exception SSOException single-sign-on token invalid or expired
*/
public String[] splitResourceName(
String serviceTypeName, String resourceName
) throws NameNotFoundException, SSOException, PolicyException {
ServiceType st = getServiceType(serviceTypeName);
Set prefixes = getManagedResourceNames(serviceTypeName);
String[] retVal = new String[2];
if (prefixes.isEmpty()) {
retVal[0] = "";
retVal[1] = resourceName;
return retVal;
}
Iterator iter = prefixes.iterator();
String tmp = null;
ResourceMatch matchResult = null;
boolean foundSuperMatch = false;
boolean foundExactMatch = false;
while (iter.hasNext()) {
tmp = (String) iter.next();
matchResult = st.compare(resourceName, tmp);
if (matchResult.equals(ResourceMatch.SUPER_RESOURCE_MATCH)) {
foundSuperMatch = true;
break;
}
if (matchResult.equals(ResourceMatch.EXACT_MATCH)) {
foundExactMatch = true;
break;
}
}
if (foundSuperMatch) {
retVal[0] = tmp;
retVal[1] = st.getSubResource(resourceName, tmp);
return retVal;
}
if (foundExactMatch) {
retVal[0] = tmp;
retVal[1] = "";
return retVal;
}
retVal[0] = "";
retVal[1] = resourceName;
return retVal;
}
/**
* Saves the resource index to data store
* @param resourceType resource type
* @param indexXML xml representation of index ( index to
* policies keyed by resource name, in a tree structure)
* @throws PolicyException
* @throws SSOException
*/
void saveResourceIndex(String resourceType, String indexXML)
throws PolicyException ,SSOException {
Map newAttrs = new HashMap();
Set newSet = new HashSet();
newSet.add(indexXML);
newAttrs.put(RESOURCES_XML, newSet);
ServiceConfig resources = getResourcesServiceConfig(true);
if (resources != null) {
ServiceConfig leafConfig = null;
try {
leafConfig = resources.getSubConfig(resourceType);
if (leafConfig == null) {
// no resource node for this service type
resources.addSubConfig(
resourceType,
PolicyManager.RESOURCES_POLICY_ID,
0,
newAttrs);
} else {
leafConfig.setAttributes(newAttrs);
}
} catch (SMSException e1) {
throw new PolicyException(e1);
}
}
}
/**
* Converts xml representation of resource prefixes
* to a map representation
* Key in the map is the prefix and the value is
* a count of how many times the prefix has been
* effectively added. The count is incremented whenever
* the prefix is added and decremented whenever
* the prefix is removed. The count is not decremented
* below 0.
* @param xmlResourcePrefixes xml representation of resource
* prefixes. This is how it is stored in datastore.
* @return map representation of resource prefixes.
*
*/
private Map xmlToResourcePrefixes(String xmlResourcePrefixes) {
Map resourcePrefixes = new HashMap();
try {
Document document = XMLUtils.getXMLDocument(
new ByteArrayInputStream(xmlResourcePrefixes.getBytes("UTF8")));
if ( (document != null) ) {
Node rootNode
= XMLUtils.getRootNode(document, RESOURCE_PREFIXES);
if ( rootNode != null ) {
Set nodeSet
= XMLUtils.getChildNodes(rootNode, PREFIX);
if ( nodeSet != null ) {
Iterator nodes = nodeSet.iterator();
while (nodes.hasNext()) {
Node node = (Node)nodes.next();
String prefix
= XMLUtils.getNodeAttributeValue(node,
NAME);
String count
= XMLUtils.getNodeAttributeValue(node,
COUNT);
if ( (prefix != null) && (count != null) ) {
resourcePrefixes.put(prefix, count);
}
}
}
}
}
} catch (Exception xmle) {
PolicyManager.debug.error("XML parsing error for resource prefixes "
+ " in organization: " + org);
}
return resourcePrefixes;
}
/**
* Converts map representation of resource prefixes
* to an xml representation
* @param resourcePrefixes map representation of resource
* prefixes
* @return xml representation of resource prefixes
*
*/
private static String resourcePrefixesToXml(Map resourcePrefixes) {
StringBuilder sb = new StringBuilder(128);
sb.append(LTS).append(RESOURCE_PREFIXES).append(GTS)
.append(NEW_LINE);
Iterator prefixes = resourcePrefixes.keySet().iterator();
while ( prefixes.hasNext() ) {
String prefix = (String) prefixes.next();
String value = (String) resourcePrefixes.get(prefix);
sb.append(LTS).append(PREFIX).append(SPACE)
.append(NAME).append(EQUALS)
.append(QUOTE).append(
XMLUtils.escapeSpecialCharacters(prefix))
.append(QUOTE).append(SPACE)
.append(COUNT).append(EQUALS)
.append(QUOTE).append(value).append(QUOTE)
.append(SGTS).append(NEW_LINE);
}
sb.append(LTSS).append(RESOURCE_PREFIXES).append(GTS)
.append(NEW_LINE);
return sb.toString();
}
/**
* Adds a set of resource prefixes to a map of resource prefixes.
* Adding a prefix increments the the count for the prefix
* in map value.
* @param prefixes a set of resource prefixes to add
* @param prefixMap a map of resource prefixes to which to
* add the prefixes.
* @return prefixMap modified accounting for the addition
* of prefixes
*
*/
private Map addResourcePrefixes(Set prefixes, Map prefixMap) {
Iterator iter = prefixes.iterator();
while ( iter.hasNext() ) {
String prefix = (String) iter.next();
int intValue = 0;
String count = (String) prefixMap.get(prefix);
if ( count != null ) {
try {
intValue = Integer.parseInt(count);
} catch (Exception e) {
PolicyManager.debug.error(
"ResourceManager.addResourcePrefixes:", e);
}
}
intValue++;
prefixMap.put(prefix, Integer.toString(intValue));
}
return prefixMap;
}
/**
* Removes a set of resource prefixes from a map of resource prefixes.
* Removing a prefix decrements the count for the prefix in the
* map value. Count value is not decremented below 0.
* @param prefixes a set of resource prefixes to remove
* @param prefixMap a map of resource prefixes from which to
* remove the prefixes.
* @return prefixMap modified accounting for the removal
* of prefixes.
*/
private Map removeResourcePrefixes(Set prefixes, Map prefixMap) {
Iterator iter = prefixes.iterator();
while ( iter.hasNext() ) {
String prefix = (String) iter.next();
int intValue = 0;
String count = (String) prefixMap.get(prefix);
if ( count != null ) {
try {
intValue = Integer.parseInt(count);
} catch (Exception e) {
PolicyManager.debug.error(
"ResourceManager.removeResourcePrefixes:", e);
}
}
intValue--;
if ( intValue > 0 ) {
prefixMap.put(prefix, Integer.toString(intValue));
} else {
prefixMap.remove(prefix);
}
}
return prefixMap;
}
}