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