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  import javax.xml.bind.UnmarshalException;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.hbase.HBaseConfiguration;
31  import org.apache.hadoop.hbase.rest.Constants;
32  import org.apache.hadoop.hbase.rest.model.StorageClusterVersionModel;
33  import org.apache.hadoop.hbase.testclassification.SmallTests;
34  import org.apache.hadoop.util.StringUtils;
35  import org.junit.Test;
36  import org.junit.experimental.categories.Category;
37  
38  /**
39   * Test class for {@link RemoteAdmin} to verify XML is parsed in a certain manner.
40   */
41  @Category(SmallTests.class)
42  public class TestXmlParsing {
43    private static final Log LOG = LogFactory.getLog(TestXmlParsing.class);
44  
45    @Test
46    public void testParsingClusterVersion() throws Exception {
47      final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
48          + "<ClusterVersion>2.0.0</ClusterVersion>";
49      Client client = mock(Client.class);
50      RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null);
51      Response resp = new Response(200, null, xml.getBytes());
52  
53      when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp);
54  
55      StorageClusterVersionModel cv = admin.getClusterVersion();
56      assertEquals("2.0.0", cv.getVersion());
57    }
58  
59    @Test
60    public void testFailOnExternalEntities() throws Exception {
61      final String externalEntitiesXml =
62          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
63          + " <!DOCTYPE foo [ <!ENTITY xxe SYSTEM \"/tmp/foo\"> ] >"
64          + " <ClusterVersion>&xee;</ClusterVersion>";
65      Client client = mock(Client.class);
66      RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null);
67      Response resp = new Response(200, null, externalEntitiesXml.getBytes());
68  
69      when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp);
70  
71      try {
72        admin.getClusterVersion();
73        fail("Expected getClusterVersion() to throw an exception");
74      } catch (IOException e) {
75        assertEquals("Cause of exception ought to be a failure to parse the stream due to our " +
76            "invalid external entity. Make sure this isn't just a false positive due to " +
77            "implementation. see HBASE-19020.", UnmarshalException.class, e.getCause().getClass());
78        final String exceptionText = StringUtils.stringifyException(e);
79        final String expectedText = "\"xee\"";
80        LOG.debug("exception text: '" + exceptionText + "'", e);
81        assertTrue("Exception does not contain expected text", exceptionText.contains(expectedText));
82      }
83    }
84  }