8354774: DocumentBuilderFactory getAttribute throws NPE

Reviewed-by: naoto, lancea
This commit is contained in:
Joe Wang 2025-04-21 18:25:59 +00:00
parent ecb54a05c6
commit 684d3b336e
11 changed files with 268 additions and 120 deletions

View File

@ -371,17 +371,10 @@ public class TransformerFactoryImpl
return _cdataChunkSize;
}
/** Check to see if the property is managed by the security manager **/
String propertyValue = (_xmlSecurityManager != null) ?
_xmlSecurityManager.getLimitAsString(name) : null;
if (propertyValue != null) {
return propertyValue;
} else {
propertyValue = (_xmlSecurityPropertyMgr != null) ?
_xmlSecurityPropertyMgr.getValue(name) : null;
if (propertyValue != null) {
return propertyValue;
}
//check if the property is managed by security manager
String value;
if ((value = JdkXmlUtils.getProperty(_xmlSecurityManager, _xmlSecurityPropertyMgr, name)) != null) {
return value;
}
// Throw an exception for all other attributes

View File

@ -27,13 +27,10 @@ package com.sun.org.apache.xerces.internal.impl;
import com.sun.xml.internal.stream.StaxEntityResolverWrapper;
import java.util.HashMap;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLResolver;
import jdk.xml.internal.FeaturePropertyBase;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.JdkProperty;
import jdk.xml.internal.JdkXmlUtils;
import jdk.xml.internal.XMLSecurityManager;
import jdk.xml.internal.XMLSecurityPropertyManager;
@ -188,20 +185,13 @@ public class PropertyManager {
if (XMLInputFactory.SUPPORT_DTD.equals(property)) {
return fSecurityManager.is(XMLSecurityManager.Limit.STAX_SUPPORT_DTD);
}
/**
* Check to see if the property is managed by the security manager *
*/
String propertyValue = (fSecurityManager != null)
? fSecurityManager.getLimitAsString(property) : null;
/**
* Check to see if the property is managed by the security property
* manager
*/
if (propertyValue == null) {
propertyValue = (fSecurityPropertyMgr != null)
? fSecurityPropertyMgr.getValue(property) : null;
//check if the property is managed by security manager
String value;
if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, property)) != null) {
return value;
}
return propertyValue != null ? propertyValue : supportedProps.get(property);
return supportedProps.get(property);
}
/**
@ -250,15 +240,9 @@ public class PropertyManager {
return;
}
//check if the property is managed by security manager
if (fSecurityManager == null
|| !fSecurityManager.setLimit(property, JdkProperty.State.APIPROPERTY, value)) {
//check if the property is managed by security property manager
if (fSecurityPropertyMgr == null
|| !fSecurityPropertyMgr.setValue(property, FeaturePropertyBase.State.APIPROPERTY, value)) {
//fall back to the existing property manager
supportedProps.put(property, value);
}
if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, property, value)) {
//fall back to the existing property manager
supportedProps.put(property, value);
}
if (equivalentProperty != null) {

View File

@ -29,7 +29,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.validation.Schema;
import jdk.xml.internal.JdkProperty;
import jdk.xml.internal.JdkXmlUtils;
import jdk.xml.internal.XMLSecurityManager;
import jdk.xml.internal.XMLSecurityPropertyManager;
import org.xml.sax.SAXException;
@ -114,20 +114,13 @@ public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory {
attributes = new HashMap<>();
}
//check if the property is managed by security manager
String pName;
if ((pName = fSecurityManager.find(name)) != null) {
// as the qName is deprecated, let the manager decide whether the
// value shall be changed
fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, value);
attributes.put(pName, fSecurityManager.getLimitAsString(pName));
if (JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, value)) {
// necessary as DocumentBuilder recreate property manager
// remove this line once that's changed
attributes.put(name, value);
// no need to create a DocumentBuilderImpl
return;
} else if ((pName = fSecurityPropertyMgr.find(name)) != null) {
attributes.put(pName, value);
return;
}
attributes.put(name, value);
// Test the attribute name by possibly throwing an exception
@ -146,13 +139,10 @@ public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory {
public Object getAttribute(String name)
throws IllegalArgumentException
{
//check if the property is managed by security manager
String pName;
if ((pName = fSecurityManager.find(name)) != null) {
return fSecurityManager.getLimitAsString(pName);
} else if ((pName = fSecurityPropertyMgr.find(name)) != null) {
return attributes.get(pName);
String value;
if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, name)) != null) {
return value;
}
// See if it's in the attributes Map

View File

@ -43,7 +43,7 @@ import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
import jdk.xml.internal.FeaturePropertyBase.State;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.JdkProperty;
import jdk.xml.internal.JdkXmlUtils;
import jdk.xml.internal.XMLSecurityManager;
import jdk.xml.internal.XMLSecurityPropertyManager;
import jdk.xml.internal.XMLSecurityPropertyManager.Property;
@ -297,17 +297,10 @@ public class DocumentBuilderImpl extends DocumentBuilder
}
}
} else {
//check if the property is managed by security manager
if (fSecurityManager == null ||
!fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, val)) {
//check if the property is managed by security property manager
if (fSecurityPropertyMgr == null ||
!fSecurityPropertyMgr.setValue(name, State.APIPROPERTY, val)) {
//fall back to the existing property manager
domParser.setProperty(name, val);
}
if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, val)) {
//fall back to the existing property manager
domParser.setProperty(name, val);
}
}
}
}

View File

@ -43,7 +43,7 @@ import javax.xml.XMLConstants;
import javax.xml.validation.Schema;
import jdk.xml.internal.FeaturePropertyBase;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.JdkProperty;
import jdk.xml.internal.JdkXmlUtils;
import jdk.xml.internal.XMLSecurityManager;
import jdk.xml.internal.XMLSecurityPropertyManager;
import org.xml.sax.EntityResolver;
@ -569,20 +569,13 @@ public class SAXParserImpl extends javax.xml.parsers.SAXParser
super.setProperty(name, value);
}
//check if the property is managed by security manager
if (fSecurityManager == null ||
!fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, value)) {
//check if the property is managed by security property manager
if (fSecurityPropertyMgr == null ||
!fSecurityPropertyMgr.setValue(name, FeaturePropertyBase.State.APIPROPERTY, value)) {
//fall back to the existing property manager
if (!fInitProperties.containsKey(name)) {
fInitProperties.put(name, super.getProperty(name));
}
super.setProperty(name, value);
if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, value)) {
//fall back to the existing property manager
if (!fInitProperties.containsKey(name)) {
fInitProperties.put(name, super.getProperty(name));
}
super.setProperty(name, value);
}
}
public synchronized Object getProperty(String name)
@ -596,19 +589,10 @@ public class SAXParserImpl extends javax.xml.parsers.SAXParser
return fSAXParser.schemaLanguage;
}
/** Check to see if the property is managed by the security manager **/
String propertyValue = (fSecurityManager != null) ?
fSecurityManager.getLimitAsString(name) : null;
if (propertyValue != null) {
return propertyValue;
} else {
propertyValue = (fSecurityPropertyMgr != null) ?
fSecurityPropertyMgr.getValue(name) : null;
if (propertyValue != null) {
return propertyValue;
}
String value;
if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, name)) != null) {
return value;
}
return super.getProperty(name);
}

