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