1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security.access;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.fail;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.hadoop.conf.Configuration;
26 import org.apache.hadoop.fs.Path;
27 import org.apache.hadoop.hbase.client.Admin;
28 import org.apache.hadoop.hbase.client.Connection;
29 import org.apache.hadoop.hbase.client.ConnectionFactory;
30 import org.apache.hadoop.hbase.client.Table;
31 import org.apache.hadoop.hbase.Coprocessor;
32 import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
33 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
34 import org.apache.hadoop.hbase.HBaseTestingUtility;
35 import org.apache.hadoop.hbase.HColumnDescriptor;
36 import org.apache.hadoop.hbase.HConstants;
37 import org.apache.hadoop.hbase.HTableDescriptor;
38 import org.apache.hadoop.hbase.TableName;
39 import org.apache.hadoop.hbase.TableNotEnabledException;
40 import org.apache.hadoop.hbase.TableNotFoundException;
41 import org.apache.hadoop.hbase.coprocessor.RegionObserver;
42 import org.apache.hadoop.hbase.testclassification.MediumTests;
43 import org.apache.hadoop.hbase.util.Bytes;
44
45 import org.junit.Test;
46 import org.junit.experimental.categories.Category;
47 import org.apache.hadoop.hbase.CategoryBasedTimeout;
48 import org.junit.rules.TestRule;
49 import org.junit.After;
50 import org.junit.ClassRule;
51
52 import java.io.IOException;
53
54
55
56
57 @Category({MediumTests.class})
58 public class TestCoprocessorWhitelistMasterObserver extends SecureTestUtil {
59 private static final Log LOG = LogFactory.getLog(TestCoprocessorWhitelistMasterObserver.class);
60 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
61 private static Configuration conf;
62 private static final TableName TEST_TABLE = TableName.valueOf("testTable");
63 private static final byte[] TEST_FAMILY = Bytes.toBytes("fam1");
64
65 @After
66 public void tearDownTestCoprocessorWhitelistMasterObserver() throws Exception {
67 Admin admin = UTIL.getHBaseAdmin();
68 try {
69 try {
70 admin.disableTable(TEST_TABLE);
71 } catch (TableNotEnabledException ex) {
72
73 LOG.info("Table was left disabled by test");
74 }
75 admin.deleteTable(TEST_TABLE);
76 } catch (TableNotFoundException ex) {
77
78 LOG.info("Table was not created for some reason");
79 }
80 UTIL.shutdownMiniCluster();
81 }
82
83 @ClassRule
84 public static TestRule timeout =
85 CategoryBasedTimeout.builder().withTimeout(TestCoprocessorWhitelistMasterObserver.class).build();
86
87
88
89
90
91
92
93
94
95
96 private static void positiveTestCase(String[] whitelistedPaths,
97 String coprocessorPath) throws Exception {
98 Configuration conf = UTIL.getConfiguration();
99
100 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
101 CoprocessorWhitelistMasterObserver.class.getName());
102 conf.setStrings(
103 CoprocessorWhitelistMasterObserver.CP_COPROCESSOR_WHITELIST_PATHS_KEY,
104 whitelistedPaths);
105
106 conf.setInt("hbase.client.retries.number", 1);
107 UTIL.startMiniCluster();
108 Table table = UTIL.createTable(TEST_TABLE,
109 new byte[][] { TEST_FAMILY });
110 UTIL.waitUntilAllRegionsAssigned(TEST_TABLE);
111 Connection connection = ConnectionFactory.createConnection(conf);
112 Table t = connection.getTable(TEST_TABLE);
113 HTableDescriptor htd = new HTableDescriptor(t.getTableDescriptor());
114 htd.addCoprocessor("net.clayb.hbase.coprocessor.NotWhitelisted",
115 new Path(coprocessorPath),
116 Coprocessor.PRIORITY_USER, null);
117 LOG.info("Modifying Table");
118 try {
119 connection.getAdmin().modifyTable(TEST_TABLE, htd);
120 fail("Expected coprocessor to raise IOException");
121 } catch (IOException e) {
122
123 }
124 LOG.info("Done Modifying Table");
125 assertEquals(0, t.getTableDescriptor().getCoprocessors().size());
126 }
127
128
129
130
131
132
133
134
135
136
137
138 private static void negativeTestCase(String[] whitelistedPaths,
139 String coprocessorPath) throws Exception {
140 Configuration conf = UTIL.getConfiguration();
141
142 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
143 CoprocessorWhitelistMasterObserver.class.getName());
144
145 conf.setInt("hbase.client.retries.number", 1);
146
147 conf.setStrings(
148 CoprocessorWhitelistMasterObserver.CP_COPROCESSOR_WHITELIST_PATHS_KEY,
149 whitelistedPaths);
150 UTIL.startMiniCluster();
151 Table table = UTIL.createTable(TEST_TABLE,
152 new byte[][] { TEST_FAMILY });
153 UTIL.waitUntilAllRegionsAssigned(TEST_TABLE);
154 Connection connection = ConnectionFactory.createConnection(conf);
155 Admin admin = connection.getAdmin();
156
157
158 admin.disableTable(TEST_TABLE);
159 Table t = connection.getTable(TEST_TABLE);
160 HTableDescriptor htd = new HTableDescriptor(t.getTableDescriptor());
161 htd.addCoprocessor("net.clayb.hbase.coprocessor.Whitelisted",
162 new Path(coprocessorPath),
163 Coprocessor.PRIORITY_USER, null);
164 LOG.info("Modifying Table");
165 admin.modifyTable(TEST_TABLE, htd);
166 assertEquals(1, t.getTableDescriptor().getCoprocessors().size());
167 LOG.info("Done Modifying Table");
168 }
169
170
171
172
173
174
175
176 @Test
177 @Category(MediumTests.class)
178 public void testSubstringNonWhitelisted() throws Exception {
179 positiveTestCase(new String[]{"/permitted/*"},
180 "file:///notpermitted/couldnotpossiblyexist.jar");
181 }
182
183
184
185
186
187
188
189
190 @Test
191 @Category(MediumTests.class)
192 public void testDifferentFileSystemNonWhitelisted() throws Exception {
193 positiveTestCase(new String[]{"hdfs://foo/bar"},
194 "file:///notpermitted/couldnotpossiblyexist.jar");
195 }
196
197
198
199
200
201
202
203
204 @Test
205 @Category(MediumTests.class)
206 public void testSchemeAndDirectorywhitelisted() throws Exception {
207 negativeTestCase(new String[]{"/tmp","file:///permitted/*"},
208 "file:///permitted/couldnotpossiblyexist.jar");
209 }
210
211
212
213
214
215
216
217
218 @Test
219 @Category(MediumTests.class)
220 public void testSchemeWhitelisted() throws Exception {
221 negativeTestCase(new String[]{"file:///"},
222 "file:///permitted/couldnotpossiblyexist.jar");
223 }
224
225
226
227
228
229
230
231
232 @Test
233 @Category(MediumTests.class)
234 public void testDFSNameWhitelistedWorks() throws Exception {
235 negativeTestCase(new String[]{"hdfs://Your-FileSystem"},
236 "hdfs://Your-FileSystem/permitted/couldnotpossiblyexist.jar");
237 }
238
239
240
241
242
243
244
245
246 @Test
247 @Category(MediumTests.class)
248 public void testDFSNameNotWhitelistedFails() throws Exception {
249 positiveTestCase(new String[]{"hdfs://Your-FileSystem"},
250 "hdfs://My-FileSystem/permitted/couldnotpossiblyexist.jar");
251 }
252
253
254
255
256
257
258
259
260 @Test
261 @Category(MediumTests.class)
262 public void testBlanketWhitelist() throws Exception {
263 negativeTestCase(new String[]{"*"},
264 "hdfs:///permitted/couldnotpossiblyexist.jar");
265 }
266
267
268
269
270
271
272 @Test
273 @Category(MediumTests.class)
274 public void testCreationNonWhitelistedCoprocessorPath() throws Exception {
275 Configuration conf = UTIL.getConfiguration();
276
277 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
278 CoprocessorWhitelistMasterObserver.class.getName());
279 conf.setStrings(CoprocessorWhitelistMasterObserver.CP_COPROCESSOR_WHITELIST_PATHS_KEY,
280 new String[]{});
281
282 conf.setInt("hbase.client.retries.number", 1);
283 UTIL.startMiniCluster();
284 HTableDescriptor htd = new HTableDescriptor(TEST_TABLE);
285 HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
286 htd.addFamily(hcd);
287 htd.addCoprocessor("net.clayb.hbase.coprocessor.NotWhitelisted",
288 new Path("file:///notpermitted/couldnotpossiblyexist.jar"),
289 Coprocessor.PRIORITY_USER, null);
290 Connection connection = ConnectionFactory.createConnection(conf);
291 Admin admin = connection.getAdmin();
292 LOG.info("Creating Table");
293 try {
294 admin.createTable(htd);
295 fail("Expected coprocessor to raise IOException");
296 } catch (IOException e) {
297
298 }
299 LOG.info("Done Creating Table");
300
301 assertEquals(new HTableDescriptor[0],
302 admin.listTables("^" + TEST_TABLE.getNameAsString() + "$"));
303 }
304
305
306 public static class TestRegionObserver extends BaseRegionObserver {}
307
308
309
310
311
312
313 @Test
314 @Category(MediumTests.class)
315 public void testCreationClasspathCoprocessor() throws Exception {
316 Configuration conf = UTIL.getConfiguration();
317
318 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
319 CoprocessorWhitelistMasterObserver.class.getName());
320 conf.setStrings(CoprocessorWhitelistMasterObserver.CP_COPROCESSOR_WHITELIST_PATHS_KEY,
321 new String[]{});
322
323 conf.setInt("hbase.client.retries.number", 1);
324 UTIL.startMiniCluster();
325 HTableDescriptor htd = new HTableDescriptor(TEST_TABLE);
326 HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
327 htd.addFamily(hcd);
328 htd.addCoprocessor(TestRegionObserver.class.getName());
329 Connection connection = ConnectionFactory.createConnection(conf);
330 Admin admin = connection.getAdmin();
331 LOG.info("Creating Table");
332 admin.createTable(htd);
333
334 LOG.info("Done Creating Table");
335 Table t = connection.getTable(TEST_TABLE);
336 assertEquals(1, t.getTableDescriptor().getCoprocessors().size());
337 }
338 }