/*
* 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;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xerces.impl.Constants;
import org.apache.xerces.util.SecurityManager;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.wso2.balana.AbstractPolicy;
import org.wso2.balana.Balana;
import org.wso2.balana.ParsingException;
import org.wso2.balana.Policy;
import org.wso2.balana.PolicySet;
import org.wso2.balana.XACMLConstants;
import org.wso2.balana.attr.AttributeValue;
import org.wso2.balana.attr.BooleanAttribute;
import org.wso2.balana.attr.DateAttribute;
import org.wso2.balana.attr.DateTimeAttribute;
import org.wso2.balana.attr.DoubleAttribute;
import org.wso2.balana.attr.HexBinaryAttribute;
import org.wso2.balana.attr.IntegerAttribute;
import org.wso2.balana.attr.StringAttribute;
import org.wso2.balana.attr.TimeAttribute;
import org.wso2.balana.combine.PolicyCombiningAlgorithm;
import org.wso2.balana.combine.xacml2.FirstApplicablePolicyAlg;
import org.wso2.balana.combine.xacml2.OnlyOneApplicablePolicyAlg;
import org.wso2.balana.combine.xacml3.DenyOverridesPolicyAlg;
import org.wso2.balana.combine.xacml3.DenyUnlessPermitPolicyAlg;
import org.wso2.balana.combine.xacml3.OrderedDenyOverridesPolicyAlg;
import org.wso2.balana.combine.xacml3.OrderedPermitOverridesPolicyAlg;
import org.wso2.balana.combine.xacml3.PermitOverridesPolicyAlg;
import org.wso2.balana.combine.xacml3.PermitUnlessDenyPolicyAlg;
import org.wso2.balana.ctx.AbstractRequestCtx;
import org.wso2.balana.ctx.Attribute;
import org.wso2.balana.xacml3.Attributes;
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.common.EntitlementConstants;
import org.wso2.carbon.identity.entitlement.dto.AttributeDTO;
import org.wso2.carbon.identity.entitlement.dto.PolicyDTO;
import org.wso2.carbon.identity.entitlement.dto.PolicyStoreDTO;
import org.wso2.carbon.identity.entitlement.internal.EntitlementExtensionBuilder;
import org.wso2.carbon.identity.entitlement.internal.EntitlementServiceComponent;
import org.wso2.carbon.identity.entitlement.pap.EntitlementAdminEngine;
import org.wso2.carbon.identity.entitlement.pap.store.PAPPolicyStore;
import org.wso2.carbon.identity.entitlement.pap.store.PAPPolicyStoreManager;
import org.wso2.carbon.identity.entitlement.pap.store.PAPPolicyStoreReader;
import org.wso2.carbon.identity.entitlement.policy.publisher.PolicyPublisher;
import org.wso2.carbon.identity.entitlement.policy.store.PolicyStoreManageModule;
import org.wso2.carbon.identity.entitlement.policy.version.PolicyVersionManager;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.identity.entitlement.util.CarbonEntityResolver;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
import javax.xml.XMLConstants;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Provides utility functionalities used across different classes.
*/
public class EntitlementUtil {
private static Log log = LogFactory.getLog(EntitlementUtil.class);
private static final String SECURITY_MANAGER_PROPERTY = Constants.XERCES_PROPERTY_PREFIX +
Constants.SECURITY_MANAGER_PROPERTY;
private static final int ENTITY_EXPANSION_LIMIT = 0;
public static final String EXTERNAL_GENERAL_ENTITIES_URI = "http://xml.org/sax/features/external-general-entities";
/**
* Return an instance of a named cache that is common to all tenants.
*
* @param name the name of the cache.
* @return the named cache instance.
*/
public static EntitlementBaseCache<IdentityCacheKey, IdentityCacheEntry> getCommonCache(String name) {
// TODO Should verify the cache creation done per tenant or as below
// We create a single cache for all tenants. It is not a good choice to create per-tenant
// caches in this case. We qualify tenants by adding the tenant identifier in the cache key.
// PrivilegedCarbonContext currentContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
// PrivilegedCarbonContext.startTenantFlow();
// try {
// currentContext.setTenantId(MultitenantConstants.SUPER_TENANT_ID);
// return CacheManager.getInstance().getCache(name);
// } finally {
// PrivilegedCarbonContext.endTenantFlow();
// }
return new EntitlementBaseCache<IdentityCacheKey, IdentityCacheEntry>(name);
}
/**
* Return the Attribute Value Object for given string value and data type
*
* @param value attribute value as a String object
* @param type attribute data type name as String object
* @return Attribute Value Object
* @throws EntitlementException throws
*/
public static AttributeValue getAttributeValue(final String value, String type)
throws EntitlementException {
try {
if (StringAttribute.identifier.equals(type)) {
return new StringAttribute(value);
}
if (IntegerAttribute.identifier.equals(type)) {
return new IntegerAttribute(Long.parseLong(value));
}
if (BooleanAttribute.identifier.equals(type)) {
return BooleanAttribute.getInstance(value);
}
if (DoubleAttribute.identifier.equals(type)) {
return new DoubleAttribute(Double.parseDouble(value));
}
if (DateAttribute.identifier.equals(type)) {
return new DateAttribute(DateFormat.getDateInstance().parse(value));
}
if (DateTimeAttribute.identifier.equals(type)) {
return new DateTimeAttribute(DateFormat.getDateInstance().parse(value));
}
if (TimeAttribute.identifier.equals(type)) {
return TimeAttribute.getInstance(value);
}
if (HexBinaryAttribute.identifier.equals(type)) {
return new HexBinaryAttribute(value.getBytes());
}
return new AttributeValue(new URI(type)) {
@Override
public String encode() {
return value;
}
};
} catch (ParsingException e) {
throw new EntitlementException("Error while creating AttributeValue object for given " +
"string value and data type");
} catch (ParseException e) {
throw new EntitlementException("Error while creating AttributeValue object for given " +
"string value and data type");
} catch (URISyntaxException e) {
throw new EntitlementException("Error while creating AttributeValue object for given " +
"string value and data type");
}
}
/**
* This creates the XACML 3.0 Request context from AttributeDTO object model
*
* @param attributeDTOs AttributeDTO objects as List
* @return DOM element as XACML request
* @throws EntitlementException throws, if fails
*/
public static AbstractRequestCtx createRequestContext(List<AttributeDTO> attributeDTOs) {
Set<Attributes> attributesSet = new HashSet<Attributes>();
for (AttributeDTO DTO : attributeDTOs) {
Attributes attributes = getAttributes(DTO);
if (attributes != null) {
attributesSet.add(attributes);
}
}
return new org.wso2.balana.ctx.xacml3.RequestCtx(attributesSet, null);
}
/**
* Validates the given policy XML files against the standard XACML policies.
*
* @param policy Policy to validate
* @return return false, If validation failed or XML parsing failed or any IOException occurs
*/
public static boolean validatePolicy(PolicyDTO policy) {
try {
if (!"true".equalsIgnoreCase((String) EntitlementServiceComponent.getEntitlementConfig()
.getEngineProperties().get(EntitlementExtensionBuilder.PDP_SCHEMA_VALIDATION))) {
return true;
}
// there may be cases where you only updated the policy meta data in PolicyDTO not the
// actual XACML policy String
if (policy.getPolicy() == null || policy.getPolicy().trim().length() < 1) {
return true;
}
//get policy version
String policyXMLNS = getPolicyVersion(policy.getPolicy());
Map<String, Schema> schemaMap = EntitlementServiceComponent.
getEntitlementConfig().getPolicySchemaMap();
//load correct schema by version
Schema schema = schemaMap.get(policyXMLNS);
if (schema != null) {
//build XML document
DocumentBuilder documentBuilder = getSecuredDocumentBuilder(false);
InputStream stream = new ByteArrayInputStream(policy.getPolicy().getBytes());
Document doc = documentBuilder.parse(stream);
//Do the DOM validation
DOMSource domSource = new DOMSource(doc);
DOMResult domResult = new DOMResult();
Validator validator = schema.newValidator();
validator.validate(domSource, domResult);
if (log.isDebugEnabled()) {
log.debug("XACML Policy validation succeeded with the Schema");
}
return true;
} else {
log.error("Invalid Namespace in policy");
}
} catch (SAXException e) {
log.error("XACML policy is not valid according to the schema :" + e.getMessage());
} catch (IOException e) {
//ignore
} catch (ParserConfigurationException e) {
//ignore
}
return false;
}
public static String getPolicyVersion(String policy) {
try {
//build XML document
DocumentBuilder documentBuilder = getSecuredDocumentBuilder(false);
InputStream stream = new ByteArrayInputStream(policy.getBytes());
Document doc = documentBuilder.parse(stream);
//get policy version
Element policyElement = doc.getDocumentElement();
return policyElement.getNamespaceURI();
} catch (Exception e) {
log.debug(e);
// ignore exception as default value is used
log.warn("Policy version can not be identified. Default XACML 3.0 version is used");
return XACMLConstants.XACML_3_0_IDENTIFIER;
}
}
public static Attributes getAttributes(AttributeDTO attributeDataDTO) {
try {
AttributeValue value = Balana.getInstance().getAttributeFactory().
createValue(new URI(attributeDataDTO.getAttributeDataType()),
attributeDataDTO.getAttributeValue());
Attribute attribute = new Attribute(new URI(attributeDataDTO.getAttributeId()),
null, null, value, XACMLConstants.XACML_VERSION_3_0);
Set<Attribute> set = new HashSet<Attribute>();
set.add(attribute);
String category = attributeDataDTO.getCategory();
// We are only creating XACML 3.0 requests Therefore covert order XACML categories to new uris
if (PDPConstants.SUBJECT_ELEMENT.equals(category)) {
category = PDPConstants.SUBJECT_CATEGORY_URI;
} else if (PDPConstants.RESOURCE_ELEMENT.equals(category)) {
category = PDPConstants.RESOURCE_CATEGORY_URI;
} else if (PDPConstants.ACTION_ELEMENT.equals(category)) {
category = PDPConstants.ACTION_CATEGORY_URI;
} else if (PDPConstants.ENVIRONMENT_ELEMENT.equals(category)) {
category = PDPConstants.ENVIRONMENT_CATEGORY_URI;
}
return new Attributes(new URI(category), set);
} catch (Exception e) {
log.debug(e);
//ignore and return null;
}
return null;
}
/**
* Creates PolicyCombiningAlgorithm object based on policy combining url
*
* @param uri policy combining url as String
* @return PolicyCombiningAlgorithm object
* @throws EntitlementException throws if unsupported algorithm
*/
public static PolicyCombiningAlgorithm getPolicyCombiningAlgorithm(String uri)
throws EntitlementException {
if (FirstApplicablePolicyAlg.algId.equals(uri)) {
return new FirstApplicablePolicyAlg();
} else if (DenyOverridesPolicyAlg.algId.equals(uri)) {
return new DenyOverridesPolicyAlg();
} else if (PermitOverridesPolicyAlg.algId.equals(uri)) {
return new PermitOverridesPolicyAlg();
} else if (OnlyOneApplicablePolicyAlg.algId.equals(uri)) {
return new OnlyOneApplicablePolicyAlg();
} else if (OrderedDenyOverridesPolicyAlg.algId.equals(uri)) {
return new OrderedDenyOverridesPolicyAlg();
} else if (OrderedPermitOverridesPolicyAlg.algId.equals(uri)) {
return new OrderedPermitOverridesPolicyAlg();
} else if (DenyUnlessPermitPolicyAlg.algId.equals(uri)) {
return new DenyUnlessPermitPolicyAlg();
} else if (PermitUnlessDenyPolicyAlg.algId.equals(uri)) {
return new PermitUnlessDenyPolicyAlg();
}
throw new EntitlementException("Unsupported policy algorithm " + uri);
}
/**
* Creates Simple XACML request using given attribute value.Here category, attribute ids and datatypes are
* taken as default values.
*
* @param subject user or role
* @param resource resource name
* @param action action name
* @param environment environment name
* @return String XACML request as String
*/
public static String createSimpleXACMLRequest(String subject, String resource, String action, String environment) {
return "<Request xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" CombinedDecision=\"false\" ReturnPolicyIdList=\"false\">\n" +
"<Attributes Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:action\">\n" +
"<Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:action:action-id\" IncludeInResult=\"false\">\n" +
"<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">" + action + "</AttributeValue>\n" +
"</Attribute>\n" +
"</Attributes>\n" +
"<Attributes Category=\"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\">\n" +
"<Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject:subject-id\" IncludeInResult=\"false\">\n" +
"<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">" + subject + "</AttributeValue>\n" +
"</Attribute>\n" +
"</Attributes>\n" +
"<Attributes Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\">\n" +
"<Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:environment:environment-id\" IncludeInResult=\"false\">\n" +
"<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">" + environment + "</AttributeValue>\n" +
"</Attribute>\n" +
"</Attributes>\n" +
"<Attributes Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\">\n" +
"<Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:resource:resource-id\" IncludeInResult=\"false\">\n" +
"<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">" + resource + "</AttributeValue>\n" +
"</Attribute>\n" +
"</Attributes>\n" +
"</Request> ";
}
public static void addSamplePolicies(Registry registry) {
File policyFolder = new File(CarbonUtils.getCarbonHome() + File.separator
+ "repository" + File.separator + "resources" + File.separator
+ "identity" + File.separator + "policies" + File.separator + "xacml"
+ File.separator + "default");
if (policyFolder.exists()) {
for (File policyFile : policyFolder.listFiles()) {
if (policyFile.isFile()) {
PolicyDTO policyDTO = new PolicyDTO();
try {
policyDTO.setPolicy(FileUtils.readFileToString(policyFile));
EntitlementUtil.addFilesystemPolicy(policyDTO, registry, false);
} catch (Exception e) {
// log and ignore
log.error("Error while adding sample XACML policies", e);
}
}
}
}
}
/**
* This method checks whether there is a policy having the same policyId as the given policyId is in the registry
*
* @param policyId
* @param registry
* @return
* @throws EntitlementException
*/
public static boolean isPolicyExists(String policyId, Registry registry) throws EntitlementException {
PAPPolicyStoreReader policyReader = null;
policyReader = new PAPPolicyStoreReader(new PAPPolicyStore(registry));
return policyReader.isExistPolicy(policyId);
}
/**
* This method persists a new XACML policy, which was read from filesystem,
* in the registry
*
* @param policyDTO PolicyDTO object
* @param registry Registry
* @param promote where policy must be promote PDP or not
* @return returns whether True/False
* @throws org.wso2.carbon.identity.entitlement.EntitlementException throws if policy with same id is exist
*/
public static boolean addFilesystemPolicy(PolicyDTO policyDTO,
Registry registry, boolean promote)
throws EntitlementException {
PAPPolicyStoreManager policyAdmin;
AbstractPolicy policyObj;
if (policyDTO.getPolicy() != null) {
policyDTO.setPolicy(policyDTO.getPolicy().replaceAll(">\\s+<", "><"));
}
policyObj = getPolicy(policyDTO.getPolicy());
if (policyObj != null) {
PAPPolicyStore policyStore = new PAPPolicyStore(registry);
policyAdmin = new PAPPolicyStoreManager();
policyDTO.setPolicyId(policyObj.getId().toASCIIString());
policyDTO.setActive(true);
if (isPolicyExists(policyDTO.getPolicyId(), registry)) {
throw new EntitlementException(
"An Entitlement Policy with the given ID already exists");
}
policyDTO.setPromote(promote);
PolicyVersionManager versionManager = EntitlementAdminEngine.getInstance().getVersionManager();
try {
String version = versionManager.createVersion(policyDTO);
policyDTO.setVersion(version);
} catch (EntitlementException e) {
log.error("Policy versioning is not supported", e);
}
policyAdmin.addOrUpdatePolicy(policyDTO);
PAPPolicyStoreReader reader = new PAPPolicyStoreReader(policyStore);
policyDTO = reader.readPolicyDTO(policyDTO.getPolicyId());
PolicyStoreDTO policyStoreDTO = new PolicyStoreDTO();
policyStoreDTO.setPolicyId(policyDTO.getPolicyId());
policyStoreDTO.setPolicy(policyDTO.getPolicy());
policyStoreDTO.setPolicyOrder(policyDTO.getPolicyOrder());
policyStoreDTO.setAttributeDTOs(policyDTO.getAttributeDTOs());
policyStoreDTO.setActive(policyDTO.isActive());
policyStoreDTO.setSetActive(policyDTO.isActive());
if (promote) {
addPolicyToPDP(policyStoreDTO);
}
policyAdmin.addOrUpdatePolicy(policyDTO);
return true;
} else {
throw new EntitlementException("Invalid Entitlement Policy");
}
}
public static AbstractPolicy getPolicy(String policy) {
DocumentBuilder builder;
InputStream stream = null;
// now use the factory to create the document builder
try {
builder = getSecuredDocumentBuilder(true);
stream = new ByteArrayInputStream(policy.getBytes("UTF-8"));
Document doc = builder.parse(stream);
Element root = doc.getDocumentElement();
String name = root.getTagName();
// see what type of policy this is
if (name.equals("Policy")) {
return Policy.getInstance(root);
} else if (name.equals("PolicySet")) {
return PolicySet.getInstance(root, null);
} else {
// this isn't a root type that we know how to handle
throw new ParsingException("Unknown root document type: " + name);
}
} catch (Exception e) {
throw new IllegalArgumentException("Error while parsing start up policy", e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
log.error("Error while closing input stream");
}
}
}
}
/**
* Gets policy dto for a given policy id
*
* @param policyId policy id
* @param registry Registry
* @return returns policy
* @throws org.wso2.carbon.identity.entitlement.EntitlementException
*/
public static PolicyDTO getPolicy(String policyId, Registry registry) throws EntitlementException {
PAPPolicyStoreReader policyReader = null;
policyReader = new PAPPolicyStoreReader(new PAPPolicyStore(registry));
return policyReader.readPolicyDTO(policyId);
}
/**
* @param policyStoreDTO
* @return
*/
public static void addPolicyToPDP(PolicyStoreDTO policyStoreDTO) throws EntitlementException {
Registry registry;
String policyPath;
Collection policyCollection;
Resource resource;
Map.Entry<PolicyStoreManageModule, Properties> entry = EntitlementServiceComponent
.getEntitlementConfig().getPolicyStore().entrySet().iterator().next();
String policyStorePath = entry.getValue().getProperty("policyStorePath");
if (policyStorePath == null) {
policyStorePath = "/repository/identity/entitlement/policy/pdp/";
}
if (policyStoreDTO == null || policyStoreDTO.getPolicy() == null
|| policyStoreDTO.getPolicy().trim().length() == 0
|| policyStoreDTO.getPolicyId() == null
|| policyStoreDTO.getPolicyId().trim().length() == 0) {
return;
}
try {
registry = EntitlementServiceComponent.getRegistryService()
.getGovernanceSystemRegistry();
if (registry.resourceExists(policyStorePath)) {
policyCollection = (Collection) registry.get(policyStorePath);
} else {
policyCollection = registry.newCollection();
}
registry.put(policyStorePath, policyCollection);
policyPath = policyStorePath + policyStoreDTO.getPolicyId();
if (registry.resourceExists(policyPath)) {
resource = registry.get(policyPath);
} else {
resource = registry.newResource();
}
resource.setProperty("policyOrder", Integer.toString(policyStoreDTO.getPolicyOrder()));
resource.setContent(policyStoreDTO.getPolicy());
resource.setMediaType("application/xacml-policy+xml");
resource.setProperty("active", String.valueOf(policyStoreDTO.isActive()));
AttributeDTO[] attributeDTOs = policyStoreDTO.getAttributeDTOs();
if (attributeDTOs != null) {
setAttributesAsProperties(attributeDTOs, resource);
}
registry.put(policyPath, resource);
//Enable published policies in PDP
PAPPolicyStoreManager storeManager = EntitlementAdminEngine.getInstance().getPapPolicyStoreManager();
if (storeManager.isExistPolicy(policyStoreDTO.getPolicyId())) {
PolicyPublisher publisher = EntitlementAdminEngine.getInstance().getPolicyPublisher();
String[] subscribers = new String[]{EntitlementConstants.PDP_SUBSCRIBER_ID};
if (policyStoreDTO.isActive()) {
publisher.publishPolicy(new String[]{policyStoreDTO.getPolicyId()}, null,
EntitlementConstants.PolicyPublish.ACTION_ENABLE, false, 0, subscribers, null);
} else {
publisher.publishPolicy(new String[]{policyStoreDTO.getPolicyId()}, null,
EntitlementConstants.PolicyPublish.ACTION_DISABLE, false, 0, subscribers, null);
}
}
} catch (RegistryException e) {
log.error(e);
throw new EntitlementException("Error while adding policy to PDP", e);
}
}
/**
* This helper method creates properties object which contains the policy meta data.
*
* @param attributeDTOs List of AttributeDTO
* @param resource registry resource
*/
public static void setAttributesAsProperties(AttributeDTO[] attributeDTOs, Resource resource) {
int attributeElementNo = 0;
if (attributeDTOs != null) {
for (AttributeDTO attributeDTO : attributeDTOs) {
resource.setProperty("policyMetaData" + attributeElementNo,
attributeDTO.getCategory() + "," +
attributeDTO.getAttributeValue() + "," +
attributeDTO.getAttributeId() + "," +
attributeDTO.getAttributeDataType());
attributeElementNo++;
}
}
}
/**
* * This method provides a secured document builder which will secure XXE attacks.
*
* @param setIgnoreComments whether to set setIgnoringComments in DocumentBuilderFactory.
* @return DocumentBuilder
* @throws ParserConfigurationException
*/
private static DocumentBuilder getSecuredDocumentBuilder(boolean setIgnoreComments) throws
ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setIgnoringComments(setIgnoreComments);
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setExpandEntityReferences(false);
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
documentBuilderFactory.setFeature(EXTERNAL_GENERAL_ENTITIES_URI, false);
SecurityManager securityManager = new SecurityManager();
securityManager.setEntityExpansionLimit(ENTITY_EXPANSION_LIMIT);
documentBuilderFactory.setAttribute(SECURITY_MANAGER_PROPERTY, securityManager);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
documentBuilder.setEntityResolver(new CarbonEntityResolver());
return documentBuilder;
}
}