diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java
index 098d3c8a260..3c8e1edd5b8 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Import.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -33,6 +33,7 @@ import java.util.Iterator;
import javax.xml.XMLConstants;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.SecuritySupport;
+import jdk.xml.internal.XMLSecurityManager;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
@@ -41,7 +42,7 @@ import org.xml.sax.XMLReader;
* @author Morten Jorgensen
* @author Erwin Bolwidt
* @author Gunnlaugur Briem
- * @LastModified: May 2021
+ * @LastModified: July 2026
*/
final class Import extends TopLevelElement {
@@ -84,8 +85,9 @@ final class Import extends TopLevelElement {
if (input == null) {
docToLoad = SystemIDResolver.getAbsoluteURI(docToLoad, currLoadedDoc);
String accessError = SecuritySupport.checkAccess(docToLoad,
- (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET),
- JdkConstants.ACCESS_EXTERNAL_ALL);
+ (XMLSecurityManager)xsltc.getProperty(JdkConstants.SECURITY_MANAGER),
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET));
if (accessError != null) {
final ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java
index ecb03df9f1c..8e3b5530320 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Include.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -33,6 +33,7 @@ import java.util.Iterator;
import javax.xml.XMLConstants;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.SecuritySupport;
+import jdk.xml.internal.XMLSecurityManager;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
@@ -41,7 +42,7 @@ import org.xml.sax.XMLReader;
* @author Morten Jorgensen
* @author Erwin Bolwidt
* @author Gunnlaugur Briem
- * @LastModified: May 2021
+ * @LastModified: July 2026
*/
final class Include extends TopLevelElement {
@@ -84,8 +85,9 @@ final class Include extends TopLevelElement {
if (input == null) {
docToLoad = SystemIDResolver.getAbsoluteURI(docToLoad, currLoadedDoc);
String accessError = SecuritySupport.checkAccess(docToLoad,
- (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET),
- JdkConstants.ACCESS_EXTERNAL_ALL);
+ (XMLSecurityManager)xsltc.getProperty(JdkConstants.SECURITY_MANAGER),
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ (String)xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET));
if (accessError != null) {
final ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java
index 0dde14f455c..f523b65a2b4 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -60,7 +60,7 @@ import org.xml.sax.helpers.AttributesImpl;
* @author G. Todd Miller
* @author Morten Jorgensen
* @author Erwin Bolwidt
- * @LastModified: July 2023
+ * @LastModified: July 2026
*/
public class Parser implements Constants, ContentHandler {
@@ -540,23 +540,20 @@ public class Parser implements Constants, ContentHandler {
return(element);
}
else {
- try {
- String path = _target;
- if (path.indexOf(":")==-1) {
- path = "file:" + path;
- }
- path = SystemIDResolver.getAbsoluteURI(path);
- String accessError = SecuritySupport.checkAccess(path,
- (String)_xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET),
- JdkConstants.ACCESS_EXTERNAL_ALL);
- if (accessError != null) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- SecuritySupport.sanitizePath(_target), accessError,
- root);
- throw new CompilerException(msg.toString());
- }
- } catch (IOException ex) {
- throw new CompilerException(ex);
+ String path = _target;
+ if (path.indexOf(":")==-1) {
+ path = "file:" + path;
+ }
+ path = SystemIDResolver.getAbsoluteURI(path);
+ String accessError = SecuritySupport.checkAccess(path,
+ (XMLSecurityManager)_xsltc.getProperty(JdkConstants.SECURITY_MANAGER),
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ (String)_xsltc.getProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET));
+ if (accessError != null) {
+ ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
+ SecuritySupport.sanitizePath(_target), accessError,
+ root);
+ throw new CompilerException(msg.toString());
}
return(loadExternalStylesheet(_target));
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
index 660d1194b30..a3875969bb7 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,7 +24,7 @@ import java.util.ListResourceBundle;
/**
* @author Morten Jorgensen
- * @LastModified: Dec 2024
+ * @LastModified: July 2026
*/
public class ErrorMessages extends ListResourceBundle {
@@ -469,7 +469,7 @@ public class ErrorMessages extends ListResourceBundle {
* Note to translators: access to the stylesheet target is denied
*/
{ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- "Could not read stylesheet target ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalStylesheet property."},
+ "Could not read stylesheet target ''{0}'', because access is not allowed due to restriction set by ''{1}''."},
/*
* Note to translators: This message represents an internal error in
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java
index 39084c87f0b..e17407e2831 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/LoadDocument.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -39,7 +39,7 @@ import jdk.xml.internal.SecuritySupport;
/**
* @author Morten Jorgensen
- * @LastModified: Sept 2021
+ * @LastModified: July 2026
*/
public final class LoadDocument {
@@ -197,12 +197,7 @@ public final class LoadDocument {
throw new TransletException(e);
}
} else {
- String accessError = SecuritySupport.checkAccess(uri, translet.getAllowedProtocols(), JdkConstants.ACCESS_EXTERNAL_ALL);
- if (accessError != null) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- SecuritySupport.sanitizePath(uri), accessError);
- throw new Exception(msg.toString());
- }
+ translet.verifyAccess(uri);
// Parse the input document and construct DOM object
// Trust the DTMManager to pick the right parser and
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
index 1612fd61923..620eb670547 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -25,6 +25,7 @@ import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
import com.sun.org.apache.xalan.internal.xsltc.Translet;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex;
import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
@@ -40,11 +41,14 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Templates;
import jdk.xml.internal.JdkConstants;
import jdk.xml.internal.JdkXmlUtils;
+import jdk.xml.internal.SecuritySupport;
+import jdk.xml.internal.XMLSecurityManager;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
@@ -54,7 +58,7 @@ import org.w3c.dom.Document;
* @author Morten Jorgensen
* @author G. Todd Miller
* @author John Howard, JohnH@schemasoft.com
- * @LastModified: Sept 2021
+ * @LastModified: July 2026
*/
public abstract class AbstractTranslet implements Translet {
@@ -115,6 +119,7 @@ public abstract class AbstractTranslet implements Translet {
* protocols allowed for external references set by the stylesheet processing instruction, Document() function, Import and Include element.
*/
private String _accessExternalStylesheet = JdkConstants.EXTERNAL_ACCESS_DEFAULT;
+ private XMLSecurityManager _xsm;
// The error message when access to exteranl resources is rejected
private String _accessErr = null;
@@ -789,6 +794,37 @@ public abstract class AbstractTranslet implements Translet {
_accessExternalStylesheet = protocols;
}
+ /**
+ * Returns the XMLSecurityManager
+ */
+ public XMLSecurityManager getXMLSecurityManager() {
+ return _xsm;
+ }
+
+ /**
+ * Sets the XMLSecurityManager
+ * @param xsm the XMLSecurityManager instance
+ */
+ public void setXMLSecurityManager(XMLSecurityManager xsm) {
+ _xsm = xsm;
+ }
+
+ /**
+ * Verifies that access to the resource represented by the systemId is permitted.
+ * @param systemId the systemId
+
+ * @throws TransletException if access is not permitted
+ */
+ public void verifyAccess(String systemId) throws TransletException {
+ String accessError = SecuritySupport.checkAccess(systemId, _xsm,
+ XMLConstants.ACCESS_EXTERNAL_STYLESHEET, _accessExternalStylesheet);
+ if (accessError != null) {
+ ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
+ SecuritySupport.sanitizePath(systemId), accessError);
+ throw new TransletException(msg.toString());
+ }
+ }
+
/**
* Returns the access error.
*/
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
index 41b83bce5df..71aad15b09f 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -58,6 +58,7 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.URIResolver;
import jdk.xml.internal.JdkConstants;
+import jdk.xml.internal.XMLSecurityManager;
/**
@@ -65,7 +66,7 @@ import jdk.xml.internal.JdkConstants;
* @author G. Todd Millerj
* @author Jochen Cordes
* @author Santiago Pericas-Geertsen
- * @LastModified: Jan 2025
+ * @LastModified: July 2026
*/
public final class TemplatesImpl implements Templates, Serializable {
static final long serialVersionUID = 673094361519270707L;
@@ -147,6 +148,7 @@ public final class TemplatesImpl implements Templates, Serializable {
* protocols allowed for external references set by the stylesheet processing instruction, Import and Include element.
*/
private transient String _accessExternalStylesheet = JdkConstants.EXTERNAL_ACCESS_DEFAULT;
+ private transient XMLSecurityManager _xsm;
/**
* @serialField _name String The Name of the main class
@@ -240,6 +242,7 @@ public final class TemplatesImpl implements Templates, Serializable {
_tfactory = tfactory;
_overrideDefaultParser = tfactory.overrideDefaultParser();
_accessExternalStylesheet = (String) tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
+ _xsm = (XMLSecurityManager) tfactory.getAttribute(JdkConstants.SECURITY_MANAGER);
}
/**
* Need for de-serialization, see readObject().
@@ -540,6 +543,7 @@ public final class TemplatesImpl implements Templates, Serializable {
translet.setTemplates(this);
translet.setOverrideDefaultParser(_overrideDefaultParser);
translet.setAllowedProtocols(_accessExternalStylesheet);
+ translet.setXMLSecurityManager(_xsm);
if (_auxClasses != null) {
translet.setAuxiliaryClasses(_auxClasses);
}
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java
index ca56223aa44..14bb3d0df82 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -88,7 +88,7 @@ import org.xml.sax.XMLReader;
* @author G. Todd Miller
* @author Morten Jorgensen
* @author Santiago Pericas-Geertsen
- * @LastModified: May 2025
+ * @LastModified: July 2026
*/
public class TransformerFactoryImpl
extends SAXTransformerFactory implements SourceLoader
@@ -515,7 +515,7 @@ public class TransformerFactoryImpl
}
if (_xmlSecurityPropertyMgr != null &&
- _xmlSecurityPropertyMgr.setValue(name, FeaturePropertyBase.State.APIPROPERTY, value)) {
+ _xmlSecurityPropertyMgr.setValue(name, JdkProperty.State.APIPROPERTY, value)) {
_accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
Property.ACCESS_EXTERNAL_DTD);
_accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
@@ -572,9 +572,9 @@ public class TransformerFactoryImpl
// set external access restriction when FSP is explicitly set
if (value) {
_xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD,
- FeaturePropertyBase.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
+ JdkProperty.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
_xmlSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_STYLESHEET,
- FeaturePropertyBase.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
+ JdkProperty.State.FSP, JdkConstants.EXTERNAL_ACCESS_DEFAULT_FSP);
_accessExternalDTD = _xmlSecurityPropertyMgr.getValue(
Property.ACCESS_EXTERNAL_DTD);
_accessExternalStylesheet = _xmlSecurityPropertyMgr.getValue(
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
index b48b9d2a657..89091355484 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -100,7 +100,7 @@ import org.xml.sax.ext.LexicalHandler;
* @author Morten Jorgensen
* @author G. Todd Miller
* @author Santiago Pericas-Geertsen
- * @LastModified: Jan 2025
+ * @LastModified: July 2026
*/
public final class TransformerImpl extends Transformer
implements DOMCache
@@ -1357,21 +1357,13 @@ public final class TransformerImpl extends Transformer
*/
AbstractTranslet t = (AbstractTranslet)translet;
String systemId = SystemIDResolver.getAbsoluteURI(href, baseURI);
- String errMsg = null;
- try {
- String accessError = SecuritySupport.checkAccess(systemId,
- t.getAllowedProtocols(),
- JdkConstants.ACCESS_EXTERNAL_ALL);
- if (accessError != null) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
- SecuritySupport.sanitizePath(href), accessError);
- errMsg = msg.toString();
- }
- } catch (IOException ioe) {
- errMsg = ioe.getMessage();
- }
- if (errMsg != null) {
- t.setAccessError(errMsg);
+ String accessError = SecuritySupport.checkAccess(systemId,
+ t.getXMLSecurityManager(), XMLConstants.ACCESS_EXTERNAL_STYLESHEET,
+ t.getAllowedProtocols());
+ if (accessError != null) {
+ ErrorMsg msg = new ErrorMsg(ErrorMsg.ACCESSING_XSLT_TARGET_ERR,
+ SecuritySupport.sanitizePath(href), accessError);
+ t.setAccessError(msg.toString());
return null;
}
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
index ccaa9f6c5dd..e9cfd0ff388 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java
@@ -2023,7 +2023,8 @@ public class XMLDocumentFragmentScannerImpl
String checkAccess(String systemId, String allowedProtocols) throws IOException {
String baseSystemId = fEntityScanner.getBaseSystemId();
String expandedSystemId = XMLEntityManager.expandSystemId(systemId, baseSystemId, fStrictURI);
- return SecuritySupport.checkAccess(expandedSystemId, allowedProtocols, JdkConstants.ACCESS_EXTERNAL_ALL);
+ return SecuritySupport.checkAccess(expandedSystemId, fSecurityManager,
+ XMLConstants.ACCESS_EXTERNAL_DTD, allowedProtocols);
}
//
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
index 99b4193b39c..75f7d5216c7 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
@@ -1361,20 +1361,15 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
if (external) {
staxInputSource = resolveEntityAsPerStax(externalEntity.entityLocation);
- /** xxx: Waiting from the EG
- * //simply return if there was entity resolver registered and application
- * //returns either XMLStreamReader or XMLEventReader.
- * if(staxInputSource.hasXMLStreamOrXMLEventReader()) return ;
- */
xmlInputSource = staxInputSource.getXMLInputSource() ;
if (!fISCreatedByResolver) {
- String accessError = SecuritySupport.checkAccess(expandedSystemId,
- fAccessExternalDTD, JdkConstants.ACCESS_EXTERNAL_ALL);
+ String accessError = SecuritySupport.checkAccess(expandedSystemId, fSecurityManager,
+ XMLConstants.ACCESS_EXTERNAL_DTD, fAccessExternalDTD);
if (accessError != null) {
- fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN,
- "AccessExternalEntity",
- new Object[] { SecuritySupport.sanitizePath(expandedSystemId), accessError },
- XMLErrorReporter.SEVERITY_FATAL_ERROR);
+ fErrorReporter.reportError(this.getEntityScanner(), XMLMessageFormatter.XML_DOMAIN,
+ "AccessExternalEntity",
+ new Object[]{SecuritySupport.sanitizePath(expandedSystemId), accessError},
+ XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
}
}
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties
index 25182a06a3c..b51e912370a 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties
@@ -283,8 +283,9 @@
# Entity related messages
# 3.1 Start-Tags, End-Tags, and Empty-Element Tags
ReferenceToExternalEntity = The external entity reference \"&{0};\" is not permitted in an attribute value.
- AccessExternalDTD = External DTD: Failed to read external DTD ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalDTD property.
- AccessExternalEntity = External Entity: Failed to read external document ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalDTD property.
+ AccessExternalDTD = External DTD: Failed to read external DTD ''{0}'', because access is not allowed due to restriction set by ''{1}''.
+ AccessExternalEntity = External Entity: Failed to read external document ''{0}'', because access is not allowed due to restriction set by ''{1}''.
+ ResourceAccess = Resource Access: Failed to read external document ''{0}'', because the ''{1}'' property is set to not allow accessing the document.
# 4.1 Character and Entity References
EntityNotDeclared = The entity \"{0}\" was referenced, but not declared.
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
index 4f15b428c8b..2004e41e51d 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties
@@ -108,7 +108,7 @@
#schema valid (3.X.3)
- schema_reference.access = schema_reference: Failed to read schema document ''{0}'', because ''{1}'' access is not allowed due to restriction set by the accessExternalSchema property.
+ schema_reference.access = schema_reference: Failed to read schema document ''{0}'', because access is not allowed due to restriction set by ''{1}''.
schema_reference.4 = schema_reference.4: Failed to read schema document ''{0}'', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .
src-annotation = src-annotation: elements can only contain and elements, but ''{0}'' was found.
src-attribute.1 = src-attribute.1: The properties ''default'' and ''fixed'' cannot both be present in attribute declaration ''{0}''. Use only one of them.
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java
index b4b76546d6d..c884eec6f9f 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -103,7 +103,7 @@ import org.xml.sax.InputSource;
* @xerces.internal
*
* @author Neil Graham, IBM
- * @LastModified: May 2025
+ * @LastModified: July 2026
*/
public class XMLSchemaLoader implements XMLGrammarLoader, XMLComponent, XSElementDeclHelper,
@@ -285,6 +285,7 @@ XSLoader, DOMConfiguration {
private CMBuilder fCMBuilder;
private XSDDescription fXSDDescription = new XSDDescription();
private String faccessExternalSchema = JdkConstants.EXTERNAL_ACCESS_DEFAULT;
+ private XMLSecurityManager fXMLScurityManager = null;
private WeakHashMap
+ *
+ * The {@link #allows(java.net.URI)} method determines whether a given URI is permitted according to this rule.
+ *
+ */
+public class AccessRule {
+ public static final AccessRule RULE_NONE = new AccessRule("");
+ public static final AccessRule RULE_ALL = new AccessRule("*");
+ private final List rules = new ArrayList<>();
+ private final boolean allowAll;
+ private final boolean denyAll;
+ private final String rawInput;
+
+ public AccessRule(String input) {
+ this.rawInput = input;
+ String trimmedInput = input == null ? "" : input.trim();
+ if (trimmedInput.equals("*")) {
+ allowAll = true;
+ denyAll = false;
+ return;
+ } else if (trimmedInput.isEmpty()) {
+ allowAll = false;
+ denyAll = true;
+ return;
+ }
+ allowAll = false;
+ denyAll = false;
+ String[] tokens = input.split(",");
+ for (String rawToken : tokens) {
+ String token = checkToken(input, rawToken);
+ rules.add(URIPatternRule.parse(token));
+ }
+ }
+
+ private String checkToken(String input, String rawToken) {
+ String token = rawToken.trim();
+ if (token.isEmpty() && !rules.isEmpty()) {
+ throw new IllegalArgumentException("Invalid format for the resource.access property: "
+ + input + ". Empty rule cannot coexist with other rules.");
+ } else if (token.equals("*") && !rules.isEmpty()) {
+ throw new IllegalArgumentException("Invalid format for the resource.access property: "
+ + input + ". All access (*) rule cannot coexist with other rules.");
+ }
+ return token;
+ }
+
+ public boolean allows(URI uri) {
+ if (denyAll) return false;
+ if (allowAll) return true;
+ for (URIPatternRule rule : rules) {
+ if (rule.matches(uri)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() { return rawInput; }
+
+ /**
+ * Represents a parsed URI-based pattern rule.
+ */
+ public static class URIPatternRule {
+ private final String scheme;
+ private final HostPattern hostPattern;
+ private final Integer port; // null if not set
+ private final PathPattern pathPattern;
+ // for scheme==jar
+ private final URIPatternRule jarBaseRule;
+ private final PathPattern jarEntryPathPattern;
+
+ // Constructor for schemes other than jar
+ private URIPatternRule(String scheme, HostPattern hostPattern, Integer port, PathPattern pathPattern) {
+ this.scheme = scheme;
+ this.hostPattern = hostPattern;
+ this.port = port;
+ this.pathPattern = pathPattern;
+ this.jarBaseRule = null;
+ this.jarEntryPathPattern = null;
+ }
+
+ // Constructor for jar patterns
+ public URIPatternRule(URIPatternRule jarBaseRule, PathPattern jarEntryPathPattern) {
+ this.scheme = "jar";
+ this.hostPattern = null;
+ this.port = null;
+ this.pathPattern = null;
+ this.jarBaseRule = jarBaseRule;
+ this.jarEntryPathPattern = jarEntryPathPattern;
+ }
+
+ /**
+ * Parses the specified pattern string.
+ * Example patterns: file:*, file:/foo, http://foo.com, https://*.foo.com:8080
+ * @param pattern the pattern string
+ * @return an instance of URIPatternRule from the pattern string
+ */
+ public static URIPatternRule parse(String pattern) {
+ // Syntax: [scheme]:/{0,3}[host[:port]][/path-pattern]
+ int schemeSep = pattern.indexOf(':');
+ if (schemeSep <= 0)
+ throw new IllegalArgumentException("Missing or invalid scheme in resource access pattern: " + pattern);
+
+ String scheme = pattern.substring(0, schemeSep).toLowerCase(Locale.ROOT);
+ if (!isSupportedScheme(scheme))
+ throw new IllegalArgumentException("Unsupported scheme in resource access pattern: " + pattern);
+
+ if ("jar".equals(scheme)) {
+ int exclIdx = pattern.indexOf('!', scheme.length() + 1);
+ String nestedPart, entryPart;
+ boolean isLocalScheme = false;
+ if (exclIdx < 0) {
+ nestedPart = pattern.substring(scheme.length() + 1); // after "jar:"
+ entryPart = null;
+ isLocalScheme = nestedPart.startsWith("file") || nestedPart.startsWith("jar") || nestedPart.startsWith("jrt");
+ } else {
+ nestedPart = pattern.substring(scheme.length() + 1, exclIdx);
+ entryPart = pattern.substring(exclIdx + 1);
+ }
+
+ // Check for illegal forms
+ if (Utils.isEmpty(nestedPart) && Utils.isNotEmpty(entryPart))
+ throw new IllegalArgumentException("Invalid JAR rule: entry pattern present but missing jar base: " + pattern);
+ if (!isLocalScheme && Utils.isEmpty(entryPart) && Utils.isNotEmptyOrWildcard(nestedPart))
+ throw new IllegalArgumentException("Invalid JAR rule: entry pattern is empty: " + pattern);
+
+ URIPatternRule jarBaseRule = null;
+ if (Utils.isNotEmptyOrWildcard(nestedPart)) {
+ jarBaseRule = URIPatternRule.parse(nestedPart);
+ }
+ PathPattern jarEntryPathPattern = (entryPart == null || entryPart.isEmpty() || entryPart.equals("/*") || entryPart.equals("*"))
+ ? PathPattern.of("*")
+ : PathPattern.of(entryPart.startsWith("/") ? entryPart : "/" + entryPart);
+
+ return new URIPatternRule(jarBaseRule, jarEntryPathPattern);
+ }
+
+ String rest = pattern.substring(schemeSep + 1);
+ // Remove up to 3 leading slashes
+ String afterSlashes;
+
+ HostPattern hostPattern = null;
+ Integer port = null;
+ PathPattern pathPattern = null;
+ // Handle file/jar/jrt schemes as path patterns
+ boolean isLocalScheme = scheme.equals("file") || scheme.equals("jar") || scheme.equals("jrt");
+ if (isLocalScheme) {
+ // Remove up to 3 leading slashes
+ afterSlashes = rest.replaceFirst("^/{0,3}", "");
+ // Should be only path or wildcard, must not be empty (file: is not allowed)
+ if (afterSlashes.isEmpty())
+ throw new IllegalArgumentException(scheme + " rule must have non-empty path: " + pattern);
+ // afterSlashes is the path pattern, can be "*"
+ if (afterSlashes.equals("*")) {
+ pathPattern = PathPattern.of("*");
+ } else {
+ if (!afterSlashes.startsWith("/")) afterSlashes = "/" + afterSlashes;
+ pathPattern = PathPattern.of(afterSlashes);
+ }
+ } else {
+ // Remove up to 2 leading slashes
+ afterSlashes = rest.replaceFirst("^/{0,2}", "");
+ // Find "host[:port][/path]"
+ if (afterSlashes.isEmpty() || afterSlashes.startsWith(":") || afterSlashes.startsWith("/")) {
+ throw new IllegalArgumentException("Rule for scheme '" + scheme + "' must specify a non-empty host: " + pattern);
+ }
+
+ String hostPart;
+ String pathPart = null;
+ int slashIndex = afterSlashes.indexOf('/');
+ if (slashIndex >= 0) {
+ hostPart = afterSlashes.substring(0, slashIndex);
+ pathPart = afterSlashes.substring(slashIndex); // includes "/"
+ } else {
+ hostPart = afterSlashes;
+ }
+ // Validate host
+ if (hostPart.isEmpty())
+ throw new IllegalArgumentException("Host must not be blank for scheme: " + scheme);
+ // Port
+ int portSep = hostPart.lastIndexOf(':');
+ if (portSep > 0 && portSep < hostPart.length() - 1
+ && isPortNumber(hostPart.substring(portSep + 1))) {
+ hostPattern = HostPattern.of(hostPart.substring(0, portSep));
+ try {
+ port = Integer.parseInt(hostPart.substring(portSep + 1));
+ if (port < 0 || port > 65535)
+ throw new IllegalArgumentException("Port must be 0-65535: " + pattern);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Port must be numeric: " + pattern);
+ }
+ } else if (!hostPart.isEmpty()) {
+ hostPattern = HostPattern.of(hostPart);
+ }
+
+ // Validate path
+ if (pathPart != null && pathPart.length() > 1 && pathPart.indexOf("//") >= 0)
+ throw new IllegalArgumentException("Path component must not contain empty segments: " + pattern);
+
+ // pathPattern is set only if specified, null otherwise
+ if (pathPart != null && !pathPart.isEmpty() && !pathPart.equals("/*")) {
+ pathPattern = PathPattern.of(pathPart);
+ } else if (pathPart != null && (pathPart.isEmpty() || pathPart.equals("/*"))) {
+ pathPattern = PathPattern.of("*");
+ }
+ }
+ return new URIPatternRule(scheme, hostPattern, port, pathPattern);
+ }
+
+ public boolean matches(URI uri) {
+ if (uri == null) return false;
+ String testScheme = uri.getScheme();
+ if (testScheme == null || !testScheme.equalsIgnoreCase(scheme)) return false;
+
+ if ("jar".equalsIgnoreCase(testScheme)) {
+ String ssp = uri.getSchemeSpecificPart();
+ int exclIdx = ssp.indexOf("!/");
+ String basePart, entryPart;
+ if (exclIdx < 0) {
+ basePart = ssp;
+ entryPart = "";
+ } else {
+ basePart = ssp.substring(0, exclIdx);
+ entryPart = ssp.substring(exclIdx + 1); // may be empty
+ }
+ URI baseUri = URI.create(basePart);
+ boolean baseMatches = (jarBaseRule == null) || jarBaseRule.matches(baseUri); // wildcard/null means match any
+ boolean entryMatches = jarEntryPathPattern == null || jarEntryPathPattern.matches(entryPart); // always at least "/*"
+ return baseMatches && entryMatches;
+ }
+
+ // Local: path-pattern match only
+ if (hostPattern == null) {
+ if (pathPattern == null) return true; // match all local of that scheme
+ String uriPath = uri.getPath();
+ return pathPattern.matches(uriPath);
+ }
+
+ // Network: host and port required
+ String testHost = uri.getHost();
+ if (!hostPattern.matches(testHost)) return false;
+ if (port != null && port != (uri.getPort() == -1 ? getDefaultPort(scheme) : uri.getPort())) return false;
+ // If a pathPattern is present, also match path; else, path is ignored
+ if (pathPattern != null) {
+ String uriPath = uri.getPath();
+ return pathPattern.matches(uriPath);
+ }
+ return true;
+ }
+
+ private static boolean isSupportedScheme(String scheme) {
+ return switch (scheme) {
+ case "http", "https", "ftp", "file", "jar", "jrt" -> true;
+ default -> false;
+ };
+ }
+
+ /**
+ * Check if string is an integer between 0 and 65535 (valid TCP/UDP port range).
+ */
+ private static boolean isPortNumber(String str) {
+ try {
+ int port = Integer.parseInt(str);
+ return port >= 0 && port <= 65535;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ // standard ports for known schemes
+ private static int getDefaultPort(String scheme) {
+ return switch (scheme) {
+ case "http" -> 80;
+ case "https" -> 443;
+ case "ftp" -> 21;
+ default -> -1;
+ };
+ }
+ }
+
+
+ // Host pattern matching for exact, IPv4 and IPv6 hosts.
+ public static class HostPattern {
+ private final String pattern;
+ private final boolean isAny;
+ private final boolean isSubdomainPattern;
+ private final byte[] literalAddress;
+
+ private HostPattern(String pattern, boolean isAny, boolean isSubdomainPattern, byte[] literalAddress) {
+ this.pattern = pattern;
+ this.isAny = isAny;
+ this.isSubdomainPattern = isSubdomainPattern;
+ this.literalAddress = literalAddress;
+ }
+
+ public static HostPattern of(String hostPattern) {
+ String trimmed = hostPattern.trim();
+ if (trimmed.equals("*")) {
+ return new HostPattern("*", true, false, null);
+ }
+ if (trimmed.startsWith("*.")) {
+ // *.example.com
+ return new HostPattern(trimmed.substring(2).toLowerCase(Locale.ROOT), false, true, null);
+ }
+ byte[] literalAddress = parseLiteralAddress(trimmed);
+ if (literalAddress != null)
+ return new HostPattern(trimmed, false, false, literalAddress);
+ // Otherwise, treat as literal domain
+ return new HostPattern(trimmed.toLowerCase(Locale.ROOT), false, false, null);
+ }
+
+ public boolean matches(String testHost) {
+ if (isAny) return true;
+ if (testHost == null) return false;
+ if (literalAddress != null) {
+ byte[] testAddress = parseLiteralAddress(testHost);
+ return testAddress != null && Arrays.equals(literalAddress, testAddress);
+ }
+ testHost = testHost.toLowerCase(Locale.ROOT);
+ // Subdomain wildcard
+ if (isSubdomainPattern) {
+ return testHost.endsWith("." + pattern);
+ }
+ // Exact match (domain, IPv4, or IPv6)
+ return testHost.equals(pattern);
+ }
+
+ private static byte[] parseLiteralAddress(String host) {
+ try {
+ return Inet4Address.ofLiteral(host).getAddress();
+ } catch (IllegalArgumentException ignored) {
+ // Not an IPv4 literal; try IPv6 below.
+ }
+
+ try {
+ return Inet6Address.ofLiteral(host).getAddress();
+ } catch (IllegalArgumentException ignored) {
+ return null;
+ }
+ }
+
+ }
+
+ public static class PathPattern {
+ private final String pattern; // E.g. /dtds/* or /*
+ private final boolean isAny;
+ private final boolean isDirectory; // endsWith /*
+
+ private PathPattern(String pattern, boolean isAny, boolean isDirectory) {
+ this.pattern = pattern;
+ this.isAny = isAny;
+ this.isDirectory = isDirectory;
+ }
+
+ public static PathPattern of(String pattern) {
+ pattern = (pattern == null || pattern.isEmpty()) ? "/" : pattern;
+ // supports *, /foo/*, /foo/bar
+ if (pattern.equals("*") || pattern.equals("/*")) {
+ return new PathPattern(pattern, true, false);
+ }
+ if (pattern.endsWith("/*")) {
+ return new PathPattern(pattern.substring(0, pattern.length() - 2), false, true);
+ }
+ return new PathPattern(pattern, false, false);
+ }
+
+ public boolean matches(String testPath) {
+ if (isAny) return true;
+ if (testPath == null) return false;
+ if (isDirectory) {
+ // Path starts with this directory
+ return testPath.startsWith(pattern + "/") || testPath.equals(pattern);
+ }
+ return testPath.equals(pattern);
+ }
+ }
+}
diff --git a/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java b/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java
index 0a17ffa1121..d311b778723 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/FeaturePropertyBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, 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
@@ -24,23 +24,12 @@
*/
package jdk.xml.internal;
+import jdk.xml.internal.JdkProperty.State;
/**
* This is the base class for features and properties
*/
public abstract class FeaturePropertyBase {
-
- /**
- * States of the settings of a property, in the order: default value, value
- * set by FEATURE_SECURE_PROCESSING, jaxp.properties file, jaxp system
- * properties, and jaxp api properties
- */
- public static enum State {
- //this order reflects the overriding order
- DEFAULT, FSP, JAXPDOTPROPERTIES, SYSTEMPROPERTY, APIPROPERTY
- }
-
-
/**
* Values of the properties as defined in enum Properties
*/
diff --git a/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java b/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java
index 412eddb5ab0..927d19bc3b3 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/JdkConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, 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
@@ -311,6 +311,17 @@ public final class JdkConstants {
//public static final int IGNORE = 1; // same as that of DTD
public static final int STRICT = 2;
+ /**
+ * System Property for the Resource Access property
+ * @since 26
+ */
+ public static final String RESOURCE_ACCESS = "jdk.xml.resource.access";
+
+ // Integer Values that maps to broad access settings such as *, remote
+ public static final int ACCESS_NONE = 0;
+ public static final int ACCESS_ALL = 1; // same as that of DTD
+ public static final int ACCESS_REMOTE = 2;
+
/**
* Values for a feature
*/
diff --git a/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java b/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java
index 9e718b264e4..f66463833ef 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026, 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
@@ -113,7 +113,7 @@ public class JdkXmlUtils {
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 xspm.setValue(property, JdkProperty.State.APIPROPERTY, value);
}
return false;
}
diff --git a/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java b/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
index 478d12220d7..2787ba67b5f 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -29,15 +29,18 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.text.MessageFormat;
+import java.util.HashSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
+import java.util.Set;
/**
* This class contains utility methods for reading resources in the JAXP packages
@@ -267,66 +270,90 @@ public class SecuritySupport {
return input;
}
+ /**
+ * Checks whether access to resource represented by the systemId is permitted
+ * by Resource Access and/or External Access Properties (EAP)
+ * @param systemId the systemId
+ * @param xsm the XMLSecurityManager
+ * @param eap the External Access Property, e.g. ACCESS_EXTERNAL_DTD
+ * @param allowedProtocols protocols allowed by the EAP
+ * @return true if access is permitted, false otherwise
+ * @throws IOException if the systemId is invalid
+ */
+ public static String checkAccess(String systemId, XMLSecurityManager xsm,
+ String eap, String allowedProtocols) {
+ String errMsg = null;
+ if (xsm != null && !xsm.isAccessAllowed(systemId)) {
+ errMsg = "Resource Access (jdk.xml.resource.access)";
+ }
+
+ if (!checkAccess(systemId, allowedProtocols)) {
+ errMsg = (errMsg != null) ? errMsg + " and " + eap : eap;
+ }
+ return errMsg;
+ }
+
/**
* Check the protocol used in the systemId against allowed protocols
*
* @param systemId the Id of the URI
* @param allowedProtocols a list of allowed protocols separated by comma
- * @param accessAny keyword to indicate allowing any protocol
- * @return the name of the protocol if rejected, null otherwise
+ * @return true if access is permitted, false otherwise
*/
- public static String checkAccess(String systemId, String allowedProtocols,
- String accessAny) throws IOException {
+ public static boolean checkAccess(String systemId, String allowedProtocols) {
+ if (Utils.isEmpty(allowedProtocols)) {
+ return false;
+ }
if (systemId == null || (allowedProtocols != null &&
- allowedProtocols.equalsIgnoreCase(accessAny))) {
- return null;
+ allowedProtocols.equalsIgnoreCase(JdkConstants.ACCESS_EXTERNAL_ALL))) {
+ return true;
}
- String protocol;
- if (!systemId.contains(":")) {
- protocol = "file";
+ URI uri = Utils.createURI(systemId);
+ String scheme = uri.getScheme();
+ if (scheme == null) {
+ scheme = "file";
} else {
- @SuppressWarnings("deprecation")
- URL url = new URL(systemId);
- protocol = url.getProtocol();
- if (protocol.equalsIgnoreCase("jar")) {
- String path = url.getPath();
- protocol = path.substring(0, path.indexOf(":"));
- } else if (protocol.equalsIgnoreCase("jrt")) {
- // if the systemId is "jrt" then allow access if "file" allowed
- protocol = "file";
+ scheme = scheme.toLowerCase(Locale.ROOT);
+ if ("jar".equals(scheme)) {
+ String ssp = uri.getSchemeSpecificPart(); // e.g. file:/x.jar!/a.xml
+ int sep = ssp.indexOf("!/");
+ if (sep != -1) {
+ URI nested = Utils.createURI(ssp.substring(0, sep));
+ String nestedScheme = nested.getScheme();
+ if (nestedScheme != null) {
+ scheme = nestedScheme.toLowerCase(Locale.ROOT);
+ }
+ }
+ } else if ("jrt".equals(scheme)) {
+ // allow access if it's "file"
+ scheme = "file";
}
}
- if (isProtocolAllowed(protocol, allowedProtocols)) {
- //access allowed
- return null;
- } else {
- return protocol;
- }
+ Set allowed = parseProtocols(allowedProtocols);
+ return allowed.contains(scheme);
}
/**
- * Check if the protocol is in the allowed list of protocols. The check
- * is case-insensitive while ignoring whitespaces.
- *
- * @param protocol a protocol
- * @param allowedProtocols a list of allowed protocols
- * @return true if the protocol is in the list
+ * Parses allowed protocols.
+ * @param protocols the protocol setting
+ * @return a set containing allowed protocols
*/
- private static boolean isProtocolAllowed(String protocol, String allowedProtocols) {
- if (allowedProtocols == null) {
- return false;
- }
- String temp[] = allowedProtocols.split(",");
- for (String t : temp) {
- t = t.trim();
- if (t.equalsIgnoreCase(protocol)) {
- return true;
- }
- }
- return false;
- }
+ private static Set parseProtocols(String protocols) {
+ Set set = new HashSet<>();
+ if (protocols == null || protocols.isEmpty()) {
+ return set;
+ }
+
+ for (String p : protocols.split(",")) {
+ String trimmed = p.trim().toLowerCase(Locale.ROOT);
+ if (!trimmed.isEmpty()) {
+ set.add(trimmed);
+ }
+ }
+ return set;
+ }
public static ClassLoader getContextClassLoader() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
diff --git a/src/java.xml/share/classes/jdk/xml/internal/Utils.java b/src/java.xml/share/classes/jdk/xml/internal/Utils.java
index 96d9b1b9521..f7f5c49387b 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/Utils.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/Utils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, 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
@@ -26,6 +26,8 @@
package jdk.xml.internal;
import java.lang.reflect.Array;
+import java.net.URI;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Supplier;
@@ -132,6 +134,52 @@ public class Utils {
* @return {@code true} if the CharSequence is empty or null
*/
public static boolean isEmpty(final CharSequence cs) {
- return cs == null || cs.length() == 0;
+ return cs == null || cs.isEmpty();
+ }
+
+ /**
+ * Checks if a CharSequence is not null and empty ("").
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is not null and empty ("")
+ */
+ public static boolean isNotEmpty(final CharSequence cs) {
+ return cs != null && !cs.isEmpty();
+ }
+
+ /**
+ * Checks if a CharSequence is not null and empty (""), and also does not end
+ * with a wildcard (*).
+ * @param cs the CharSequence to check, may be null
+ * @return {@code true} if the CharSequence is not null and empty ("") and does
+ * not end with a wildcard
+ */
+ public static boolean isNotEmptyOrWildcard(final CharSequence cs) {
+ return cs != null && !cs.isEmpty() && (cs.charAt(cs.length() - 1) != '*');
+ }
+
+ /**
+ * Creates a {@link URI} instance from a systemId.
+ * This method handles strings that are either absolute URIs or local file
+ * system paths.
+ *
+ * @param systemId the systemId
+ * @return a {@link URI} instance corresponding to the systemId
+ */
+ public static URI createURI(String systemId) {
+ if (systemId == null) {
+ return null;
+ }
+
+ try {
+ URI uri = new URI(systemId);
+
+ if (uri.getScheme() == null) {
+ return Path.of(systemId).toUri();
+ }
+ return uri;
+ } catch (Exception e) {
+ // fallback for paths with illegal characters (e.g. spaces)
+ return Path.of(systemId).toUri();
+ }
}
}
diff --git a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java
index a1687c420c3..336b101f8ac 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, 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
@@ -26,6 +26,8 @@ package jdk.xml.internal;
import com.sun.org.apache.xerces.internal.util.SecurityManager;
+
+import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -82,6 +84,17 @@ public final class XMLSecurityManager implements Cloneable {
CR_MAP = Collections.unmodifiableMap(map);
}
+ // Valid values for Resource Access, and mappings between the string and
+ // integer values
+ static final Map RA_MAP;
+ // Source Level JDK 8
+ static {
+ Map map = new HashMap<>();
+ map.put("*", 0);
+ map.put("", 2);
+ RA_MAP = Collections.unmodifiableMap(map);
+ }
+
// Value converter for properties of type Boolean
private static final BooleanMapper BOOLMAPPER = new BooleanMapper();
@@ -94,6 +107,9 @@ public final class XMLSecurityManager implements Cloneable {
// Catalog Resolve value mapper
private static final StringMapper CRMAPPER = new StringMapper(CR_MAP);
+ // Resource Access value mapper
+ private static final StringMapper RAMAPPER = new StringMapper(RA_MAP);
+
/**
* Limits managed by the security manager
*/
@@ -129,6 +145,8 @@ public final class XMLSecurityManager implements Cloneable {
STAX_SUPPORT_DTD("supportDTD", XMLInputFactory.SUPPORT_DTD, null, null, 1, 1, Processor.PARSER, BOOLMAPPER),
JDKCATALOG_RESOLVE("JDKCatalogResolve", JdkConstants.JDKCATALOG_RESOLVE, JdkConstants.JDKCATALOG_RESOLVE, null,
JdkConstants.CONTINUE, JdkConstants.CONTINUE, Processor.PARSER, CRMAPPER),
+ RESOURCE_ACCESS("ResourceAccess", JdkConstants.RESOURCE_ACCESS, JdkConstants.RESOURCE_ACCESS, null,
+ JdkConstants.ALLOW, JdkConstants.ALLOW, Processor.PARSER, RAMAPPER),
;
final String key;
@@ -262,6 +280,8 @@ public final class XMLSecurityManager implements Cloneable {
private final int indexEntityCountInfo = 10000;
private String printEntityCountInfo = "";
+ private AccessRule accessRule = null;
+
/**
* Default constructor. Establishes default values for known security
* vulnerabilities.
@@ -289,6 +309,11 @@ public final class XMLSecurityManager implements Cloneable {
states[limit.ordinal()] = State.DEFAULT;
}
}
+ if (secureProcessing) {
+ accessRule = (Limit.RESOURCE_ACCESS.secureValue == JdkConstants.ALLOW) ? AccessRule.RULE_ALL : AccessRule.RULE_NONE;
+ } else {
+ accessRule = (Limit.RESOURCE_ACCESS.defaultValue() == JdkConstants.ALLOW) ? AccessRule.RULE_ALL : AccessRule.RULE_NONE;
+ }
}
/**
@@ -380,6 +405,15 @@ public final class XMLSecurityManager implements Cloneable {
* @return the limit's new name if found, null otherwise
*/
public String find(String propertyName) {
+ /*
+ * Access property is unique in its value type. Using the SecurityManager
+ * infrastructure, but handles differently than other limits
+ */
+ if (Limit.RESOURCE_ACCESS.is(propertyName)) {
+ return (Limit.RESOURCE_ACCESS.systemProperty != null)
+ ? Limit.RESOURCE_ACCESS.systemProperty
+ : Limit.RESOURCE_ACCESS.apiProperty;
+ }
for (Limit limit : Limit.values()) {
if (limit.is(propertyName)) {
// current spec: new property name == systemProperty
@@ -440,6 +474,24 @@ public final class XMLSecurityManager implements Cloneable {
* @param value the value of the property
*/
public void setLimit(Limit limit, State state, Object value) {
+ /*
+ * Access property is unique in its value type. Using the SecurityManager
+ * infrastructure, but handles differently than other limits
+ */
+ if (limit == Limit.RESOURCE_ACCESS) {
+ int index = limit.ordinal();
+ if (state.compareTo(states[index]) >= 0) {
+ String ruleValue = (String)value;
+ AccessRule rule = new AccessRule(ruleValue);
+ int intValue = limit.mapper().toInt(ruleValue);
+ accessRule = rule;
+ values[index] = intValue;
+ states[index] = state;
+ isSet[index] = true;
+ }
+ return;
+ }
+
int intValue = limit.mapper().toInt(value);
if (intValue < 0) {
intValue = 0;
@@ -469,6 +521,29 @@ public final class XMLSecurityManager implements Cloneable {
}
}
+ public AccessRule getAccessRule() {
+ return accessRule;
+ }
+
+ public boolean isAccessAllowed(String systemId) {
+ URI uri = Utils.createURI(systemId);
+ if (uri == null) return true;
+ return isAccessAllowed(uri);
+ }
+
+ /**
+ * Checks the RESOURCE_ACCESS property to see if access to the specified
+ * uri is allowed.
+ *
+ * @param uri the specified uri
+ * @return true if the RESOURCE_ACCESS property is set to allow access to the
+ * specified uri, false otherwise
+ */
+ public boolean isAccessAllowed(URI uri) {
+ return accessRule.allows(uri);
+ }
+
+
/**
* Return the value of the specified property
*
@@ -477,6 +552,10 @@ public final class XMLSecurityManager implements Cloneable {
* by this manager, its value shall not be null.
*/
public String getLimitAsString(String propertyName) {
+ if (Limit.RESOURCE_ACCESS.is(propertyName)) {
+ return accessRule.toString();
+ }
+
int index = getIndex(propertyName);
if (index > -1) {
return getLimitValueByIndex(index);
@@ -620,10 +699,10 @@ public final class XMLSecurityManager implements Cloneable {
}
/**
- * Check against cumulated value
+ * Check limit against the cumulated value
*
* @param limit the type of the limit property
- * @param size the size (count or length) of the entity
+ * @param limitAnalyzer the limit analyzer
* @return true if the size is over the limit, false otherwise
*/
public boolean isOverLimit(Limit limit, XMLLimitAnalyzer limitAnalyzer) {
@@ -739,7 +818,7 @@ public final class XMLSecurityManager implements Cloneable {
try {
String value = System.getProperty(sysPropertyName);
- if (value != null && !value.equals("")) {
+ if (isPropertyValuePresent(limit, value)) {
setLimit(limit, State.SYSTEMPROPERTY, value);
return true;
}
@@ -760,7 +839,7 @@ public final class XMLSecurityManager implements Cloneable {
private boolean getPropertyConfig(Limit limit, String sysPropertyName) {
try {
String value = SecuritySupport.readConfig(sysPropertyName);
- if (value != null && !value.equals("")) {
+ if (isPropertyValuePresent(limit, value)) {
setLimit(limit, State.JAXPDOTPROPERTIES, value);
return true;
}
@@ -771,6 +850,10 @@ public final class XMLSecurityManager implements Cloneable {
return false;
}
+ private boolean isPropertyValuePresent(Limit limit, String value) {
+ return value != null && (!value.isEmpty() || limit == Limit.RESOURCE_ACCESS);
+ }
+
/**
* Convert a value set through setProperty to XMLSecurityManager.
* If the value is an instance of XMLSecurityManager, use it to override the default;
diff --git a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java
index ff9ab621fab..226a5e34fbc 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityPropertyManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, 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
@@ -26,6 +26,7 @@
package jdk.xml.internal;
import javax.xml.XMLConstants;
+import jdk.xml.internal.JdkProperty.State;
/**
* This class manages security related properties
@@ -161,6 +162,15 @@ public final class XMLSecurityPropertyManager extends FeaturePropertyBase implem
return values[property.ordinal()];
}
+ /**
+ * {@return the state of the specified property}
+ *
+ * @param property the specified property
+ */
+ public State getState(Property property) {
+ return states[property.ordinal()];
+ }
+
/**
* Read from system properties, or those in jaxp.properties
*/
diff --git a/src/java.xml/share/classes/module-info.java b/src/java.xml/share/classes/module-info.java
index 1b4f345eb72..fe9c116f7d2 100644
--- a/src/java.xml/share/classes/module-info.java
+++ b/src/java.xml/share/classes/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2026, 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
@@ -23,6 +23,8 @@
* questions.
*/
+import java.net.URI;
+
/**
* Defines the Java APIs for XML Processing (JAXP).
*
@@ -197,6 +199,14 @@
*
*
*
+ * If more than one property affects an aspect of operation, all properties must
+ * permit the operation in order for it to proceed. For example, both the
+ * Resource Access property
+ * and External Access Properties (EAPs) must
+ * be set to allow in order for a direct fetch of an external resource to be
+ * carried out. For more details, refer to the
+ * External Resource Resolution Process.
+ *
* Using the {@link javax.xml.catalog.CatalogFeatures CatalogFeatures}' RESOLVE
* property as an example, the following illustrates how these rules are applied:
*
* The catalog is loaded once when the first JAXP processor factory is created.
*
- *
External Resource Resolution Process with the built-in Catalog
- * The JDK creates a {@link javax.xml.catalog.CatalogResolver CatalogResolver}
- * with the built-in catalog when needed. This CatalogResolver is used as the
- * default external resource resolver.
+ *
External Resource Resolution Process
*
- * XML processors may use resolvers (such as {@link org.xml.sax.EntityResolver EntityResolver},
- * {@link javax.xml.stream.XMLResolver XMLResolver}, and {@link javax.xml.catalog.CatalogResolver CatalogResolver})
- * to handle external references. In the absence of the user-defined resolvers,
- * the JDK XML processors fall back to the default CatalogResolver to attempt to
- * find a resolution before making a connection to fetch the resources. The fall-back
- * also takes place if a user-defined resolver exists but allows the process to
- * continue when unable to resolve the resource.
+ * The XML processor resolves external resources using the following steps:
+ *
+ *
User-defined resolver, such as {@link org.xml.sax.EntityResolver EntityResolver},
+ * {@link javax.xml.stream.XMLResolver XMLResolver}, if registered on the XML factory
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} if registered or
+ * if a catalog file is provided
+ *
The JDK Built-in Catalog
+ *
Direct fetch
+ *
+ *
*
- * If the default CatalogResolver is unable to locate a resource, it may signal
- * the XML processors to continue processing, or skip the resource, or
- * throw a CatalogException. The behavior is configured with the
- * {@code jdk.xml.jdkcatalog.resolve} property.
+ * If a resolver or catalog successfully resolves the resource, the process ends.
+ * Otherwise, the XML processor evaluates the signal returned to decide whether
+ * to continue, ignore, or reject the resource.
+ *
+ * It continues to the next step if:
+ *
+ *
User-defined resolver returns {@code null}
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} returns {@code null}
+ * and the {@link javax.xml.catalog.CatalogFeatures.Feature#RESOLVE RESOLVE} feature
+ * is set to {@code continue}
+ *
+ *
The JDK Built-in Catalog returns {@code null} and its Resolve property
+ * {@code jdk.xml.jdkcatalog.resolve} is set to {@code continue}
+ * It ignores the resource and returns an empty source if:
+ *
+ *
User-defined resolver returns an empty source
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} returns an empty source
+ * and the {@link javax.xml.catalog.CatalogFeatures.Feature#RESOLVE RESOLVE} feature
+ * is set to {@code ignore}
+ *
+ *
+ *
+ * It terminates and throws an exception if:
+ *
+ *
User-defined resolver throws an exception
+ *
{@link javax.xml.catalog.CatalogResolver CatalogResolver} returns {@code null},
+ * the {@link javax.xml.catalog.CatalogFeatures.Feature#RESOLVE RESOLVE} feature
+ * is {@code strict}
+ *
* In addition to the standard JAXP Properties,
@@ -871,7 +915,7 @@
*
Determines whether extension functions in the Transform API are to be allowed.
* The extension functions in the XPath API are not affected by this property.
*
- *
yes
+ *
yes
*
Boolean
*
* true or false. True indicates that extension functions are allowed; False otherwise.
@@ -994,6 +1038,109 @@
*
+ * Except where this specification explicitly extends or overrides the syntax or
+ * semantics defined by the {@link java.net.URI URI} class, such as the support for wildcard
+ * patterns, the definitions of {@link java.net.URI URI} apply.
+ * Where:
+ *
+ *
Component Syntax: A resource access entry is either:
+ *
+ *
+ * An exact-match URI, where the scheme, host, port, and path components
+ * must conform to the syntax requirements of the {@link java.net.URI URI}
+ * class and the URI is interpreted as a hierarchical URI.
+ *
+ *
+ * A wildcard URI pattern, where the URI syntax is extended to allow
+ * the wildcard {@code *} in the components explicitly defined by this specification.
+ * The wildcard matching rules for each supported component are described below.
+ *
+ *
+ * For both forms, the scheme and host are case-insensitive, while the path is case-sensitive.
+ *
+ *
scheme: The URI scheme. Unless the entire pattern is the single wildcard {@code *},
+ * the scheme must be one of the supported schemes (http, https, ftp, file, or jrt).
+ *
+ *
jar: jar URIs are matched against the URI of the underlying JAR file
+ * using the corresponding rule pattern. For example, the rule pattern
+ * {@code file:/tmp/foo.jar} permits access to {@code jar:file:/tmp/foo.jar!/dtds/test.dtd}.
+ *
+ * Permission to access the JAR file automatically grants access to all entries within
+ * that JAR; entry-level restrictions are not supported.
+ *
+ *
/ (slash): The slash following the scheme may appear one to three times.
+ * Two slashes (//) indicate the start of an authority (for example, http://example.com).
+ * One or three slashes (/ or ///) indicate the start of a local resource path
+ * (for example, {@code file:/foo/bar.dtd, file:///foo/bar.dtd}).
+ *
+ *
host: Optional. A domain name, IPv4 address, IPv6 literal, or supported
+ * wildcard pattern. The wildcard {@code *} denotes any host. A leading wildcard followed
+ * by a domain, such as {@code*.example.com}, matches all subdomains of {@code example.com}.
+ * For network schemes, the host component must not be empty.
+ *
IPv6 Literals: IPv6 literals must be enclosed in square brackets,
+ * as defined by {@link java.net.URI URI}, for example {@code https://[2001:db8::6]}
+ *
port: Optional. A decimal port number, as per the URI standard,
+ * to indicate only the specified port is permitted. If specified,
+ * it can not be empty. {@code http://example.com:}, for example, is illegal.
+ *
path pattern: Optional. Specifies a resource path. Wildcard {@code *}
+ * may be used in the path to match any sequence (e.g., {@code /foo/*} matches
+ * all resources under {@code /foo/}). For local schemes, paths are typically
+ * absolute (e.g., {@code file:/dtds/*}). To match all resources under a directory,
+ * the wildcard {@code *} must be added. Without it, the path is treated as
+ * a literal file or directory.
+ *
entire pattern: can be a wildcard {@code *} or empty "", which
+ * represents all access or no access permitted respectively.
+ *
wildcard: The wildcard {@code *} may be used only in the forms
+ * explicitly defined by this specification:
+ *
+ *
as the entire pattern ({@code *});
+ *
as the entire host component ({@code http://*});
+ *
as a leading wildcard in the host component ({@code http://*.example.com});
+ *
as the final path segment ({@code file:/foo/*}).
+ *
+ * Any other occurrence of * is treated as a literal character and does not perform wildcard matching.
+ *
@@ -1037,6 +1184,11 @@
* These three properties control whether DTDs as a whole shall be processed. When
* they are set to deny or ignore, other properties that regulate a part or an
* aspect of DTD shall have no effect.
+ *
+ * [8] In the current release, the state of the {@code jdk.xml.resource.access}
+ * property does not change when {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING FEATURE_SECURE_PROCESSING}
+ * (FSP) is enabled. In future releases, it will transition to a restrictive setting
+ * when FSP is enabled.
*
*
Legacy Property Names (deprecated)
* JDK releases prior to JDK 17 support the use of URI style prefix for properties.
diff --git a/src/java.xml/share/conf/jaxp.properties b/src/java.xml/share/conf/jaxp.properties
index 2b7136319ce..58c7044af77 100644
--- a/src/java.xml/share/conf/jaxp.properties
+++ b/src/java.xml/share/conf/jaxp.properties
@@ -95,6 +95,81 @@ jdk.xml.overrideDefaultParser=false
# javax.xml.accessExternalStylesheet="all"
#
#
+# XML Resource Access Property:
+#
+# A comma-separated list of URI patterns, * (wildcard), or "" (empty string),
+# each following the syntax: scheme:[/][host][:port]/[path]
+#
+# Component Syntax: A resource access entry is either:
+# - An exact-match URI, where the scheme, host, port, and path components must conform
+# to the syntax requirements of the java.net.URI class.
+# - A wildcard URI pattern, where the URI syntax is extended to allow the wildcard *
+# in the components explicitly defined by this specification.
+#
+# For both forms, the scheme and host are case-insensitive, while the path is case-sensitive.
+#
+# scheme: The URI scheme. Unless the entire pattern is the single wildcard *,
+# the scheme must be one of the supported schemes (http, https, ftp, file, or jrt).
+#
+# jar: jar URIs are matched against the URI of the underlying JAR file using the
+# corresponding rule pattern. For example, the rule pattern file:/tmp/foo.jar permits
+# access to jar:file:/tmp/foo.jar!/dtds/test.dtd.
+#
+# Permission to access the JAR file automatically grants access to all entries within that JAR;
+# entry-level restrictions are not supported.
+
+# / (slash): The slash following the scheme may appear one to three times.
+# Two slashes (//) indicate the start of an authority (for example, http://example.com).
+# One or three slashes (/ or ///) indicate the start of a local resource path
+# (for example, file:/foo/bar.dtd or file:///foo/bar.dtd).
+
+# host: Optional. A domain name, IPv4 address, IPv6 literal, or supported wildcard pattern.
+# The wildcard * denotes any host. A leading wildcard followed by a domain,
+# such as *.example.com, matches all subdomains of example.com. For network schemes,
+# the host component must not be empty.
+#
+# IPv6 Literals: IPv6 literals must be enclosed in square brackets,
+# as defined by java.net.URI, for example https://[2001:db8::6].
+#
+# port: Optional. A decimal port number, as per the URI standard, to indicate only
+# the specified port is permitted. If specified, it can not be empty.
+# http://example.com:, for example, is illegal.
+#
+# path: Optional. Specifies a resource path. Wildcard * may be used in the path
+# to match any sequence (e.g., /foo/* matches all resources under /foo/).
+# For local schemes, paths are typically absolute (e.g., file:/dtds/*).
+# To match all resources under a directory, the wildcard * must be added.
+# Without it, the path is treated as a literal file or directory.
+#
+# entire pattern: can be a wildcard * or empty "", which represents all access
+# or no access permitted respectively.
+#
+# wildcard: The wildcard * may be used only in the forms explicitly defined by this specification:
+# - as the entire pattern (*);
+# - as the entire host component (http://*);
+# - as a leading wildcard in the host component (http://*.example.com);
+# - as the final path segment (file:/foo/*).
+#
+# Any other occurrence of * is treated as a literal character and does not perform wildcard matching.
+#
+#
+# Example:
+# jdk.xml.resource.access = https://*.sun.com, http://www.w3.org, https://127.0.0.1, file:/dtds/, jrt:*, file:/tmp/foo.jar
+#Examples:
+#
+# jdk.xml.resource.access = https://*.example.com, http://www.example.com, https://127.0.0.1, \
+# https://127.0.0.1:80, https://[fe80::1%lo0], https://[fe80::1%lo0]:80, file:/dtds/*, jrt:/*, file:/tmp/foo.jar
+#
+# This configuration permits access to:
+# - https access to any subdomain of example.com, e.g. foo.example.com
+# - Resources from specific domain as listed in the example, example.com, 127.0.0.1 and [fe80::1%lo0]
+# - All local resources under the dtds directory
+# - Resources from the Java runtime image
+# - Resources from local /tmp/foo.jar
+#
+# The default setting allows unrestricted access
+jdk.xml.resource.access=*
+#
# Catalog Properties:
#
# The Catalog API defines four features: FILES, PREFER, DEFER and RESOLVE.
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java
new file mode 100644
index 00000000000..0513896a7f6
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+import jdk.xml.internal.AccessRule;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.net.URI;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+
+/*
+ * @test
+ * @bug 8357394
+ * @summary Verifies access rules defined by property jdk.xml.resource.access
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest /test/lib
+ * @modules java.xml/jdk.xml.internal
+ * @run junit/othervm common.access.AccessRuleTest
+ */
+public class AccessRuleTest {
+ /**
+ * Returns test data for testAccessRule.
+ * Data: rules, URI strings, result (true if allowed, false otherwise)
+ * @return test data for testAccessRule
+ */
+ private static Stream testData() {
+
+ return Stream.of(
+ Arguments.of("*", "http://all.access", true),
+ Arguments.of("", "http://no.access", false),
+ Arguments.of("http:*; http:/*; http://*", "http://all.http.access", true),
+ Arguments.of("http://*.oracle.com", "http://subdomains.oracle.com/dtds/example.dtd", true),
+ Arguments.of("https:*;https:/*;https://*", "https://all.https.access", true),
+ Arguments.of("https://*.oracle.com", "https://subdomains.oracle.com/dtds/example.dtd", true),
+ Arguments.of("file:*;file:/*;file://*;file:///*", "file://all.file.access", true),
+ Arguments.of("http://www.oracle.com", "http://www.oracle.com/dtds/example.dtd", true),
+ Arguments.of("http://www.oracle.com, http://*.oracle.com",
+ "http://www.oracle.com/dtds/example.dtd; http://subdomains.oracle.com/dtds/example.dtd", true),
+ Arguments.of("file:/dtds/dtd1.dtd", "file:/dtds/dtd1.dtd", true),
+ Arguments.of("file:/dtds/dtd1.dtd, file:/xsds/*", "file:/dtds/dtd1.dtd; file:/xsds/example.xsd", true),
+ Arguments.of("http://www.oracle.com, file:/dtds/dtd1.dtd, file:/xsds/*",
+ "http://www.oracle.com/dtds/example.dtd; file:/dtds/dtd1.dtd; file:/xsds/example.xsd", true),
+ Arguments.of("http://[2001:db8::1]",
+ "http://[2001:0db8:0000:0000:0000:0000:0000:0001]/dtds/example.dtd; "
+ + "http://[2001:db8:0:0:0:0:0:1]/dtds/example.dtd", true),
+ Arguments.of("http://[2001:0db8:0000:0000:0000:0000:0000:0001]",
+ "http://[2001:db8::1]/dtds/example.dtd", true),
+ Arguments.of("jrt:*; jrt:/java.xml/*", "jrt:/java.xml/jdk/xml/internal/jdkcatalog/JDKCatalog.xml", true),
+ Arguments.of("jar:file:/tmp/foo.jar; jar:file:/tmp/foo.jar!/dtds/*", "jar:file:/tmp/foo.jar!/dtds/example.dtd", true),
+ Arguments.of("jar:*; jar:file:*", "jar:file://all.file.access", true)
+ );
+ }
+
+ /**
+ * Returns test data for testInvalidRules.
+ * Data: rules, exception class
+ * @return test data for testInvalidRules
+ */
+ private static Stream testInvalidInput() {
+
+ return Stream.of(
+ Arguments.of("http://:8080", IllegalArgumentException.class),
+ Arguments.of("http:///dtds", IllegalArgumentException.class),
+ Arguments.of("scheme", IllegalArgumentException.class),
+ Arguments.of("http", IllegalArgumentException.class),
+ Arguments.of("http:", IllegalArgumentException.class),
+ Arguments.of("http://:8080", IllegalArgumentException.class),
+ Arguments.of("http:///dtds", IllegalArgumentException.class),
+ Arguments.of("http://example.com, , file:*", IllegalArgumentException.class),
+ Arguments.of("http://example.com, *, file:*", IllegalArgumentException.class)
+ );
+ }
+
+ /**
+ * Verifies that the Access External Properties are supported throughout the
+ * JAXP APIs.
+ * @param rules the access rules separate by ";"
+ * @param systemIds system IDs represented as semicolon-separated URI strings
+ * @param permitted the flag indicating whether the rules permit the resource
+ * represented by the systemId
+ * @throws Exception if the test fails due to test configuration issues other
+ * than the expected result
+ */
+ @ParameterizedTest
+ @MethodSource("testData")
+ public void testAccessExternalProperties(String rules, String systemIds, boolean permitted)
+ throws Exception {
+ String[] accessRules = rules.split(";");
+ for (String rule : accessRules) {
+ AccessRule accessRule = new AccessRule(rule.trim());
+ String[] ids = systemIds.split(";");
+ for (String systemId : ids) {
+ assertEquals(accessRule.allows(URI.create(systemId.trim())), permitted);
+ }
+ }
+ }
+
+ /**
+ * Verifies that the specified rule is invalid.
+ * @param rule indicates whether there is a custom resolver
+ * @param expectedType the expected throw type
+ * @throws Exception if the test fails other than the expected Exception, which
+ * would indicate an issue in configuring the test
+ */
+ @ParameterizedTest
+ @MethodSource("testInvalidInput")
+ public void testAccessRule(String rule, Class expectedType) throws Exception {
+ assertThrows(expectedType, () -> parseRules(rule));
+
+ }
+
+ /**
+ * Attempts to parse an access rule
+ * @param rule the access rule
+
+ * @throws Exception if the test fails due to test configuration issues other
+ * than the expected result
+ */
+ private void parseRules(String rule) {
+ AccessRule accessRule = new AccessRule(rule.trim());
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessTestBase.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessTestBase.java
new file mode 100644
index 00000000000..7b6c0423209
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessTestBase.java
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+import common.util.TestBase;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.validation.SchemaFactory;
+
+/**
+ * Test base for Access Rule test.
+ */
+public class AccessTestBase extends TestBase {
+ /*
+ * Test scenarios for verifying preferences.
+ *
+ * Fields:
+ * file, FSP, state of setting, config file, system property, api property,
+ * Custom Catalog, error expected, error code or expected result
+ */
+ public Object[][] getConfigs(Processor processor) {
+ // file with an external DTD that's not in JdkCatalog
+ String fileDTDNotInC = "properties1.xml";
+ // file with an external DTD that's in the Custom Catalog
+ String fileDTDInCC = "test.xml";
+ // file with an external DTD that's in JdkCatalog
+ String javaDTD = "properties.xml";
+
+ // error code when CATALOG=strict; The cause for DOM
+ String errCode = "JAXP09040001";
+
+ // error (not from catalog) is expect when CATALOG=continue
+ boolean isErrExpected = true;
+ String expected1 = UNKNOWN_HOST;
+
+ // expected when reference is resolved by Catalog
+ String expected2 = "";
+ switch (processor) {
+ case SAX:
+ errCode = "JAXP00090001";
+ break;
+ case STAX:
+ errCode = "JAXP00090001";
+ // StAX is non-validating parser
+ isErrExpected = false;
+ expected1 = ".*[\\w\\s]*(value1)[\\w\\s]*.*";
+ expected2 = ".*(123)[\\w\\s]*.*";
+ break;
+ default:
+ break;
+ }
+
+ return new Object[][]{
+ /**
+ * Case 1: all properties must permit
+ * Note: External reference not in the built-in catalog
+ * Expect: error as the parser continues and tries to access an invalid site
+ * java.net.UnknownHostException: invalid.site.com
+ */
+ /**
+ * Case 1-1: by default, both RESOURCE_ACCESS and EAP allow access
+ */
+ {fileDTDNotInC, null, null, null, null, null, null, isErrExpected, expected1},
+ /**
+ * Case 1-2: FSP is set, both RESOURCE_ACCESS and EAP are set to allow
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, isErrExpected, expected1},
+ /**
+ * Case 2: access is denied unless all properties permit the operation
+ *
+ * Sample Error Message: [Fatal Error] properties1.xml:7:11: External DTD: Failed to read external DTD 'properties1.dtd',
+ * because access is not allowed due to restriction set by 'Resource Access (jdk.xml.resource.access) and http://javax.xml.XMLConstants/property/accessExternalDTD'.
+ *
+ */
+ /**
+ * Case 2-1: FSP is set. RESOURCE_ACCESS is unchanged, and EAP denies access
+
+ * Expect: [Fatal Error] access denied by ACCESS_EXTERNAL_DTD
+ */
+ {fileDTDNotInC, Properties.FSP, null, null, null, null, null, true, XMLConstants.ACCESS_EXTERNAL_DTD},
+ /**
+ * Case 2-2: RESOURCE_ACCESS is set to deny access though EAP allows it
+
+ * Expect: [Fatal Error] access denied by RESOURCE_ACCESS
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS1, Properties.AED0}, null, true, SP_ACCESS},
+ /**
+ * Case 2-3: ACCESS_EXTERNAL_DTD is set to deny access though RESOURCE_ACCESS allows it
+
+ * Expect: [Fatal Error] access denied by ACCESS_EXTERNAL_DTD
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED2}, null, true, XMLConstants.ACCESS_EXTERNAL_DTD},
+ /**
+ * Case 2-4: System properties override FSP secure values.
+ *
+ * Expect: error as the parser continues and tries to access an invalid site
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.SYSTEM, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, null, isErrExpected, expected1},
+ /**
+ * Case 2-5: API property setting overrides system property setting.
+ *
+ * Expect: error as the parser continues and tries to access an invalid site
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS1, Properties.AED0}, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, isErrExpected, expected1},
+ /**
+ * Case 2-6: API property setting overrides system property setting.
+ *
+ * Expect: [Fatal Error] access denied by RESOURCE_ACCESS
+ */
+ {fileDTDNotInC, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, new Properties[]{Properties.ACCESS1, Properties.AED0}, null, true, SP_ACCESS},
+
+ /**
+ * Case 3: Resolvers and Catalogs take precedence in the resource resolution process
+ *
+ * Sample Error Message when access is denied by Catalog's Resolve property:
+ * [Fatal Error] properties1.xml:7:11: JAXP00090001: The CatalogResolver is enabled with the catalog "JDKCatalog.xml", but a CatalogException is returned.
+ * org.xml.sax.SAXException: javax.xml.catalog.CatalogException: JAXP09040001: No match found for publicId 'null' and systemId 'http://invalid.site.com/dtd/properties1.dtd'.
+ *
+ */
+ /**
+ * Case 3-1: the built-in catalog's Resolve property is set to "strict", both Resource Access (jdk.xml.resource.access) and External Access Properties (EAPs) have no effect,
+ * regardless of their configured values
+ *
+ * Expect: error as access is denied by the Catalog's Resolve property
+ */
+ {fileDTDNotInC, null, PropertyState.CONFIG_FILE_SYSTEM_API, Properties.CONFIG_FILE_CATALOG_STRICT, null, new Properties[]{Properties.ACCESS0, Properties.AED0}, null, true, errCode},
+ /**
+ * Case 3-2: the reference is resolved by the built-in catalog before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {javaDTD, Properties.FSP, PropertyState.CONFIG_FILE, Properties.CONFIG_FILE_CATALOG_STRICT, null, null, null, false, expected1},
+ /**
+ * Case 3-3: the reference is resolved by a custom catalog before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {fileDTDInCC, Properties.FSP, PropertyState.CONFIG_FILE, Properties.CONFIG_FILE_CATALOG_STRICT, null, null, CustomCatalog.STRICT, false, expected2}
+ };
+ }
+
+ /*
+ * Test scenarios for XInclude. XInclude direct fetches are controlled by
+ * RESOURCE_ACCESS, while resolver/catalog results take precedence.
+ */
+ public Object[][] getXIncludeConfigs(Processor processor) {
+ String xinclude = "XI_roottest.xml";
+
+ return new Object[][]{
+ /**
+ * Case 1-1: by default, RESOURCE_ACCESS allows direct XInclude access.
+ */
+ {xinclude, null, null, null, null, null, null, false, ""},
+ /**
+ * Case 1-2: FSP is set, RESOURCE_ACCESS is explicitly set to allow.
+ */
+ {xinclude, Properties.FSP, PropertyState.API, null, null,
+ new Properties[]{Properties.ACCESS0}, null, false, ""},
+ /**
+ * Case 2-1: RESOURCE_ACCESS is set to deny direct XInclude access.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xinclude, Properties.FSP, PropertyState.API, null, null,
+ new Properties[]{Properties.ACCESS1}, null, true, SP_ACCESS},
+ /**
+ * Case 2-2: system properties override FSP.
+ */
+ {xinclude, Properties.FSP, PropertyState.SYSTEM, null,
+ new Properties[]{Properties.ACCESS0}, null, null, false, ""},
+ /**
+ * Case 2-3: API property setting overrides system property setting.
+ */
+ {xinclude, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null,
+ new Properties[]{Properties.ACCESS1},
+ new Properties[]{Properties.ACCESS0}, null, false, ""},
+ /**
+ * Case 2-4: API property setting overrides system property setting.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xinclude, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null,
+ new Properties[]{Properties.ACCESS0},
+ new Properties[]{Properties.ACCESS1}, null, true, SP_ACCESS},
+ /**
+ * Case 3-1: custom catalog resolves the reference before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {xinclude, Properties.FSP, PropertyState.CONFIG_FILE,
+ Properties.CONFIG_FILE_CATALOG_STRICT, null, null,
+ CustomCatalog.STRICT, false, ""},
+ };
+ }
+
+ /*
+ * Test scenarios for configuring properties for validation or transform.
+ *
+ * Fields:
+ * xml file, xsd or xsl file, FSP, state of setting, config file, system property,
+ * api property, Custom Catalog, error expected, error code or expected result
+ */
+ public Object[][] getConfig(String m) {
+ // Schema Import
+ String xmlFile = "XSDImport_company.xsd";
+ String xsdOrXsl = null;
+ String expected = "";
+ String errCode = "JAXP00090001";
+ Properties eapAllow = Properties.AES0;
+ Properties eapDeny = Properties.AES2;
+ String eapName = "accessExternalDTD,accessExternalSchema";
+
+ switch (m) {
+ case "SchemaTest2":
+ // Schema Include
+ xmlFile = "XSDInclude_company.xsd";
+ break;
+ case "Validation":
+ // Schema Location
+ xmlFile = "val_test.xml";
+ break;
+ case "Stylesheet":
+ errCode = "JAXP09040001";
+ xmlFile = "XSLDTD.xsl";
+ eapAllow = Properties.AED0;
+ eapDeny = Properties.AED2;
+ eapName = XMLConstants.ACCESS_EXTERNAL_DTD;
+ break;
+ case "Transform":
+ xmlFile = "XSLPI.xml";
+ errCode = "JAXP00090001";
+ xsdOrXsl = ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + " ";
+ eapAllow = Properties.AEX0;
+ eapDeny = Properties.AEX2;
+ eapName = XMLConstants.ACCESS_EXTERNAL_STYLESHEET;
+ break;
+ default:
+ break;
+ }
+
+ return new Object[][]{
+ /**
+ * Case 1: all properties must permit.
+ *
+ * Case 1-1: by default, both RESOURCE_ACCESS and EAP allow access.
+ */
+ {xmlFile, xsdOrXsl, null, null, null, null, null, null, false, expected},
+ /**
+ * Case 1-2: FSP is set, both RESOURCE_ACCESS and EAP are set to allow.
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, false, expected},
+ /**
+ * Case 2: access is denied unless all properties permit the operation.
+ *
+ * Case 2-1: FSP is set. RESOURCE_ACCESS is unchanged, and EAP denies access.
+ *
+ * Expect: access denied by EAP
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE, null, null, null, null, true, eapName},
+ /**
+ * Case 2-2: RESOURCE_ACCESS is set to deny access though EAP allows it.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS1, Properties.AED0, eapAllow}, null, true, SP_ACCESS},
+ /**
+ * Case 2-3: EAP is set to deny access though RESOURCE_ACCESS allows it.
+ *
+ * Expect: access denied by EAP
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.API, null, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapDeny}, null, true, eapName},
+ /**
+ * Case 2-4: system properties override FSP secure values.
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.SYSTEM, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, null, false, expected},
+ /**
+ * Case 2-5: API property setting overrides system property setting.
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS1, Properties.AED0, eapAllow}, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, false, expected},
+ /**
+ * Case 2-6: API property setting overrides system property setting.
+ *
+ * Expect: access denied by RESOURCE_ACCESS
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE_SYSTEM_API, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, new Properties[]{Properties.ACCESS1, Properties.AED0, eapAllow}, null, true, SP_ACCESS},
+ /**
+ * Case 3: Catalogs take precedence in the resource resolution process.
+ *
+ * Case 3-1: the built-in catalog's Resolve property is set to "strict",
+ * and the reference is not in the built-in catalog.
+ *
+ * Expect: error as access is denied by the Catalog's Resolve property
+ */
+ {xmlFile, xsdOrXsl, null, PropertyState.CONFIG_FILE_SYSTEM_API, Properties.CONFIG_FILE_CATALOG_STRICT, null, new Properties[]{Properties.ACCESS0, Properties.AED0, eapAllow}, null, true, errCode},
+ /**
+ * Case 3-2: custom catalog resolves the reference before direct fetch.
+ * FSP sets EAP to deny direct fetch, but catalog resolution completes first.
+ *
+ * Expect: no error
+ */
+ {xmlFile, xsdOrXsl, Properties.FSP, PropertyState.CONFIG_FILE, Properties.CONFIG_FILE_CATALOG_STRICT, null, null, CustomCatalog.STRICT, false, expected},
+ };
+ }
+
+ public void testDOM(String filename, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ DocumentBuilderFactory dbf = getDBF(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, dbf, expectError, error);
+ }
+
+ public void testSAX(String filename, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ SAXParser parser = getSAXParser(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, parser, expectError, error);
+ }
+
+ public void testStAX(String filename, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ XMLInputFactory xif = getXMLInputFactory(state, config, sysProp, apiProp, cc);
+ process(filename, xif, expectError, error);
+ }
+
+ public void testSchema1(String filename, String xsd, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ SchemaFactory sf = getSchemaFactory(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, sf, expectError, error);
+ }
+
+ public void testSchema2(String filename, String xsd, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+ testSchema1(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ }
+
+ public void testValidation(String filename, String xsd, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ SchemaFactory sf = getSchemaFactory(fsp, state, config, sysProp, apiProp, cc);
+ validate(filename, sf, expectError, error);
+ }
+
+ public void testStylesheet(String filename, String xsl, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ TransformerFactory tf = getTransformerFactory(fsp, state, config, sysProp, apiProp, cc);
+ process(filename, tf, expectError, error);
+ }
+
+ public void testTransform(String filename, String xsl, Properties fsp, PropertyState state,
+ Properties config, Properties[] sysProp, Properties[] apiProp, CustomCatalog cc,
+ boolean expectError, String error) throws Exception {
+
+ TransformerFactory tf = getTransformerFactory(fsp, state, config, sysProp, apiProp, cc);
+ transform(filename, xsl, tf, expectError, error);
+ }
+
+ // parameters in the same order as the test method
+ String filename; String xsd; String xsl; Properties fsp; PropertyState state;
+ Properties config; Properties[] sysProp; Properties[] apiProp; CustomCatalog cc;
+ boolean expectError; String error;
+
+ // Maps the scenario array to individual parameters
+ public void paramMap(Processor processor, String method, String index) {
+ int i = 0;
+ Object[][] params;
+ if (processor == Processor.VALIDATOR ||
+ processor == Processor.TRANSFORMER) {
+ params = getConfig(method);
+ i = 1;
+ } else {
+ params = getConfigs(processor);
+ }
+ Object[] param = params[Integer.parseInt(index)];
+ filename = (String)param[0];
+ if (processor == Processor.VALIDATOR) {
+ xsd = (String)param[i];
+ } else if (processor == Processor.TRANSFORMER) {
+ xsl = (String)param[i];
+ }
+ fsp = (Properties)param[i + 1];
+ state = (PropertyState)param[i + 2];
+ config = (Properties)param[i + 3];
+ sysProp = (Properties[])param[i + 4];
+ apiProp = (Properties[])param[i + 5];
+ cc = (CustomCatalog)param[i + 6];
+ expectError = (boolean)param[i + 7];
+ error = (String)param[i + 8];
+ }
+
+ public void paramMapXInclude(Processor processor, String index) {
+ Object[] param = getXIncludeConfigs(processor)[Integer.parseInt(index)];
+ filename = (String)param[0];
+ fsp = (Properties)param[1];
+ state = (PropertyState)param[2];
+ config = (Properties)param[3];
+ sysProp = (Properties[])param[4];
+ apiProp = (Properties[])param[5];
+ cc = (CustomCatalog)param[6];
+ expectError = (boolean)param[7];
+ error = (String)param[8];
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/DOMTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/DOMTest.java
new file mode 100644
index 00000000000..e0223f93459
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/DOMTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8357394
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.DOMTest 0 // by default, both RESOURCE_ACCESS and EAP allow access
+ * @run driver common.access.DOMTest 1 // FSP is set, both RESOURCE_ACCESS and EAP are set to allow
+ * @run driver common.access.DOMTest 2 // FSP is set, RESOURCE_ACCESS is unchanged, EAP denies access
+ * @run driver common.access.DOMTest 3 // RESOURCE_ACCESS denies access though EAP allows it
+ * @run driver common.access.DOMTest 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.DOMTest 5 // system properties override FSP secure values
+ * @run driver common.access.DOMTest 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.DOMTest 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.DOMTest 8 // the built-in catalog's Resolve property is strict
+ * @run driver common.access.DOMTest 9 // the built-in catalog resolves the reference before direct fetch
+ * @run driver common.access.DOMTest 10 // the custom catalog resolves the reference before direct fetch
+ * @summary Tests the interaction between Resource Access (jdk.xml.resource.access),
+ * External Access Properties (EAPs), and the built-in catalog's Resolve setting,
+ * ensuring correct precedence and behavior across different combinations of these
+ * configuration mechanisms
+ */
+public class DOMTest extends AccessTestBase {
+ public static void main(String[] args) throws Exception {
+ final ProxySelector previous = ProxySelector.getDefault();
+ // disable proxy
+ ProxySelector.setDefault(ProxySelector.of(null));
+ try {
+ new DOMTest().run(args[0]);
+ } finally {
+ // reset to the previous proxy selector
+ ProxySelector.setDefault(previous);
+ }
+ }
+
+ public void run(String index) throws Exception {
+ paramMap(Processor.DOM, null, index);
+ super.testDOM(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/SAXTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/SAXTest.java
new file mode 100644
index 00000000000..d17852b895b
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/SAXTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+import common.util.TestBase;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8357394
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.SAXTest 0 // by default, both RESOURCE_ACCESS and EAP allow access
+ * @run driver common.access.SAXTest 1 // FSP is set, both RESOURCE_ACCESS and EAP are set to allow
+ * @run driver common.access.SAXTest 2 // FSP is set, RESOURCE_ACCESS is unchanged, EAP denies access
+ * @run driver common.access.SAXTest 3 // RESOURCE_ACCESS denies access though EAP allows it
+ * @run driver common.access.SAXTest 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SAXTest 5 // system properties override FSP secure values
+ * @run driver common.access.SAXTest 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SAXTest 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SAXTest 8 // the built-in catalog's Resolve property is strict
+ * @run driver common.access.SAXTest 9 // the built-in catalog resolves the reference before direct fetch
+ * @run driver common.access.SAXTest 10 // the custom catalog resolves the reference before direct fetch
+ * @summary Tests the interaction between Resource Access (jdk.xml.resource.access),
+ * External Access Properties (EAPs), and the built-in catalog's Resolve setting,
+ * ensuring correct precedence and behavior across different combinations of these
+ * configuration mechanisms
+ */
+public class SAXTest extends AccessTestBase {
+ public static void main(String[] args) throws Exception {
+ final ProxySelector previous = ProxySelector.getDefault();
+ // disable proxy
+ ProxySelector.setDefault(ProxySelector.of(null));
+ try {
+ new SAXTest().run(args[0]);
+ } finally {
+ // reset to the previous proxy selector
+ ProxySelector.setDefault(previous);
+ }
+ }
+
+ public void run(String index) throws Exception {
+ paramMap(TestBase.Processor.SAX, null, index);
+ super.testSAX(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/SchemaTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/SchemaTest.java
new file mode 100644
index 00000000000..e984bc16639
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/SchemaTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8306632
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.SchemaTest SchemaTest1 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow access
+ * @run driver common.access.SchemaTest SchemaTest1 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow
+ * @run driver common.access.SchemaTest SchemaTest1 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_SCHEMA denies
+ * @run driver common.access.SchemaTest SchemaTest1 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_SCHEMA allows it
+ * @run driver common.access.SchemaTest SchemaTest1 4 // ACCESS_EXTERNAL_SCHEMA denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SchemaTest SchemaTest1 5 // system properties override FSP secure values
+ * @run driver common.access.SchemaTest SchemaTest1 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SchemaTest SchemaTest1 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SchemaTest SchemaTest1 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.SchemaTest SchemaTest1 9 // custom catalog resolves before direct fetch
+ * @run driver common.access.SchemaTest SchemaTest2 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow access
+ * @run driver common.access.SchemaTest SchemaTest2 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow
+ * @run driver common.access.SchemaTest SchemaTest2 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_SCHEMA denies
+ * @run driver common.access.SchemaTest SchemaTest2 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_SCHEMA allows it
+ * @run driver common.access.SchemaTest SchemaTest2 4 // ACCESS_EXTERNAL_SCHEMA denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SchemaTest SchemaTest2 5 // system properties override FSP secure values
+ * @run driver common.access.SchemaTest SchemaTest2 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SchemaTest SchemaTest2 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SchemaTest SchemaTest2 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.SchemaTest SchemaTest2 9 // custom catalog resolves before direct fetch
+ * @run driver common.access.SchemaTest Validation 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow access
+ * @run driver common.access.SchemaTest Validation 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_SCHEMA allow
+ * @run driver common.access.SchemaTest Validation 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_SCHEMA denies
+ * @run driver common.access.SchemaTest Validation 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_SCHEMA allows it
+ * @run driver common.access.SchemaTest Validation 4 // ACCESS_EXTERNAL_SCHEMA denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.SchemaTest Validation 5 // system properties override FSP secure values
+ * @run driver common.access.SchemaTest Validation 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.SchemaTest Validation 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.SchemaTest Validation 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.SchemaTest Validation 9 // custom catalog resolves before direct fetch
+ * @summary verifies Schema and Validation support for Resource Access, ACCESS_EXTERNAL_SCHEMA, and catalog precedence.
+ */
+public class SchemaTest extends AccessTestBase {
+
+ public static void main(String args[]) throws Exception {
+ new SchemaTest().run(args[0], args[1]);
+ }
+
+ public void run(String method, String index) throws Exception {
+ paramMap(Processor.VALIDATOR, method, index);
+ switch (method) {
+ case "SchemaTest1":
+ super.testSchema1(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case "SchemaTest2":
+ super.testSchema2(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case "Validation":
+ super.testValidation(filename, xsd, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ }
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/StAXTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/StAXTest.java
new file mode 100644
index 00000000000..65b73ee03ed
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/StAXTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+
+import common.util.TestBase;
+
+import java.net.ProxySelector;
+
+/**
+ * @test @bug 8357394
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.StAXTest 0 // by default, both RESOURCE_ACCESS and EAP allow access
+ * @run driver common.access.StAXTest 3 // RESOURCE_ACCESS denies access though EAP allows it
+ * @run driver common.access.StAXTest 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.StAXTest 5 // system properties override FSP secure values
+ * @run driver common.access.StAXTest 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.StAXTest 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.StAXTest 8 // the built-in catalog's Resolve property is strict
+ * @run driver common.access.StAXTest 9 // the built-in catalog resolves the reference before direct fetch
+ * @run driver common.access.StAXTest 10 // the custom catalog resolves the reference before direct fetch
+ * @summary Tests the interaction between Resource Access (jdk.xml.resource.access),
+ * External Access Properties (EAPs), and the built-in catalog's Resolve setting,
+ * ensuring correct precedence and behavior across different combinations of these
+ * configuration mechanisms
+ */
+public class StAXTest extends AccessTestBase {
+ public static void main(String[] args) throws Exception {
+ new StAXTest().run(args[0]);
+ }
+
+ public void run(String index) throws Exception {
+ paramMap(TestBase.Processor.STAX, null, index);
+ super.testStAX(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/TransformTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/TransformTest.java
new file mode 100644
index 00000000000..38a5ec18b72
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/TransformTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+/**
+ * @test @bug 8306632
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.TransformTest Stylesheet 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_DTD allow access
+ * @run driver common.access.TransformTest Stylesheet 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_DTD allow
+ * @run driver common.access.TransformTest Stylesheet 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_DTD denies
+ * @run driver common.access.TransformTest Stylesheet 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_DTD allows it
+ * @run driver common.access.TransformTest Stylesheet 4 // ACCESS_EXTERNAL_DTD denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.TransformTest Stylesheet 5 // system properties override FSP secure values
+ * @run driver common.access.TransformTest Stylesheet 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.TransformTest Stylesheet 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.TransformTest Stylesheet 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.TransformTest Stylesheet 9 // custom catalog resolves before direct fetch
+ * @run driver common.access.TransformTest Transform 0 // default RESOURCE_ACCESS and ACCESS_EXTERNAL_STYLESHEET allow access
+ * @run driver common.access.TransformTest Transform 1 // FSP with explicit RESOURCE_ACCESS and ACCESS_EXTERNAL_STYLESHEET allow
+ * @run driver common.access.TransformTest Transform 2 // FSP leaves RESOURCE_ACCESS unchanged, ACCESS_EXTERNAL_STYLESHEET denies
+ * @run driver common.access.TransformTest Transform 3 // RESOURCE_ACCESS denies access though ACCESS_EXTERNAL_STYLESHEET allows it
+ * @run driver common.access.TransformTest Transform 4 // ACCESS_EXTERNAL_STYLESHEET denies access though RESOURCE_ACCESS allows it
+ * @run driver common.access.TransformTest Transform 5 // system properties override FSP secure values
+ * @run driver common.access.TransformTest Transform 6 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.TransformTest Transform 7 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.TransformTest Transform 8 // built-in catalog resolve=strict denies unresolved reference
+ * @run driver common.access.TransformTest Transform 9 // custom catalog resolves before direct fetch
+ * @summary verifies Transform support for Resource Access, external access properties, and catalog precedence.
+ */
+public class TransformTest extends AccessTestBase {
+
+ public static void main(String args[]) throws Exception {
+ new TransformTest().run(args[0], args[1]);
+ }
+
+ public void run(String method, String index) throws Exception {
+ paramMap(Processor.TRANSFORMER, method, index);
+ switch (method) {
+ case "Stylesheet":
+ super.testStylesheet(filename, xsl, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case "Transform":
+ super.testTransform(filename, xsl, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ }
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/XIncludeTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/XIncludeTest.java
new file mode 100644
index 00000000000..47b5aa6e85a
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/XIncludeTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2026, 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.access;
+
+/**
+ * @test @bug 8306632
+ * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
+ * @modules java.xml/jdk.xml.internal
+ * @run driver common.access.XIncludeTest DOM 0 // default RESOURCE_ACCESS allows direct XInclude access
+ * @run driver common.access.XIncludeTest DOM 1 // FSP with explicit RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest DOM 2 // RESOURCE_ACCESS denies direct XInclude access
+ * @run driver common.access.XIncludeTest DOM 3 // system properties override FSP
+ * @run driver common.access.XIncludeTest DOM 4 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.XIncludeTest DOM 5 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest DOM 6 // custom catalog resolves before direct fetch
+ * @run driver common.access.XIncludeTest SAX 0 // default RESOURCE_ACCESS allows direct XInclude access
+ * @run driver common.access.XIncludeTest SAX 1 // FSP with explicit RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest SAX 2 // RESOURCE_ACCESS denies direct XInclude access
+ * @run driver common.access.XIncludeTest SAX 3 // system properties override FSP
+ * @run driver common.access.XIncludeTest SAX 4 // API RESOURCE_ACCESS allow overrides system RESOURCE_ACCESS deny
+ * @run driver common.access.XIncludeTest SAX 5 // API RESOURCE_ACCESS deny overrides system RESOURCE_ACCESS allow
+ * @run driver common.access.XIncludeTest SAX 6 // custom catalog resolves before direct fetch
+ * @summary verifies XInclude support for Resource Access and catalog precedence.
+ */
+public class XIncludeTest extends AccessTestBase {
+
+ public static void main(String args[]) throws Exception {
+ new XIncludeTest().run(args[0], args[1]);
+ }
+
+ public void run(String processor, String index) throws Exception {
+ Processor p = Processor.valueOf(processor);
+ paramMapXInclude(p, index);
+ switch (p) {
+ case DOM:
+ super.testDOM(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ case SAX:
+ super.testSAX(filename, fsp, state, config, sysProp, apiProp, cc, expectError, error);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported processor: " + processor);
+ }
+ }
+}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml
index 216b3b81543..f1912ed877a 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/testcatalog/TestCatalog.xml
@@ -18,6 +18,9 @@
+
+
+
@@ -26,7 +29,7 @@
-
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java
index b37b7da4e9a..81ac14ce9e9 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDTestBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package common.dtd;
@@ -12,7 +12,7 @@ import javax.xml.validation.SchemaFactory;
import common.util.TestBase;
/**
- * @bug 8306632
+ * @bug 8306632 8357394
* @summary tests the DTD property jdk.xml.dtd.support.
* The DTD property controls how DTDs are processed.
*/
@@ -126,7 +126,7 @@ public class DTDTestBase extends TestBase {
* Expect: error as the parser processes DTD and tries to access the invalid site
* Error: JAXP00010008 java.net.UnknownHostException: invalid.site.com
*/
- {fileDTDNotInC, null, null, null, null, null, isErrExpected, expected},
+ {fileDTDNotInC, null, null, null, null, null, isErrExpected, expected1},
/**
* Case 1-2: DTD=deny in config file
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java b/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java
index 77672609147..9e0a629a217 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, 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
@@ -29,7 +29,6 @@ import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Objects;
-import java.util.regex.Pattern;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.parsers.DocumentBuilder;
@@ -44,6 +43,7 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
@@ -53,8 +53,8 @@ import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
-import org.w3c.dom.Document;
import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
@@ -90,8 +90,8 @@ public class TestBase {
private static final String CONFIG_FILE = "java.xml.config.file";
// CATALOG Abbreviation: C
- static final String C_FILE = CatalogFeatures.Feature.FILES.getPropertyName();
- static final String C_RESOLVE = CatalogFeatures.Feature.RESOLVE.getPropertyName();
+ public static final String C_FILE = CatalogFeatures.Feature.FILES.getPropertyName();
+ public static final String C_RESOLVE = CatalogFeatures.Feature.RESOLVE.getPropertyName();
// Xerces Property
public static final String DISALLOW_DTD = "http://apache.org/xml/features/disallow-doctype-decl";
@@ -106,15 +106,31 @@ public class TestBase {
public static final String SP_CATALOG = "jdk.xml.jdkcatalog.resolve";
public static final String OVERRIDE_PARSER = "jdk.xml.overrideDefaultParser";
+ //System Properties corresponding to ACCESS_EXTERNAL_* properties
+ public static final String SP_ACCESS_EXTERNAL_STYLESHEET = "javax.xml.accessExternalStylesheet";
+ public static final String SP_ACCESS_EXTERNAL_DTD = "javax.xml.accessExternalDTD";
+ public static final String SP_ACCESS_EXTERNAL_SCHEMA = "javax.xml.accessExternalSchema";
+ //Values for the ACCESS_EXTERNAL_* properties
+ public static final String ACCESS_EXTERNAL_ALL = "all";
+ public static final String ACCESS_EXTERNAL_NONE = "";
+
+ // JDK 27
+ public static final String SP_ACCESS = "jdk.xml.resource.access";
+
// DTD/CATALOG constants
public static final String RESOLVE_CONTINUE = "continue";
public static final String RESOLVE_IGNORE = "ignore";
public static final String RESOLVE_STRICT = "strict";
+ public static final String RESOLVE_STRICT_NONLOCAL = "strict:non-local";
public static final String DTD_ALLOW = "allow";
public static final String DTD_IGNORE = "ignore";
public static final String DTD_DENY = "deny";
+ // resource access constants
+ public static final String ACCESS_ALLOW = "*";
+ public static final String ACCESS_DENY = "";
+
// JAXP Configuration File(JCF) location
// DTD = deny
public static final String JCF_DTD2 = "dtd2.properties";
@@ -126,6 +142,8 @@ public class TestBase {
public static final String CONFIG_DEFAULT = "jaxp.properties";
public static final String CONFIG_STRICT = "jaxp-strict.properties";
public static final String CONFIG_TEMPLATE_STRICT = "jaxp-strict.properties.template";
+ public static final String CONFIG_COMPAT = "jaxp-compat.properties";
+ public static final String CONFIG_TEMPLATE_COMPAT = "jaxp-compat.properties.template";
public static final String UNKNOWN_HOST = "invalid.site.com";
@@ -150,6 +168,16 @@ public class TestBase {
CATALOG0(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_CONTINUE),
CATALOG1(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_IGNORE),
CATALOG2(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_STRICT),
+ CATALOG_NONLOCAL(SP_CATALOG, "ditto", Type.PROPERTY, RESOLVE_STRICT_NONLOCAL),
+ AED0(XMLConstants.ACCESS_EXTERNAL_DTD, SP_ACCESS_EXTERNAL_DTD, Type.PROPERTY, ACCESS_EXTERNAL_ALL),
+ AED2(XMLConstants.ACCESS_EXTERNAL_DTD, SP_ACCESS_EXTERNAL_DTD, Type.PROPERTY, ACCESS_EXTERNAL_NONE),
+ AES0(XMLConstants.ACCESS_EXTERNAL_SCHEMA, SP_ACCESS_EXTERNAL_SCHEMA, Type.PROPERTY, ACCESS_EXTERNAL_ALL),
+ AES2(XMLConstants.ACCESS_EXTERNAL_SCHEMA, SP_ACCESS_EXTERNAL_SCHEMA, Type.PROPERTY, ACCESS_EXTERNAL_NONE),
+ AEX0(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, SP_ACCESS_EXTERNAL_STYLESHEET, Type.PROPERTY, ACCESS_EXTERNAL_ALL),
+ AEX2(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, SP_ACCESS_EXTERNAL_STYLESHEET, Type.PROPERTY, ACCESS_EXTERNAL_NONE),
+
+ ACCESS0(SP_ACCESS, "ditto", Type.PROPERTY, ACCESS_ALLOW),
+ ACCESS1(SP_ACCESS, "ditto", Type.PROPERTY, ACCESS_DENY),
// StAX properties
SUPPORT_DTD(XMLInputFactory.SUPPORT_DTD, null, Type.FEATURE, "true"),
@@ -243,10 +271,21 @@ public class TestBase {
String error) throws Exception {
//dbf.setAttribute(CatalogFeatures.Feature.RESOLVE.getPropertyName(), "continue");
DocumentBuilder builder = dbf.newDocumentBuilder();
+ builder.setEntityResolver((String publicId, String systemId) -> {
+ InputSource dtd = null;
+ InputStream is = null;
+ if ("http://foo.bar/dtd/test.dtd".equals(systemId)) {
+ is = getClass().getResourceAsStream("/local/store/path/test.dtd");
+ }
+ if (is != null) {
+ dtd = new InputSource(is);
+ }
+ return dtd;
+ });
File file = new File(getPath(TEST_SOURCE_DIR, filename));
try {
- Document document = builder.parse(file);
- Assert.assertTrue(!expectError);
+ builder.parse(file);
+ processResult(expectError, error);
} catch (Exception e) {
e.printStackTrace();
processError(expectError, error, e);
@@ -259,7 +298,7 @@ public class TestBase {
File file = new File(getPath(TEST_SOURCE_DIR, filename));
try {
parser.parse(file, new DefaultHandler());
- Assert.assertTrue(!expectError);
+ processResult(expectError, error);
} catch (Exception e) {
//e.printStackTrace();
processError(expectError, error, e);
@@ -275,8 +314,7 @@ public class TestBase {
XMLStreamReader streamReader = xif.createXMLStreamReader(xml, entityxml);
String text = getText(streamReader, XMLStreamConstants.CHARACTERS);
System.out.println("Text: [" + text.trim() + "]");
- Assert.assertTrue(Pattern.matches(expected, text.trim()));
- Assert.assertTrue(!expectError);
+ processResult(expectError, expected);
} catch (Exception e) {
e.printStackTrace();
processError(expectError, expected, e);
@@ -289,8 +327,8 @@ public class TestBase {
String xsd = getPath(TEST_SOURCE_DIR, filename);
try {
Schema schema = sf.newSchema(new StreamSource(new File(xsd)));
- Assert.assertTrue(!expectError);
- } catch (Exception e) {
+ processResult(expectError, expected);
+ } catch (SAXException e) {
e.printStackTrace();
processError(expectError, expected, e);
}
@@ -303,8 +341,8 @@ public class TestBase {
SAXSource xslSource = new SAXSource(new InputSource(xsl));
xslSource.setSystemId(xsl);
Transformer transformer = tf.newTransformer(xslSource);
- Assert.assertTrue(!expectError);
- } catch (Exception e) {
+ processResult(expectError, expected);
+ } catch (TransformerConfigurationException e) {
//e.printStackTrace();
processError(expectError, expected, e);
}
@@ -320,7 +358,7 @@ public class TestBase {
Transformer transformer = tf.newTransformer(xslSource);
StringWriter sw = new StringWriter();
transformer.transform(getSource(SourceType.STREAM, xmlSysId), new StreamResult(sw));
- Assert.assertTrue(!expectError);
+ processResult(expectError, expected);
} catch (Exception e) {
processError(expectError, expected, e);
}
@@ -333,16 +371,23 @@ public class TestBase {
Schema schema = sf.newSchema();
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File(xml)));
- Assert.assertTrue(!expectError);
+ processResult(expectError, expected);
} catch (Exception e) {
e.printStackTrace();
processError(expectError, expected, e);
}
}
+ protected void processResult(boolean expectError, String expected) {
+ if (expectError) {
+ Assert.assertTrue(false, "Expected error, but processing succeeded.");
+ }
+ }
+
protected void processError(boolean expectError, String error, Exception e)
throws Exception {
String str = e.getMessage();
+ String errorText = getErrorText(e);
if (!expectError) {
Assert.assertTrue(false, "Expected pass, but Exception is thrown " + str);
} else {
@@ -351,11 +396,33 @@ public class TestBase {
if (UNKNOWN_HOST.equals(error)) {
Assert.assertTrue((str != null) && str.equals(error));
} else {
- Assert.assertTrue((str != null) && str.contains(error));
+ String matched = null;
+ for (String err : error.split(",")) {
+ String trimmed = err.trim();
+ if (!trimmed.isEmpty() && errorText.contains(trimmed)) {
+ matched = trimmed;
+ break;
+ }
+ }
+ if (matched == null) {
+ Assert.assertTrue(false,"Missing expected error code(s): " + error);
+ }
+ Assert.assertTrue(true, "Found expected error code: " + matched);
}
}
}
+ private String getErrorText(Throwable t) {
+ StringBuilder sb = new StringBuilder();
+ while (t != null) {
+ if (t.getMessage() != null) {
+ sb.append(t.getMessage()).append('\n');
+ }
+ t = t.getCause();
+ }
+ return sb.toString();
+ }
+
/**
* Returns a DocumentBuilderFactory with settings as specified.
*
@@ -667,11 +734,15 @@ public class TestBase {
System.setProperty(property.spName, property.value);
break;
case CONFIG_FILE:
- System.setProperty(CONFIG_FILE, config.value);
+ if (config != null) {
+ System.setProperty(CONFIG_FILE, config.value);
+ }
break;
case CONFIG_FILE_SYSTEM:
case CONFIG_FILE_SYSTEM_API:
- System.setProperty(CONFIG_FILE, config.value);
+ if (config != null) {
+ System.setProperty(CONFIG_FILE, config.value);
+ }
if (property != null) {
System.setProperty(property.spName, property.value);
}
@@ -714,7 +785,7 @@ public class TestBase {
}
}
- static String getPath(String base, String file) {
+ public static String getPath(String base, String file) {
String temp = base + file;
if (IS_WINDOWS) {
temp = "/" + temp;
@@ -734,6 +805,8 @@ public class TestBase {
} else {
throw new RuntimeException("Expected true but was false. ");
}
+ } else if (message != null && !message.isEmpty()) {
+ System.out.println("Passed: " + message);
}
}
diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/xmlfiles/XI_simple.xml b/test/jaxp/javax/xml/jaxp/unittest/common/xmlfiles/XI_simple.xml
new file mode 100644
index 00000000000..98155ece7bb
--- /dev/null
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/xmlfiles/XI_simple.xml
@@ -0,0 +1,2 @@
+
+123