You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by sy...@apache.org on 2017/01/07 08:04:58 UTC

[16/16] hbase git commit: HBASE-17424 Disable external entity parsing in RemoteAdmin

HBASE-17424 Disable external entity parsing in RemoteAdmin


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/6fecf55a
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/6fecf55a
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/6fecf55a

Branch: refs/heads/hbase-12439
Commit: 6fecf55a7eb05d4f85a17ad9f56d9728f1c5d3e7
Parents: b2a9be0
Author: Josh Elser <el...@apache.org>
Authored: Tue Jan 3 19:02:08 2017 -0500
Committer: Josh Elser <el...@apache.org>
Committed: Fri Jan 6 16:38:50 2017 -0500

----------------------------------------------------------------------
 .../hadoop/hbase/rest/client/RemoteAdmin.java   | 26 ++++++-
 .../hbase/rest/client/TestXmlParsing.java       | 76 ++++++++++++++++++++
 2 files changed, 100 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/6fecf55a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/client/RemoteAdmin.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/client/RemoteAdmin.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/client/RemoteAdmin.java
index e8845eb..de1e23f 100644
--- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/client/RemoteAdmin.java
+++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/client/RemoteAdmin.java
@@ -26,6 +26,9 @@ import java.io.InterruptedIOException;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
 
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.classification.InterfaceStability;
@@ -209,12 +212,12 @@ public class RemoteAdmin {
         try {
 
           return (StorageClusterVersionModel) getUnmarsheller().unmarshal(
-              new ByteArrayInputStream(response.getBody()));
+              getInputStream(response));
         } catch (JAXBException jaxbe) {
 
           throw new IOException(
               "Issue parsing StorageClusterVersionModel object in XML form: "
-                  + jaxbe.getLocalizedMessage());
+                  + jaxbe.getLocalizedMessage(), jaxbe);
         }
       case 404:
         throw new IOException("Cluster version not found");
@@ -398,4 +401,23 @@ public class RemoteAdmin {
     throw new IOException("get request to " + path.toString()
         + " request timed out");
   }
+
+  /**
+   * Convert the REST server's response to an XML reader.
+   *
+   * @param response The REST server's response.
+   * @return A reader over the parsed XML document.
+   * @throws IOException If the document fails to parse
+   */
+  private XMLStreamReader getInputStream(Response response) throws IOException {
+    try {
+      // Prevent the parser from reading XMl with external entities defined
+      XMLInputFactory xif = XMLInputFactory.newFactory();
+      xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+      xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
+      return xif.createXMLStreamReader(new ByteArrayInputStream(response.getBody()));
+    } catch (XMLStreamException e) {
+      throw new IOException("Failed to parse XML", e);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/6fecf55a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestXmlParsing.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestXmlParsing.java b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestXmlParsing.java
new file mode 100644
index 0000000..56dc05e
--- /dev/null
+++ b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestXmlParsing.java
@@ -0,0 +1,76 @@
+/*
+ * 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.hadoop.hbase.rest.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.rest.Constants;
+import org.apache.hadoop.hbase.rest.model.StorageClusterVersionModel;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.util.StringUtils;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Test class for {@link RemoteAdmin} to verify XML is parsed in a certain manner.
+ */
+@Category(SmallTests.class)
+public class TestXmlParsing {
+
+  @Test
+  public void testParsingClusterVersion() throws Exception {
+    final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+        + "<ClusterVersion>2.0.0</ClusterVersion>";
+    Client client = mock(Client.class);
+    RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null);
+    Response resp = new Response(200, null, xml.getBytes());
+
+    when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp);
+
+    StorageClusterVersionModel cv = admin.getClusterVersion();
+    assertEquals("2.0.0", cv.getVersion());
+  }
+
+  @Test
+  public void testFailOnExternalEntities() throws Exception {
+    final String externalEntitiesXml =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+        + " <!DOCTYPE foo [ <!ENTITY xxe SYSTEM \"/tmp/foo\"> ] >"
+        + " <ClusterVersion>&xee;</ClusterVersion>";
+    Client client = mock(Client.class);
+    RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null);
+    Response resp = new Response(200, null, externalEntitiesXml.getBytes());
+
+    when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp);
+
+    try {
+      admin.getClusterVersion();
+      fail("Expected getClusterVersion() to throw an exception");
+    } catch (IOException e) {
+      final String exceptionText = StringUtils.stringifyException(e);
+      final String expectedText = "The entity \"xee\" was referenced, but not declared.";
+      assertTrue("Exception does not contain expected text", exceptionText.contains(expectedText));
+    }
+  }
+}