[566183] Restrict which external entities are automatically allowed,
since some are required for proper XHTML functionality in
JSPs.
diff --git a/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/contentmodels/TestFixedCMDocuments.java b/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/contentmodels/TestFixedCMDocuments.java
index 6040131..997d4d9 100644
--- a/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/contentmodels/TestFixedCMDocuments.java
+++ b/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/contentmodels/TestFixedCMDocuments.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2020 IBM Corporation and others.
+ * Copyright (c) 2007, 2021 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -12,16 +12,27 @@
*******************************************************************************/
package org.eclipse.jst.jsp.core.tests.contentmodels;
+import java.io.IOException;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
import org.eclipse.jst.jsp.core.internal.contentmodel.JSPCMDocumentFactory;
+import org.eclipse.jst.jsp.core.tests.ProjectUtil;
import org.eclipse.wst.html.core.internal.contentmodel.JSP11Namespace;
import org.eclipse.wst.html.core.internal.contentmodel.JSP20Namespace;
import org.eclipse.wst.html.core.internal.contentmodel.JSP21Namespace;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.xml.core.internal.contentmodel.CMAttributeDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNode;
+import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil;
import org.eclipse.wst.xml.core.internal.provisional.contentmodel.CMDocType;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+import org.w3c.dom.Element;
import junit.framework.TestCase;
@@ -272,6 +283,22 @@
checkDocument(CMDocType.TAG20_DOC_TYPE);
}
+ public void testXmlJsp() throws IOException, CoreException {
+ ProjectUtil.createProject("testxmljsp", null, null);
+ ProjectUtil.copyBundleEntriesIntoWorkspace("testfiles/testxmljsp", "testxmljsp");
+ IStructuredModel model = null;
+ try {
+ model = StructuredModelManager.getModelManager().getModelForRead(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("testxmljsp/test.jsp")));
+ Element body = (Element) ((IDOMModel) model).getDocument().getElementsByTagName("body").item(0);
+ assertNotNull("XHTML Transitional DTD did not load for JSP document (check if trusted according to DTDCorePlugin)", ModelQueryUtil.getModelQuery(model).getCMElementDeclaration(body));
+ }
+ finally {
+ if (model != null) {
+ model.releaseFromRead();
+ }
+ }
+ }
+
private void verifyAttributeDeclaration(CMElementDeclaration elemDecl, CMNode attr) {
assertTrue(attr.getNodeType() == CMNode.ATTRIBUTE_DECLARATION);
assertNotNull("no name on an attribute declaration", attr.getNodeName());
diff --git a/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testxmljsp/test.jsp b/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testxmljsp/test.jsp
new file mode 100644
index 0000000..450a139
--- /dev/null
+++ b/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testxmljsp/test.jsp
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Test</title>
+</head>
+<body>
+Before Tag
+
+After Tag
+</body>
+</html>
diff --git a/xml/bundles/org.eclipse.wst.dtd.core/contentmodel/org/eclipse/wst/dtd/core/internal/contentmodel/DTDImpl.java b/xml/bundles/org.eclipse.wst.dtd.core/contentmodel/org/eclipse/wst/dtd/core/internal/contentmodel/DTDImpl.java
index eca56ac..c9463d9 100644
--- a/xml/bundles/org.eclipse.wst.dtd.core/contentmodel/org/eclipse/wst/dtd/core/internal/contentmodel/DTDImpl.java
+++ b/xml/bundles/org.eclipse.wst.dtd.core/contentmodel/org/eclipse/wst/dtd/core/internal/contentmodel/DTDImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2001, 2011 IBM Corporation and others.
+ * Copyright (c) 2001, 2021 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -18,12 +18,13 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import com.ibm.icu.util.StringTokenizer;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.wst.dtd.core.internal.DTDCorePlugin;
import org.eclipse.wst.dtd.core.internal.emf.DTDAnyContent;
import org.eclipse.wst.dtd.core.internal.emf.DTDAttribute;
import org.eclipse.wst.dtd.core.internal.emf.DTDBasicType;
@@ -66,6 +67,7 @@
import org.eclipse.wst.xml.core.internal.contentmodel.basic.CMNodeListImpl;
import org.eclipse.wst.xml.core.internal.contentmodel.util.CMDescriptionBuilder;
+import com.ibm.icu.util.StringTokenizer;
public class DTDImpl {
static {
@@ -87,6 +89,7 @@
public static DTDFile buildDTDModel(String uri) {
DTDUtil dtdUtil = new DTDUtil();
dtdUtil.setexpandEntityReferences(true);
+ dtdUtil.setIsTrustedBase(isKnownURI(uri));
dtdUtil.parse(new ResourceSetImpl(), uri);
return dtdUtil.getDTDFile();
}
@@ -111,6 +114,54 @@
return isMulti ? -1 : 1;
}
+ /**
+ * A URI is considered known if one of its fragments begins with the name
+ * of a known contributor and the uri ends with one of its contributed URI
+ * values. The fuzzy matching is needed to account for runtime differences
+ * during development and production.
+ *
+ * @param dtdURI
+ * @return
+ */
+ static boolean isKnownURI(String dtdURI) {
+ /* nothing in the current workspace should be trusted */
+ if (dtdURI.contains(ResourcesPlugin.getWorkspace().getRoot().getLocation().toString())) {
+ return false;
+ }
+
+ String[] parts = dtdURI.split("/");
+ if (parts.length < 5) {
+ return false;
+ }
+ /* nothing remote should be trusted */
+ if (!parts[0].endsWith("file:")) {
+ return false;
+ }
+
+ String[] activeContributors = DTDCorePlugin.KNOWN_URIS.keySet().toArray(new String[0]);
+ /*
+ * The last part at least must be the file name, and the first part
+ * part of the installation location, so skip them
+ */
+ for (int i = parts.length - 2; i > 0; i--) {
+ String part = parts[i];
+ for (int j = 0; j < activeContributors.length; j++) {
+ if (part.startsWith(activeContributors[j])) {
+ part = activeContributors[j];
+ String[] contributedUris = null;
+ if ((contributedUris = DTDCorePlugin.KNOWN_URIS.get(part)) != null) {
+ for (int k = 0; k < contributedUris.length; k++) {
+ if (dtdURI.endsWith(contributedUris[k])) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
public static class DTDAdapterFactoryImpl extends AdapterFactoryImpl {
public Adapter createAdapter(Notifier target) {
Adapter result = null;
diff --git a/xml/bundles/org.eclipse.wst.dtd.core/emfmodel/org/eclipse/wst/dtd/core/internal/emf/util/DTDUtil.java b/xml/bundles/org.eclipse.wst.dtd.core/emfmodel/org/eclipse/wst/dtd/core/internal/emf/util/DTDUtil.java
index 88490dd..c162dbd 100644
--- a/xml/bundles/org.eclipse.wst.dtd.core/emfmodel/org/eclipse/wst/dtd/core/internal/emf/util/DTDUtil.java
+++ b/xml/bundles/org.eclipse.wst.dtd.core/emfmodel/org/eclipse/wst/dtd/core/internal/emf/util/DTDUtil.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2001, 2005 IBM Corporation and others.
+ * Copyright (c) 2001, 2021 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -64,6 +64,7 @@
private DTDParser parser;
private Vector errorMsgs = new Vector();
+ private boolean isTrustedBase;
private static Hashtable utilCache = new Hashtable();
@@ -101,6 +102,7 @@
if (expandEntityReferences) {
parser.setExpandEntityReferences(expandEntityReferences);
}
+ parser.setIsTrustedBase(isTrustedBase);
parser.parse(filename);
}
catch (IOException ex) {
@@ -153,6 +155,10 @@
this.expandEntityReferences = expandEntityReferences;
}
+ public void setIsTrustedBase(boolean trusted) {
+ this.isTrustedBase = trusted;
+ }
+
public boolean getExpandEntityReferences() {
return expandEntityReferences;
}
diff --git a/xml/bundles/org.eclipse.wst.dtd.core/saxparser/org/eclipse/wst/dtd/core/internal/saxparser/DTDParser.java b/xml/bundles/org.eclipse.wst.dtd.core/saxparser/org/eclipse/wst/dtd/core/internal/saxparser/DTDParser.java
index 8fd6a8c..cf029bc 100644
--- a/xml/bundles/org.eclipse.wst.dtd.core/saxparser/org/eclipse/wst/dtd/core/internal/saxparser/DTDParser.java
+++ b/xml/bundles/org.eclipse.wst.dtd.core/saxparser/org/eclipse/wst/dtd/core/internal/saxparser/DTDParser.java
@@ -145,7 +145,7 @@
currentDTD.setIsExceptionDuringParse(true);
}
catch (Exception e) {
- Logger.logException(e);
+ Logger.log(Logger.ERROR_DEBUG, e.getMessage(), e);
if (currentDTD != null)
currentDTD.setIsExceptionDuringParse(true);
}
@@ -171,6 +171,15 @@
}
}
+ /**
+ * Affects the resolution of external entities by asserting that the parser
+ * started with a trusted/known DTD
+ * @param nowTrusted
+ */
+ public void setIsTrustedBase(boolean nowTrusted) {
+ this.isTrustedBase = nowTrusted;
+ }
+
/*
* @deprecated Entity references are always expanded.
*/
@@ -249,6 +258,12 @@
protected String attributeString = ""; //$NON-NLS-1$
+ /**
+ * Is this a trusted (known) URI, or what that was referenced by a
+ * known/trusted URI?
+ */
+ boolean isTrustedBase;
+
public void attributeDecl(String eName, String aName, String type, String valueDefault, String value) throws SAXException {
startDeclaration(DeclNode.ATTLIST);
//declString = "<!ATTLIST"; //$NON-NLS-1$
@@ -578,8 +593,14 @@
break;
}
case DeclNode.EXTERNAL_ENTITY : {
- if (!this.expandEntityReferences) {
- break;
+ if (!this.isTrustedBase) {
+ if (!this.expandEntityReferences) {
+ break;
+ }
+ boolean resolveExternalEntities = InstanceScope.INSTANCE.getNode(XMLCorePlugin.getDefault().getBundle().getSymbolicName()).getBoolean(XMLCorePreferenceNames.RESOLVE_EXTERNAL_ENTITIES, false);
+ if (!resolveExternalEntities) {
+ break;
+ }
}
}
case DeclNode.INTERNAL_ENTITY : {
diff --git a/xml/bundles/org.eclipse.wst.dtd.core/src/org/eclipse/wst/dtd/core/internal/DTDCorePlugin.java b/xml/bundles/org.eclipse.wst.dtd.core/src/org/eclipse/wst/dtd/core/internal/DTDCorePlugin.java
index 357601c..9896848 100644
--- a/xml/bundles/org.eclipse.wst.dtd.core/src/org/eclipse/wst/dtd/core/internal/DTDCorePlugin.java
+++ b/xml/bundles/org.eclipse.wst.dtd.core/src/org/eclipse/wst/dtd/core/internal/DTDCorePlugin.java
@@ -14,11 +14,23 @@
*******************************************************************************/
package org.eclipse.wst.dtd.core.internal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
+import org.eclipse.wst.xml.core.internal.XMLCorePlugin;
+import org.osgi.framework.BundleContext;
public class DTDCorePlugin extends Plugin {
private static DTDCorePlugin instance;
+ public static Map<String, String[]> KNOWN_URIS;
+
public synchronized static DTDCorePlugin getInstance() {
return instance;
}
@@ -27,6 +39,32 @@
return instance;
}
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+
+ KNOWN_URIS = new HashMap<>();
+ IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(XMLCorePlugin.getDefault().getBundle().getSymbolicName(), "catalogContributions");
+ IConfigurationElement[] configurationElements = extension.getConfigurationElements();
+ Map<String, List<String>> known = new HashMap<>();
+ for (int i = 0; i < configurationElements.length; i++) {
+ String contributor = configurationElements[i].getNamespaceIdentifier();
+ if (!known.containsKey(contributor)) {
+ known.put(contributor, new ArrayList<>());
+ }
+ IConfigurationElement[] elements = configurationElements[i].getChildren();
+ for (int j = 0; j < elements.length; j++) {
+ String uri = elements[j].getAttribute("uri");
+ if (uri != null && uri.length() > 0) {
+ known.get(contributor).add(uri);
+ }
+ }
+ }
+ known.forEach((contributor, uris) -> {
+ KNOWN_URIS.put(contributor, uris.toArray(new String[uris.size()]));
+ });
+ }
+
public DTDCorePlugin() {
super();
instance = this;