-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SOLR-12450: Don't allow referal to external resources in various conf…
…ig files
- Loading branch information
1 parent
e27cf65
commit 1880d48
Showing
5 changed files
with
287 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
solr/core/src/java/org/apache/solr/util/SafeXMLParsing.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.solr.util; | ||
|
||
import java.io.FilterReader; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.Reader; | ||
import java.io.StringReader; | ||
|
||
import javax.xml.XMLConstants; | ||
import javax.xml.parsers.DocumentBuilder; | ||
import javax.xml.parsers.DocumentBuilderFactory; | ||
import javax.xml.parsers.ParserConfigurationException; | ||
|
||
import org.apache.commons.io.input.CloseShieldInputStream; | ||
import org.apache.lucene.analysis.util.ResourceLoader; | ||
import org.apache.solr.common.EmptyEntityResolver; | ||
import org.apache.solr.common.SolrException; | ||
import org.apache.solr.common.util.SuppressForbidden; | ||
import org.apache.solr.common.util.XMLErrorLogger; | ||
import org.slf4j.Logger; | ||
import org.w3c.dom.Document; | ||
import org.xml.sax.InputSource; | ||
import org.xml.sax.SAXException; | ||
|
||
/** | ||
* Some utility methods for parsing XML in a safe way. This class can be used to parse XML | ||
* coming from network (completely untrusted) or it can load a config file from a | ||
* {@link ResourceLoader}. In this case it allows external entities and xincludes, but only | ||
* referring to files reachable by the loader. | ||
*/ | ||
@SuppressForbidden(reason = "This class uses XML APIs directly that should not be used anywhere else in Solr code") | ||
public final class SafeXMLParsing { | ||
|
||
public static final String SYSTEMID_UNTRUSTED = "untrusted://stream"; | ||
|
||
private SafeXMLParsing() {} | ||
|
||
/** Parses a config file from ResourceLoader. Xinclude and external entities are enabled, but cannot escape the resource loader. */ | ||
public static Document parseConfigXML(Logger log, ResourceLoader loader, String file) throws SAXException, IOException { | ||
try (InputStream in = loader.openResource(file)) { | ||
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | ||
dbf.setValidating(false); | ||
dbf.setNamespaceAware(true); | ||
trySetDOMFeature(dbf, XMLConstants.FEATURE_SECURE_PROCESSING, true); | ||
try { | ||
dbf.setXIncludeAware(true); | ||
} catch (UnsupportedOperationException e) { | ||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "XML parser doesn't support XInclude option", e); | ||
} | ||
|
||
final DocumentBuilder db = dbf.newDocumentBuilder(); | ||
db.setEntityResolver(new SystemIdResolver(loader)); | ||
db.setErrorHandler(new XMLErrorLogger(log)); | ||
return db.parse(in, SystemIdResolver.createSystemIdFromResourceName(file)); | ||
} catch (ParserConfigurationException pce) { | ||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "XML parser cannot be configured", pce); | ||
} | ||
} | ||
|
||
/** Parses the given InputStream as XML, disabling any external entities with secure processing enabled. | ||
* The given InputStream is not closed. */ | ||
public static Document parseUntrustedXML(Logger log, InputStream in) throws SAXException, IOException { | ||
return getUntrustedDocumentBuilder(log).parse(new CloseShieldInputStream(in), SYSTEMID_UNTRUSTED); | ||
} | ||
|
||
/** Parses the given InputStream as XML, disabling any external entities with secure processing enabled. | ||
* The given Reader is not closed. */ | ||
public static Document parseUntrustedXML(Logger log, Reader reader) throws SAXException, IOException { | ||
final InputSource is = new InputSource(new FilterReader(reader) { | ||
@Override public void close() {} | ||
}); | ||
is.setSystemId(SYSTEMID_UNTRUSTED); | ||
return getUntrustedDocumentBuilder(log).parse(is); | ||
} | ||
|
||
public static Document parseUntrustedXML(Logger log, String xml) throws SAXException, IOException { | ||
return parseUntrustedXML(log, new StringReader(xml)); | ||
} | ||
|
||
private static DocumentBuilder getUntrustedDocumentBuilder(Logger log) { | ||
try { | ||
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | ||
dbf.setValidating(false); | ||
dbf.setNamespaceAware(true); | ||
trySetDOMFeature(dbf, XMLConstants.FEATURE_SECURE_PROCESSING, true); | ||
|
||
final DocumentBuilder db = dbf.newDocumentBuilder(); | ||
db.setEntityResolver(EmptyEntityResolver.SAX_INSTANCE); | ||
db.setErrorHandler(new XMLErrorLogger(log)); | ||
return db; | ||
} catch (ParserConfigurationException pce) { | ||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "XML parser cannot be configured", pce); | ||
} | ||
} | ||
|
||
private static void trySetDOMFeature(DocumentBuilderFactory factory, String feature, boolean enabled) { | ||
try { | ||
factory.setFeature(feature, enabled); | ||
} catch (Exception ex) { | ||
// ignore | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.