001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.rest.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022import static org.junit.Assert.fail; 023import static org.mockito.Mockito.mock; 024import static org.mockito.Mockito.when; 025 026import java.io.IOException; 027import javax.xml.bind.UnmarshalException; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseConfiguration; 030import org.apache.hadoop.hbase.rest.Constants; 031import org.apache.hadoop.hbase.rest.model.StorageClusterVersionModel; 032import org.apache.hadoop.hbase.testclassification.SmallTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.apache.hadoop.util.StringUtils; 035import org.junit.ClassRule; 036import org.junit.Test; 037import org.junit.experimental.categories.Category; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041/** 042 * Test class for {@link RemoteAdmin} to verify XML is parsed in a certain manner. 043 */ 044@Category(SmallTests.class) 045public class TestXmlParsing { 046 047 @ClassRule 048 public static final HBaseClassTestRule CLASS_RULE = 049 HBaseClassTestRule.forClass(TestXmlParsing.class); 050 051 private static final Logger LOG = LoggerFactory.getLogger(TestXmlParsing.class); 052 053 @Test 054 public void testParsingClusterVersion() throws Exception { 055 final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" 056 + "<ClusterVersion Version=\"2.0.0\"/>"; 057 Client client = mock(Client.class); 058 RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null); 059 Response resp = new Response(200, null, Bytes.toBytes(xml)); 060 061 when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp); 062 063 StorageClusterVersionModel cv = admin.getClusterVersion(); 064 assertEquals("2.0.0", cv.getVersion()); 065 } 066 067 @Test 068 public void testFailOnExternalEntities() throws Exception { 069 final String externalEntitiesXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 070 + " <!DOCTYPE foo [ <!ENTITY xxe SYSTEM \"/tmp/foo\"> ] >" 071 + " <ClusterVersion>&xee;</ClusterVersion>"; 072 Client client = mock(Client.class); 073 RemoteAdmin admin = new RemoteAdmin(client, HBaseConfiguration.create(), null); 074 Response resp = new Response(200, null, Bytes.toBytes(externalEntitiesXml)); 075 076 when(client.get("/version/cluster", Constants.MIMETYPE_XML)).thenReturn(resp); 077 078 try { 079 admin.getClusterVersion(); 080 fail("Expected getClusterVersion() to throw an exception"); 081 } catch (IOException e) { 082 assertEquals("Cause of exception ought to be a failure to parse the stream due to our " 083 + "invalid external entity. Make sure this isn't just a false positive due to " 084 + "implementation. see HBASE-19020.", UnmarshalException.class, e.getCause().getClass()); 085 final String exceptionText = StringUtils.stringifyException(e); 086 final String expectedText = "\"xee\""; 087 LOG.debug("exception text: '" + exceptionText + "'", e); 088 assertTrue("Exception does not contain expected text", exceptionText.contains(expectedText)); 089 } 090 } 091}