View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.hadoop.hbase.rest.client;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertTrue;
21  import static org.junit.Assert.fail;
22  import static org.mockito.Mockito.mock;
23  import static org.mockito.Mockito.when;
24  
25  import java.io.IOException;
26  
27  import javax.xml.bind.UnmarshalException;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.HBaseConfiguration;
32  import org.apache.hadoop.hbase.rest.Constants;
33  import org.apache.hadoop.hbase.rest.model.StorageClusterVersionModel;
34  import org.apache.hadoop.hbase.testclassification.SmallTests;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.util.StringUtils;
37  import org.junit.Test;
38  import org.junit.experimental.categories.Category;
39  
40  /**
41   * Test class for {@link RemoteAdmin} to verify XML is parsed in a certain manner.
42   */
43  @Category(SmallTests.class)
44  public class TestXmlParsing {
45    private static final Log LOG = LogFactory.getLog(TestXmlParsing.class);
46  
47    @Test
48    public void testParsingClusterVersion() throws Exception {
49      final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
50          + "<ClusterVersion Version=\"2.0.0\"/>";
51      Client client = mock(Client.class);
52      RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null);
53      Response resp = new Response(200, null, Bytes.toBytes(xml));
54  
55      when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp);
56  
57      StorageClusterVersionModel cv = admin.getClusterVersion();
58      assertEquals("2.0.0", cv.getVersion());
59    }
60  
61    @Test
62    public void testFailOnExternalEntities() throws Exception {
63      final String externalEntitiesXml =
64          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
65          + " <!DOCTYPE foo [ <!ENTITY xxe SYSTEM \"/tmp/foo\"> ] >"
66          + " <ClusterVersion>&xee;</ClusterVersion>";
67      Client client = mock(Client.class);
68      RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null);
69      Response resp = new Response(200, null, Bytes.toBytes(externalEntitiesXml));
70  
71      when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp);
72  
73      try {
74        admin.getClusterVersion();
75        fail("Expected getClusterVersion() to throw an exception");
76      } catch (IOException e) {
77        assertEquals("Cause of exception ought to be a failure to parse the stream due to our " +
78            "invalid external entity. Make sure this isn't just a false positive due to " +
79            "implementation. see HBASE-19020.", UnmarshalException.class, e.getCause().getClass());
80        final String exceptionText = StringUtils.stringifyException(e);
81        final String expectedText = "\"xee\"";
82        LOG.debug("exception text: '" + exceptionText + "'", e);
83        assertTrue("Exception does not contain expected text", exceptionText.contains(expectedText));
84      }
85    }
86  }