blob: 6cc4f3d41af746d8e49bbdcfa98700da7253882c [file] [log] [blame]
/*
* Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.internal.helper;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.validation.SchemaFactory;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFactoryConfigurationException;
import org.eclipse.persistence.internal.oxm.OXMSystemProperties;
import org.eclipse.persistence.internal.oxm.record.XMLReader;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.SessionLog;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
public class XMLHelper {
// LJ - does not cache logger to allow its dynamic reconfiguration
// not in older JDK, so must be duplicated here, otherwise javax.xml.XMLConstants should be used
public static final String ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema";
public static final String ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD";
private static final String PROP_ACCESS_EXTERNAL_SCHEMA = "javax.xml.accessExternalSchema";
private static final String PROP_ACCESS_EXTERNAL_DTD = "javax.xml.accessExternalDTD";
/**
* If true XML security features when parsing XML documents will be disabled.
* The default value is false.
*
* Boolean
* @since 2.6.3
*/
private static final boolean XML_SECURITY_DISABLED = PrivilegedAccessHelper.getSystemPropertyBoolean(OXMSystemProperties.DISABLE_SECURE_PROCESSING, false);
private static boolean isXMLSecurityDisabled(boolean runtimeSetting) {
return XML_SECURITY_DISABLED || runtimeSetting;
}
/**
* Returns properly configured (e.g. security features) schema factory
* - namespaceAware == true
* - securityProcessing == is set based on security processing property, default is true
*/
public static SchemaFactory createSchemaFactory(final String language, boolean disableSecureProcessing) throws IllegalStateException {
SessionLog logger = AbstractSessionLog.getLog();
try {
SchemaFactory factory = SchemaFactory.newInstance(language);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "schema_factory", new Object[] {factory});
}
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, !isXMLSecurityDisabled(disableSecureProcessing));
return factory;
} catch (SAXNotRecognizedException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException(ex);
} catch (SAXNotSupportedException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException(ex);
} catch (AbstractMethodError er) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, er);
throw new IllegalStateException(er);
}
}
/**
* Returns properly configured (e.g. security features) parser factory
* - namespaceAware == true
* - securityProcessing == is set based on security processing property, default is true
*/
public static SAXParserFactory createParserFactory(boolean disableSecureProcessing) throws IllegalStateException {
SessionLog logger = AbstractSessionLog.getLog();
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "saxparser_factory", new Object[] {factory});
}
factory.setNamespaceAware(true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, !isXMLSecurityDisabled(disableSecureProcessing));
return factory;
} catch (ParserConfigurationException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException( ex);
} catch (SAXNotRecognizedException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException( ex);
} catch (SAXNotSupportedException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException( ex);
} catch (AbstractMethodError er) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, er);
throw new IllegalStateException(er);
}
}
/**
* Returns properly configured (e.g. security features) factory
* - securityProcessing == is set based on security processing property, default is true
*/
public static XPathFactory createXPathFactory(boolean disableSecureProcessing) throws IllegalStateException {
SessionLog logger = AbstractSessionLog.getLog();
try {
XPathFactory factory = XPathFactory.newInstance();
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "xpath_factory", new Object[] {factory});
}
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, !isXMLSecurityDisabled(disableSecureProcessing));
return factory;
} catch (XPathFactoryConfigurationException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException( ex);
} catch (AbstractMethodError er) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, er);
throw new IllegalStateException(er);
}
}
/**
* Returns properly configured (e.g. security features) factory
* - securityProcessing == is set based on security processing property, default is true
*/
public static TransformerFactory createTransformerFactory(boolean disableSecureProcessing) throws IllegalStateException {
SessionLog logger = AbstractSessionLog.getLog();
try {
TransformerFactory factory = TransformerFactory.newInstance();
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "transformer_factory", new Object[] {factory});
}
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, !isXMLSecurityDisabled(disableSecureProcessing));
return factory;
} catch (TransformerConfigurationException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException( ex);
} catch (AbstractMethodError er) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, er);
throw new IllegalStateException(er);
}
}
/**
* Returns properly configured (e.g. security features) factory
* - namespaceAware == true
* - securityProcessing == is set based on security processing property, default is true
*/
public static DocumentBuilderFactory createDocumentBuilderFactory(boolean disableSecureProcessing) throws IllegalStateException {
SessionLog logger = AbstractSessionLog.getLog();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "documentbuilder_factory", new Object[] {factory});
}
factory.setNamespaceAware(true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, !isXMLSecurityDisabled(disableSecureProcessing));
return factory;
} catch (ParserConfigurationException ex) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, ex);
throw new IllegalStateException( ex);
} catch (AbstractMethodError er) {
logger.logThrowable(SessionLog.SEVERE, SessionLog.MOXY, er);
throw new IllegalStateException(er);
}
}
public static SchemaFactory allowExternalAccess(SchemaFactory sf, String value, boolean disableSecureProcessing) {
SessionLog logger = AbstractSessionLog.getLog();
// if xml security (feature secure processing) disabled, nothing to do, no restrictions applied
if (isXMLSecurityDisabled(disableSecureProcessing)) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_disabled", new Object[] {"xsd"});
}
return sf;
}
if (PrivilegedAccessHelper.getSystemProperty(PROP_ACCESS_EXTERNAL_SCHEMA) != null) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_explicit", new Object[] {"xsd"});
}
return sf;
}
try {
sf.setProperty(ACCESS_EXTERNAL_SCHEMA, value);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_prop_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
}
} catch (SAXException ignored) {
// nothing to do; support depends on version JDK or SAX implementation
if (logger.shouldLog(SessionLog.CONFIG, SessionLog.MOXY)) {
logger.log(SessionLog.CONFIG, SessionLog.MOXY, "jaxp_sec_prop_not_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
logger.logThrowable(SessionLog.CONFIG, SessionLog.MOXY, ignored);
}
}
return sf;
}
public static TransformerFactory allowExternalAccess(TransformerFactory tf, String value, boolean disableSecureProcessing) {
SessionLog logger = AbstractSessionLog.getLog();
// if xml security (feature secure processing) disabled, nothing to do, no restrictions applied
if (isXMLSecurityDisabled(disableSecureProcessing)) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_disabled", new Object[] {"xsd"});
}
return tf;
}
if (PrivilegedAccessHelper.getSystemProperty(PROP_ACCESS_EXTERNAL_SCHEMA) != null) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_explicit", new Object[] {"xsd"});
}
return tf;
}
try {
tf.setAttribute(ACCESS_EXTERNAL_SCHEMA, value);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_prop_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
}
} catch (IllegalArgumentException ignored) {
// nothing to do; support depends on version JDK or SAX implementation
if (logger.shouldLog(SessionLog.CONFIG, SessionLog.MOXY)) {
logger.log(SessionLog.CONFIG, SessionLog.MOXY, "jaxp_sec_prop_not_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
logger.logThrowable(SessionLog.CONFIG, SessionLog.MOXY, ignored);
}
}
return tf;
}
public static DocumentBuilderFactory allowExternalAccess(DocumentBuilderFactory dbf, String value, boolean disableSecureProcessing) {
SessionLog logger = AbstractSessionLog.getLog();
// if xml security (feature secure processing) disabled, nothing to do, no restrictions applied
if (isXMLSecurityDisabled(disableSecureProcessing)) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_disabled", new Object[] {"xsd"});
}
return dbf;
}
if (PrivilegedAccessHelper.getSystemProperty(PROP_ACCESS_EXTERNAL_SCHEMA) != null) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_explicit", new Object[] {"xsd"});
}
return dbf;
}
try {
dbf.setAttribute(ACCESS_EXTERNAL_SCHEMA, value);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_prop_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
}
} catch (IllegalArgumentException ignored) {
// nothing to do; support depends on version JDK or SAX implementation
if (logger.shouldLog(SessionLog.CONFIG, SessionLog.MOXY)) {
logger.log(SessionLog.CONFIG, SessionLog.MOXY, "jaxp_sec_prop_not_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
logger.logThrowable(SessionLog.CONFIG, SessionLog.MOXY, ignored);
}
}
return dbf;
}
public static XMLReader allowExternalAccess(XMLReader xmlReader, String value, boolean disableSecureProcessing) {
SessionLog logger = AbstractSessionLog.getLog();
// if xml security (feature secure processing) disabled, nothing to do, no restrictions applied
if (isXMLSecurityDisabled(disableSecureProcessing)) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_disabled", new Object[] {"xsd"});
}
return xmlReader;
}
if (PrivilegedAccessHelper.getSystemProperty(PROP_ACCESS_EXTERNAL_SCHEMA) != null) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_explicit", new Object[] {"xsd"});
}
return xmlReader;
}
try {
xmlReader.setProperty(ACCESS_EXTERNAL_SCHEMA, value);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_prop_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
}
} catch (SAXException ignored) {
// nothing to do; support depends on version JDK or SAX implementation
if (logger.shouldLog(SessionLog.CONFIG, SessionLog.MOXY)) {
logger.log(SessionLog.CONFIG, SessionLog.MOXY, "jaxp_sec_prop_not_supported", new Object[] {ACCESS_EXTERNAL_SCHEMA});
logger.logThrowable(SessionLog.CONFIG, SessionLog.MOXY, ignored);
}
}
return xmlReader;
}
public static SchemaFactory allowExternalDTDAccess(SchemaFactory sf, String value, boolean disableSecureProcessing) {
SessionLog logger = AbstractSessionLog.getLog();
// if xml security (feature secure processing) disabled, nothing to do, no restrictions applied
if (isXMLSecurityDisabled(disableSecureProcessing)) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_disabled", new Object[] {"DTD"});
}
return sf;
}
if (PrivilegedAccessHelper.getSystemProperty(PROP_ACCESS_EXTERNAL_DTD) != null) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_explicit", new Object[] {"DTD"});
}
return sf;
}
try {
sf.setProperty(ACCESS_EXTERNAL_DTD, value);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_prop_supported", new Object[] {ACCESS_EXTERNAL_DTD});
}
} catch (SAXException ignored) {
// nothing to do; support depends on version JDK or SAX implementation
if (logger.shouldLog(SessionLog.CONFIG, SessionLog.MOXY)) {
logger.log(SessionLog.CONFIG, SessionLog.MOXY, "jaxp_sec_prop_not_supported", new Object[] {ACCESS_EXTERNAL_DTD});
logger.logThrowable(SessionLog.CONFIG, SessionLog.MOXY, ignored);
}
}
return sf;
}
public static DocumentBuilderFactory allowExternalDTDAccess(DocumentBuilderFactory dbf, String value, boolean disableSecureProcessing) {
SessionLog logger = AbstractSessionLog.getLog();
// if xml security (feature secure processing) disabled, nothing to do, no restrictions applied
if (isXMLSecurityDisabled(disableSecureProcessing)) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_disabled", new Object[] {"DTD"});
}
return dbf;
}
if (PrivilegedAccessHelper.getSystemProperty(PROP_ACCESS_EXTERNAL_DTD) != null) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_explicit", new Object[] {"DTD"});
}
return dbf;
}
try {
dbf.setAttribute(ACCESS_EXTERNAL_DTD, value);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_prop_supported", new Object[] {ACCESS_EXTERNAL_DTD});
}
} catch (IllegalArgumentException ignored) {
// nothing to do; support depends on version JDK or SAX implementation
if (logger.shouldLog(SessionLog.CONFIG, SessionLog.MOXY)) {
logger.log(SessionLog.CONFIG, SessionLog.MOXY, "jaxp_sec_prop_not_supported", new Object[] {ACCESS_EXTERNAL_DTD});
logger.logThrowable(SessionLog.CONFIG, SessionLog.MOXY, ignored);
}
}
return dbf;
}
public static XMLReader allowExternalDTDAccess(XMLReader xmlReader, String value, boolean disableSecureProcessing) {
SessionLog logger = AbstractSessionLog.getLog();
// if xml security (feature secure processing) disabled, nothing to do, no restrictions applied
if (isXMLSecurityDisabled(disableSecureProcessing)) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_disabled", new Object[] {"DTD"});
}
return xmlReader;
}
if (PrivilegedAccessHelper.getSystemProperty(PROP_ACCESS_EXTERNAL_DTD) != null) {
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_explicit", new Object[] {"DTD"});
}
return xmlReader;
}
try {
xmlReader.setProperty(ACCESS_EXTERNAL_DTD, value);
if (logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
logger.log(SessionLog.FINE, SessionLog.MOXY, "jaxp_sec_prop_supported", new Object[] {ACCESS_EXTERNAL_DTD});
}
} catch (SAXException ignored) {
// nothing to do; support depends on version JDK or SAX implementation
if (logger.shouldLog(SessionLog.CONFIG, SessionLog.MOXY)) {
logger.log(SessionLog.CONFIG, SessionLog.MOXY, "jaxp_sec_prop_not_supported", new Object[] {ACCESS_EXTERNAL_DTD});
logger.logThrowable(SessionLog.CONFIG, SessionLog.MOXY, ignored);
}
}
return xmlReader;
}
}