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