View File

@ -40,7 +40,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures.Feature;
import javax.xml.stream.XMLEventReader;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
@ -404,10 +403,11 @@ public final class XMLSchemaFactory extends SchemaFactory {
}
try {
/** Check to see if the property is managed by the security manager **/
String propertyValue = (fSecurityManager != null) ?
fSecurityManager.getLimitAsString(name) : null;
return propertyValue != null ? propertyValue :
fXMLSchemaLoader.getProperty(name);
String value;
if ((value = JdkXmlUtils.getProperty(fSecurityManager, fSecurityPropertyMgr, name)) != null) {
return value;
}
return fXMLSchemaLoader.getProperty(name);
}
catch (XMLConfigurationException e) {
String identifier = e.getIdentifier();
@ -513,15 +513,9 @@ public final class XMLSchemaFactory extends SchemaFactory {
"property-not-supported", new Object [] {name}));
}
try {
//check if the property is managed by security manager
if (fSecurityManager == null ||
!fSecurityManager.setLimit(name, JdkProperty.State.APIPROPERTY, object)) {
//check if the property is managed by security property manager
if (fSecurityPropertyMgr == null ||
!fSecurityPropertyMgr.setValue(name, FeaturePropertyBase.State.APIPROPERTY, object)) {
//fall back to the existing property manager
fXMLSchemaLoader.setProperty(name, object);
}
if (!JdkXmlUtils.setProperty(fSecurityManager, fSecurityPropertyMgr, name, object)) {
//fall back to the existing property manager
fXMLSchemaLoader.setProperty(name, object);
}
}
catch (XMLConfigurationException e) {

View File

@ -48,7 +48,7 @@ import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
import javax.xml.catalog.CatalogFeatures;
import jdk.xml.internal.FeaturePropertyBase;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.JdkProperty;
import jdk.xml.internal.JdkXmlUtils;
import jdk.xml.internal.XMLSecurityManager;
import jdk.xml.internal.XMLSecurityPropertyManager;
import org.w3c.dom.ls.LSResourceResolver;
@ -353,7 +353,7 @@ final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettin
* Set the state of a feature.
*
* @param featureId The unique identifier (URI) of the feature.
* @param state The requested state of the feature (true or false).
* @param value The value of the feature (true or false).
*
* @exception XMLConfigurationException If the requested feature is not known.
*/
@ -361,7 +361,7 @@ final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettin
if (PARSER_SETTINGS.equals(featureId)) {
throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
}
else if (value == false && (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId))) {
else if (!value && (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId))) {
throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
}
else if (USE_GRAMMAR_POOL_ONLY.equals(featureId) && value != fUseGrammarPoolOnly) {
@ -452,18 +452,12 @@ final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettin
fComponents.put(propertyId, value);
return;
}
//check if the property is managed by security manager
if (fInitSecurityManager == null ||
!fInitSecurityManager.setLimit(propertyId, JdkProperty.State.APIPROPERTY, value)) {
//check if the property is managed by security property manager
if (fSecurityPropertyMgr == null ||
!fSecurityPropertyMgr.setValue(propertyId, FeaturePropertyBase.State.APIPROPERTY, value)) {
//fall back to the existing property manager
if (!fInitProperties.containsKey(propertyId)) {
fInitProperties.put(propertyId, super.getProperty(propertyId));
}
super.setProperty(propertyId, value);
if (!JdkXmlUtils.setProperty(fInitSecurityManager, fSecurityPropertyMgr, propertyId, value)) {
//fall back to the existing property manager
if (!fInitProperties.containsKey(propertyId)) {
fInitProperties.put(propertyId, super.getProperty(propertyId));
}
super.setProperty(propertyId, value);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -98,6 +98,47 @@ public class JdkXmlUtils {
private static final SAXParserFactory instance = getSAXFactory(false);
}
/**
* Sets the property if it's managed by either XMLSecurityManager or XMLSecurityPropertyManager.
* @param xsm the XMLSecurityManager
* @param xspm the XMLSecurityPropertyManager
* @param property the property
* @param value the value
* @return true if the property is managed by either XMLSecurityManager or
* XMLSecurityPropertyManager, false otherwise
*/
public static boolean setProperty(XMLSecurityManager xsm, XMLSecurityPropertyManager xspm,
String property, Object value) {
if (xsm != null && xsm.find(property) != null) {
return xsm.setLimit(property, JdkProperty.State.APIPROPERTY, value);
} else if (xspm != null && xspm.find(property) != null) {
return xspm.setValue(property, FeaturePropertyBase.State.APIPROPERTY, value);
}
return false;
}
/**
* Returns the value of the property if it's managed by either XMLSecurityManager
* or XMLSecurityPropertyManager.
* @param xsm the XMLSecurityManager
* @param xspm the XMLSecurityPropertyManager
* @param property the property
* @return the value of the property if it's managed by either XMLSecurityManager
* or XMLSecurityPropertyManager, null otherwise
*/
public static String getProperty(XMLSecurityManager xsm, XMLSecurityPropertyManager xspm,
String property) {
String value = null;
if (xsm != null && (value = xsm.getLimitAsString(property)) != null) {
return value;
}
if (xspm != null) {
value = xspm.getValue(property);
}
return value;
}
/**
* Returns the value.
*

View File

@ -361,7 +361,7 @@ public final class XMLSecurityManager {
for (Limit limit : Limit.values()) {
if (limit.is(propertyName)) {
// current spec: new property name == systemProperty
return limit.systemProperty();
return (limit.systemProperty != null) ? limit.systemProperty : limit.apiProperty;
}
}
//ENTITYCOUNT's new name is qName

View File

@ -32,6 +32,19 @@ public class JUnitTestUtil {
public static final String CLS_DIR = System.getProperty("test.classes");
public static final String SRC_DIR = System.getProperty("test.src");
// as in the Processors table in java.xml module summary
public enum Processor {
DOM,
SAX,
XMLREADER,
StAX,
VALIDATION,
TRANSFORM,
XSLTC,
DOMLS,
XPATH
};
/**
* Returns the System identifier (URI) of the source.
* @param path the path to the source

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package common;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.validation.SchemaFactory;
import java.util.EnumSet;
import java.util.Set;
import java.util.stream.Stream;
import jaxp.library.JUnitTestUtil.Processor;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.xml.sax.XMLReader;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*
* @test
* @bug 8354774
* @summary Verifies JAXP API Properties as specified in the java.xml module.
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest /test/lib
* @run junit/othervm common.PropertiesTest
*/
public class PropertiesTest {
private static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD;
private static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA;
private static final String ACCESS_EXTERNAL_STYLESHEET = XMLConstants.ACCESS_EXTERNAL_STYLESHEET;
private static final String SP_ACCESS_EXTERNAL_DTD = "javax.xml.accessExternalDTD";
private static final String SP_ACCESS_EXTERNAL_SCHEMA = "javax.xml.accessExternalSchema";
private static final String SP_ACCESS_EXTERNAL_STYLESHEET = "javax.xml.accessExternalStylesheet";
private static final String DEFAULT_VALUE = "all";
/**
* Returns test data for testAccessExternalProperties
* @return test data for testAccessExternalProperties
*/
private static Stream<Arguments> testData() {
// Supported processors for Access External Properties
Set<Processor> supportedProcessors1 = EnumSet.of(Processor.DOM, Processor.SAX, Processor.XMLREADER,
Processor.StAX, Processor.VALIDATION);
Set<Processor> supportedProcessors2 = EnumSet.of(Processor.TRANSFORM);
return Stream.of(
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, null, SP_ACCESS_EXTERNAL_DTD, null, DEFAULT_VALUE),
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, "http", SP_ACCESS_EXTERNAL_DTD, null, "http"),
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, null, SP_ACCESS_EXTERNAL_DTD, "https", "https"),
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_DTD, "http", SP_ACCESS_EXTERNAL_DTD, "https", "http"),
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, null, SP_ACCESS_EXTERNAL_SCHEMA, null, DEFAULT_VALUE),
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, "http", SP_ACCESS_EXTERNAL_SCHEMA, null, "http"),
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, null, SP_ACCESS_EXTERNAL_SCHEMA, "https", "https"),
Arguments.of(supportedProcessors1, ACCESS_EXTERNAL_SCHEMA, "http", SP_ACCESS_EXTERNAL_SCHEMA, "https", "http"),
Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, null, SP_ACCESS_EXTERNAL_STYLESHEET, null, DEFAULT_VALUE),
Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, "http", SP_ACCESS_EXTERNAL_STYLESHEET, null, "http"),
Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, null, SP_ACCESS_EXTERNAL_STYLESHEET, "https", "https"),
Arguments.of(supportedProcessors2, ACCESS_EXTERNAL_STYLESHEET, "http", SP_ACCESS_EXTERNAL_STYLESHEET, "https", "http")
);
}
/**
* Verifies that the Access External Properties are supported throughout the
* JAXP APIs.
* @param supportedProcessors the supported processors for the property
* @param apiProperty the API property
* @param apiValue the value of the API property
* @param sysProperty the System property corresponding to the API property
* @param sysValue the value of the System property
* @param expected the expected result
* @throws Exception if the test fails due to test configuration issues other
* than the expected result
*/
@ParameterizedTest
@MethodSource("testData")
public void testAccessExternalProperties(Set<Processor> supportedProcessors,
String apiProperty, String apiValue, String sysProperty, String sysValue,
String expected) throws Exception {
for (Processor p : supportedProcessors) {
testProperties(p, apiProperty, apiValue, sysProperty, sysValue,
expected);
}
}
/**
* Verifies that properties can be set via the JAXP APIs and their corresponding
* System Properties.
* @param processor the processor type
* @param apiProperty the API property
* @param apiValue the value to be set via the API property
* @param sysProperty the System Property
* @param sysValue the value to be set via the System property
* @param expected the expected result
* @throws Exception if the test fails, which can only happen if the property
* is set incorrectly.
*/
void testProperties(Processor processor, String apiProperty, String apiValue,
String sysProperty, String sysValue, String expected)
throws Exception {
Object ret1 = null;
if (sysValue != null) {
System.setProperty(sysProperty, sysValue);
}
switch (processor) {
case DOM:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance();
if (apiValue != null) dbf.setAttribute(apiProperty, apiValue);
ret1 = dbf.getAttribute(apiProperty);
break;
case SAX:
SAXParser sp = SAXParserFactory.newDefaultInstance().newSAXParser();
if (apiValue != null) sp.setProperty(apiProperty, apiValue);
ret1 = sp.getProperty(apiProperty);
break;
case XMLREADER:
XMLReader reader = SAXParserFactory.newDefaultInstance().newSAXParser().getXMLReader();
if (apiValue != null) reader.setProperty(apiProperty, apiValue);
ret1 = reader.getProperty(apiProperty);
break;
case StAX:
XMLInputFactory xif = XMLInputFactory.newDefaultFactory();
if (apiValue != null) xif.setProperty(apiProperty, apiValue);
ret1 = xif.getProperty(apiProperty);
break;
case VALIDATION:
SchemaFactory sf = SchemaFactory.newDefaultInstance();
if (apiValue != null) sf.setProperty(apiProperty, apiValue);
ret1 = sf.getProperty(apiProperty);
break;
case TRANSFORM:
TransformerFactory tf = TransformerFactory.newDefaultInstance();
if (apiValue != null) tf.setAttribute(apiProperty, apiValue);
ret1 = tf.getAttribute(apiProperty);
break;
}
if (sysValue != null) System.clearProperty(sysProperty);
// property value is as expected
assertEquals(expected, ret1);
}
}