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
22 import java.util.List;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.hbase.Cell;
28 import org.apache.hadoop.hbase.Coprocessor;
29 import org.apache.hadoop.hbase.HBaseTestingUtility;
30 import org.apache.hadoop.hbase.HColumnDescriptor;
31 import org.apache.hadoop.hbase.HTableDescriptor;
32 import org.apache.hadoop.hbase.testclassification.MediumTests;
33 import org.apache.hadoop.hbase.TableNotFoundException;
34 import org.apache.hadoop.hbase.client.Admin;
35 import org.apache.hadoop.hbase.client.Delete;
36 import org.apache.hadoop.hbase.client.Get;
37 import org.apache.hadoop.hbase.client.HTable;
38 import org.apache.hadoop.hbase.client.Increment;
39 import org.apache.hadoop.hbase.client.Put;
40 import org.apache.hadoop.hbase.client.Result;
41 import org.apache.hadoop.hbase.client.ResultScanner;
42 import org.apache.hadoop.hbase.client.Scan;
43 import org.apache.hadoop.hbase.client.Table;
44 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
45 import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
46 import org.apache.hadoop.hbase.security.User;
47 import org.apache.hadoop.hbase.security.access.Permission.Action;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.apache.hadoop.hbase.util.TestTableName;
50 import org.apache.hadoop.hbase.util.Threads;
51 import org.apache.log4j.Level;
52 import org.apache.log4j.Logger;
53 import org.junit.After;
54 import org.junit.AfterClass;
55 import org.junit.Before;
56 import org.junit.BeforeClass;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.experimental.categories.Category;
60
61 import com.google.common.collect.Lists;
62
63 @Category(MediumTests.class)
64 public class TestCellACLs extends SecureTestUtil {
65 private static final Log LOG = LogFactory.getLog(TestCellACLs.class);
66
67 static {
68 Logger.getLogger(AccessController.class).setLevel(Level.TRACE);
69 Logger.getLogger(AccessControlFilter.class).setLevel(Level.TRACE);
70 Logger.getLogger(TableAuthManager.class).setLevel(Level.TRACE);
71 }
72
73 @Rule
74 public TestTableName TEST_TABLE = new TestTableName();
75 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
76 private static final byte[] TEST_FAMILY = Bytes.toBytes("f1");
77 private static final byte[] TEST_ROW = Bytes.toBytes("cellpermtest");
78 private static final byte[] TEST_Q1 = Bytes.toBytes("q1");
79 private static final byte[] TEST_Q2 = Bytes.toBytes("q2");
80 private static final byte[] TEST_Q3 = Bytes.toBytes("q3");
81 private static final byte[] TEST_Q4 = Bytes.toBytes("q4");
82 private static final byte[] ZERO = Bytes.toBytes(0L);
83 private static final byte[] ONE = Bytes.toBytes(1L);
84
85 private static Configuration conf;
86
87 private static User USER_OWNER;
88 private static User USER_OTHER;
89
90 @BeforeClass
91 public static void setupBeforeClass() throws Exception {
92
93 conf = TEST_UTIL.getConfiguration();
94
95 enableSecurity(conf);
96
97 verifyConfiguration(conf);
98
99
100 conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false);
101
102 TEST_UTIL.startMiniCluster();
103 MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster()
104 .getMasterCoprocessorHost();
105 cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf);
106 AccessController ac = (AccessController)
107 cpHost.findCoprocessor(AccessController.class.getName());
108 cpHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf);
109 RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
110 .getRegionServerCoprocessorHost();
111 rsHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf);
112
113
114 TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME);
115
116
117 USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
118 USER_OTHER = User.createUserForTesting(conf, "other", new String[0]);
119 }
120
121 @AfterClass
122 public static void tearDownAfterClass() throws Exception {
123 TEST_UTIL.shutdownMiniCluster();
124 }
125
126 @Before
127 public void setUp() throws Exception {
128
129 Admin admin = TEST_UTIL.getHBaseAdmin();
130 HTableDescriptor htd = new HTableDescriptor(TEST_TABLE.getTableName());
131 HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
132 hcd.setMaxVersions(4);
133 htd.setOwner(USER_OWNER);
134 htd.addFamily(hcd);
135 admin.createTable(htd, new byte[][] { Bytes.toBytes("s") });
136 TEST_UTIL.waitTableEnabled(TEST_TABLE.getTableName());
137 LOG.info("Sleeping a second because of HBASE-12581");
138 Threads.sleep(1000);
139 }
140
141 @Test
142 public void testCellPermissions() throws Exception {
143
144 verifyAllowed(new AccessTestAction() {
145 @Override
146 public Object run() throws Exception {
147 Table t = new HTable(conf, TEST_TABLE.getTableName());
148 try {
149 Put p;
150
151 p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q1, ZERO);
152 p.setACL(USER_OTHER.getShortName(), new Permission(Action.READ));
153 t.put(p);
154
155 p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q2, ZERO);
156 p.setACL(USER_OTHER.getShortName(), new Permission(Action.READ, Action.WRITE));
157 t.put(p);
158
159 p = new Put(TEST_ROW)
160 .add(TEST_FAMILY, TEST_Q3, ZERO)
161 .add(TEST_FAMILY, TEST_Q4, ZERO);
162 t.put(p);
163 } finally {
164 t.close();
165 }
166 return null;
167 }
168 }, USER_OWNER);
169
170
171
172 AccessTestAction getQ1 = new AccessTestAction() {
173 @Override
174 public Object run() throws Exception {
175 Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q1);
176 Table t = new HTable(conf, TEST_TABLE.getTableName());
177 try {
178 return t.get(get).listCells();
179 } finally {
180 t.close();
181 }
182 }
183 };
184
185 AccessTestAction getQ2 = new AccessTestAction() {
186 @Override
187 public Object run() throws Exception {
188 Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q2);
189 Table t = new HTable(conf, TEST_TABLE.getTableName());
190 try {
191 return t.get(get).listCells();
192 } finally {
193 t.close();
194 }
195 }
196 };
197
198 AccessTestAction getQ3 = new AccessTestAction() {
199 @Override
200 public Object run() throws Exception {
201 Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q3);
202 Table t = new HTable(conf, TEST_TABLE.getTableName());
203 try {
204 return t.get(get).listCells();
205 } finally {
206 t.close();
207 }
208 }
209 };
210
211 AccessTestAction getQ4 = new AccessTestAction() {
212 @Override
213 public Object run() throws Exception {
214 Get get = new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q4);
215 Table t = new HTable(conf, TEST_TABLE.getTableName());
216 try {
217 return t.get(get).listCells();
218 } finally {
219 t.close();
220 }
221 }
222 };
223
224
225
226 verifyAllowed(getQ1, USER_OTHER);
227 verifyAllowed(getQ2, USER_OTHER);
228
229
230
231 verifyDenied(getQ3, USER_OTHER);
232 verifyDenied(getQ4, USER_OTHER);
233
234
235
236
237
238 final List<Cell> scanResults = Lists.newArrayList();
239
240 AccessTestAction scanAction = new AccessTestAction() {
241 @Override
242 public List<Cell> run() throws Exception {
243 Scan scan = new Scan();
244 scan.setStartRow(TEST_ROW);
245 scan.setStopRow(Bytes.add(TEST_ROW, new byte[]{ 0 } ));
246 scan.addFamily(TEST_FAMILY);
247 Table t = new HTable(conf, TEST_TABLE.getTableName());
248 try {
249 ResultScanner scanner = t.getScanner(scan);
250 Result result = null;
251 do {
252 result = scanner.next();
253 if (result != null) {
254 scanResults.addAll(result.listCells());
255 }
256 } while (result != null);
257 } finally {
258 t.close();
259 }
260 return scanResults;
261 }
262 };
263
264
265 scanResults.clear();
266 verifyAllowed(scanAction, USER_OWNER);
267 assertEquals(4, scanResults.size());
268
269
270 scanResults.clear();
271 verifyAllowed(scanAction, USER_OTHER);
272 assertEquals(2, scanResults.size());
273
274
275
276 AccessTestAction incrementQ1 = new AccessTestAction() {
277 @Override
278 public Object run() throws Exception {
279 Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q1, 1L);
280 Table t = new HTable(conf, TEST_TABLE.getTableName());
281 try {
282 t.increment(i);
283 } finally {
284 t.close();
285 }
286 return null;
287 }
288 };
289
290 AccessTestAction incrementQ2 = new AccessTestAction() {
291 @Override
292 public Object run() throws Exception {
293 Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q2, 1L);
294 Table t = new HTable(conf, TEST_TABLE.getTableName());
295 try {
296 t.increment(i);
297 } finally {
298 t.close();
299 }
300 return null;
301 }
302 };
303
304 AccessTestAction incrementQ2newDenyACL = new AccessTestAction() {
305 @Override
306 public Object run() throws Exception {
307 Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q2, 1L);
308
309 i.setACL(USER_OTHER.getShortName(), new Permission(Action.READ));
310 Table t = new HTable(conf, TEST_TABLE.getTableName());
311 try {
312 t.increment(i);
313 } finally {
314 t.close();
315 }
316 return null;
317 }
318 };
319
320 AccessTestAction incrementQ3 = new AccessTestAction() {
321 @Override
322 public Object run() throws Exception {
323 Increment i = new Increment(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q3, 1L);
324 Table t = new HTable(conf, TEST_TABLE.getTableName());
325 try {
326 t.increment(i);
327 } finally {
328 t.close();
329 }
330 return null;
331 }
332 };
333
334 verifyDenied(incrementQ1, USER_OTHER);
335 verifyDenied(incrementQ3, USER_OTHER);
336
337
338
339 verifyAllowed(incrementQ2, USER_OTHER);
340 verifyAllowed(incrementQ2newDenyACL, USER_OTHER);
341
342
343 verifyDenied(incrementQ2, USER_OTHER);
344
345
346
347 AccessTestAction deleteFamily = new AccessTestAction() {
348 @Override
349 public Object run() throws Exception {
350 Delete delete = new Delete(TEST_ROW).deleteFamily(TEST_FAMILY);
351 Table t = new HTable(conf, TEST_TABLE.getTableName());
352 try {
353 t.delete(delete);
354 } finally {
355 t.close();
356 }
357 return null;
358 }
359 };
360
361 AccessTestAction deleteQ1 = new AccessTestAction() {
362 @Override
363 public Object run() throws Exception {
364 Delete delete = new Delete(TEST_ROW).deleteColumn(TEST_FAMILY, TEST_Q1);
365 Table t = new HTable(conf, TEST_TABLE.getTableName());
366 try {
367 t.delete(delete);
368 } finally {
369 t.close();
370 }
371 return null;
372 }
373 };
374
375 verifyDenied(deleteFamily, USER_OTHER);
376 verifyDenied(deleteQ1, USER_OTHER);
377 verifyAllowed(deleteQ1, USER_OWNER);
378 }
379
380
381
382
383
384 @Test
385 public void testCoveringCheck() throws Exception {
386
387 grantOnTable(TEST_UTIL, USER_OTHER.getShortName(), TEST_TABLE.getTableName(),
388 TEST_FAMILY, null, Action.READ);
389
390
391
392
393 verifyDenied(new AccessTestAction() {
394 @Override
395 public Object run() throws Exception {
396 Table t = new HTable(conf, TEST_TABLE.getTableName());
397 try {
398 Put p;
399 p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q1, ZERO);
400 t.put(p);
401 } finally {
402 t.close();
403 }
404 return null;
405 }
406 }, USER_OTHER);
407
408
409 verifyAllowed(new AccessTestAction() {
410 @Override
411 public Object run() throws Exception {
412 Table t = new HTable(conf, TEST_TABLE.getTableName());
413 try {
414 Put p;
415 p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q1, ZERO);
416 t.put(p);
417 } finally {
418 t.close();
419 }
420 return null;
421 }
422 }, USER_OWNER);
423
424
425 verifyDenied(new AccessTestAction() {
426 @Override
427 public Object run() throws Exception {
428 Table t = new HTable(conf, TEST_TABLE.getTableName());
429 try {
430 Put p;
431 p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q1, ONE);
432 t.put(p);
433 } finally {
434 t.close();
435 }
436 return null;
437 }
438 }, USER_OTHER);
439
440
441 verifyAllowed(new AccessTestAction() {
442 @Override
443 public Object run() throws Exception {
444 Table t = new HTable(conf, TEST_TABLE.getTableName());
445 try {
446 return t.get(new Get(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q1));
447 } finally {
448 t.close();
449 }
450 }
451 }, USER_OTHER);
452 }
453
454 @After
455 public void tearDown() throws Exception {
456
457 try {
458 TEST_UTIL.deleteTable(TEST_TABLE.getTableName());
459 } catch (TableNotFoundException ex) {
460
461 LOG.info("Test deleted table " + TEST_TABLE.getTableName());
462 }
463 assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size());
464 }
465 }