From 721147acf549958f48cb2d55e693507e3cd209f2 Mon Sep 17 00:00:00 2001 From: anoopsamjohn Date: Mon, 13 Jan 2014 17:53:40 +0000 Subject: [PATCH] HBASE-10326 Super user should be able scan all the cells irrespective of the visibility labels(Ram) git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1557792 13f79535-47bb-0310-9956-ffa450edef68 --- .../visibility/VisibilityController.java | 19 ++ .../visibility/TestVisibilityLabels.java | 234 ++++++++++++------ .../TestVisibilityLabelsWithACL.java | 103 +++++++- 3 files changed, 262 insertions(+), 94 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java index 4e82f271beb..2a2526b75ba 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java @@ -855,6 +855,11 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb RegionScanner s) throws IOException { HRegion region = e.getEnvironment().getRegion(); Authorizations authorizations = null; + // If a super user issues a scan, he should be able to scan the cells + // irrespective of the Visibility labels + if (checkIfScanOrGetFromSuperUser()) { + return s; + } try { authorizations = scan.getAuthorizations(); } catch (DeserializationException de) { @@ -872,6 +877,15 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb return s; } + private boolean checkIfScanOrGetFromSuperUser() throws IOException { + User user = getActiveUser(); + if (user != null && user.getShortName() != null) { + List auths = this.visibilityManager.getAuths(user.getShortName()); + return (auths.contains(SYSTEM_LABEL)); + } + return false; + } + @Override public RegionScanner postScannerOpen(final ObserverContext c, final Scan scan, final RegionScanner s) throws IOException { @@ -921,6 +935,11 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb public void preGetOp(ObserverContext e, Get get, List results) throws IOException { Authorizations authorizations = null; + // If a super user issues a get, he should be able to scan the cells + // irrespective of the Visibility labels + if (checkIfScanOrGetFromSuperUser()) { + return; + } try { authorizations = get.getAuthorizations(); } catch (DeserializationException de) { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java index fd78feb9aa9..f7ad077cbf9 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java @@ -101,7 +101,7 @@ public class TestVisibilityLabels { conf.setClass(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, SimpleScanLabelGenerator.class, ScanLabelGenerator.class); String currentUser = User.getCurrent().getName(); - conf.set("hbase.superuser", "admin,"+currentUser); + conf.set("hbase.superuser", "admin"); TEST_UTIL.startMiniCluster(2); SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); @@ -367,12 +367,19 @@ public class TestVisibilityLabels { // Start one new RS RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer(); waitForLabelsRegionAvailability(rs.getRegionServer()); - String[] labels = { SECRET, CONFIDENTIAL, PRIVATE, "ABC", "XYZ" }; - try { - VisibilityClient.addLabels(conf, labels); - } catch (Throwable t) { - throw new IOException(t); - } + PrivilegedExceptionAction action = + new PrivilegedExceptionAction() { + public VisibilityLabelsResponse run() throws Exception { + String[] labels = { SECRET, CONFIDENTIAL, PRIVATE, "ABC", "XYZ" }; + try { + VisibilityClient.addLabels(conf, labels); + } catch (Throwable t) { + throw new IOException(t); + } + return null; + } + }; + SUPERUSER.runAs(action); // Scan the visibility label Scan s = new Scan(); s.setAuthorizations(new Authorizations(VisibilityUtils.SYSTEM_LABEL)); @@ -437,24 +444,45 @@ public class TestVisibilityLabels { @Test public void testAddLabels() throws Throwable { - String[] labels = { "L1", SECRET, "L2", "invalid~", "L3" }; - VisibilityLabelsResponse response = VisibilityClient.addLabels(conf, labels); - List resultList = response.getResultList(); - assertEquals(5, resultList.size()); - assertTrue(resultList.get(0).getException().getValue().isEmpty()); - assertEquals("org.apache.hadoop.hbase.security.visibility.LabelAlreadyExistsException", - resultList.get(1).getException().getName()); - assertTrue(resultList.get(2).getException().getValue().isEmpty()); - assertEquals("org.apache.hadoop.hbase.security.visibility.InvalidLabelException", resultList - .get(3).getException().getName()); - assertTrue(resultList.get(4).getException().getValue().isEmpty()); + PrivilegedExceptionAction action = + new PrivilegedExceptionAction() { + public VisibilityLabelsResponse run() throws Exception { + String[] labels = { "L1", SECRET, "L2", "invalid~", "L3" }; + VisibilityLabelsResponse response = null; + try { + response = VisibilityClient.addLabels(conf, labels); + } catch (Throwable e) { + fail("Should not have thrown exception"); + } + List resultList = response.getResultList(); + assertEquals(5, resultList.size()); + assertTrue(resultList.get(0).getException().getValue().isEmpty()); + assertEquals("org.apache.hadoop.hbase.security.visibility.LabelAlreadyExistsException", + resultList.get(1).getException().getName()); + assertTrue(resultList.get(2).getException().getValue().isEmpty()); + assertEquals("org.apache.hadoop.hbase.security.visibility.InvalidLabelException", + resultList.get(3).getException().getName()); + assertTrue(resultList.get(4).getException().getValue().isEmpty()); + return null; + } + }; + SUPERUSER.runAs(action); } @Test public void testSetAndGetUserAuths() throws Throwable { - String[] auths = { SECRET, CONFIDENTIAL }; - String user = "user1"; - VisibilityClient.setAuths(conf, auths, user); + final String user = "user1"; + PrivilegedExceptionAction action = new PrivilegedExceptionAction() { + public Void run() throws Exception { + String[] auths = { SECRET, CONFIDENTIAL }; + try { + VisibilityClient.setAuths(conf, auths, user); + } catch (Throwable e) { + } + return null; + } + }; + SUPERUSER.runAs(action); HTable ht = null; try { ht = new HTable(conf, LABELS_TABLE_NAME); @@ -477,73 +505,117 @@ public class TestVisibilityLabels { ht.close(); } } - GetAuthsResponse authsResponse = VisibilityClient.getAuths(conf, user); - List authsList = new ArrayList(); - for (ByteString authBS : authsResponse.getAuthList()) { - authsList.add(Bytes.toString(authBS.toByteArray())); - } - assertEquals(2, authsList.size()); - assertTrue(authsList.contains(SECRET)); - assertTrue(authsList.contains(CONFIDENTIAL)); - + + action = new PrivilegedExceptionAction() { + public Void run() throws Exception { + GetAuthsResponse authsResponse = null; + try { + authsResponse = VisibilityClient.getAuths(conf, user); + } catch (Throwable e) { + fail("Should not have failed"); + } + List authsList = new ArrayList(); + for (ByteString authBS : authsResponse.getAuthList()) { + authsList.add(Bytes.toString(authBS.toByteArray())); + } + assertEquals(2, authsList.size()); + assertTrue(authsList.contains(SECRET)); + assertTrue(authsList.contains(CONFIDENTIAL)); + return null; + } + }; + SUPERUSER.runAs(action); + // Try doing setAuths once again and there should not be any duplicates - String[] auths1 = { SECRET, CONFIDENTIAL }; - user = "user1"; - VisibilityClient.setAuths(conf, auths1, user); - - authsResponse = VisibilityClient.getAuths(conf, user); - authsList = new ArrayList(); - for (ByteString authBS : authsResponse.getAuthList()) { - authsList.add(Bytes.toString(authBS.toByteArray())); - } - assertEquals(2, authsList.size()); - assertTrue(authsList.contains(SECRET)); - assertTrue(authsList.contains(CONFIDENTIAL)); + action = new PrivilegedExceptionAction() { + public Void run() throws Exception { + String[] auths1 = { SECRET, CONFIDENTIAL }; + GetAuthsResponse authsResponse = null; + try { + VisibilityClient.setAuths(conf, auths1, user); + try { + authsResponse = VisibilityClient.getAuths(conf, user); + } catch (Throwable e) { + fail("Should not have failed"); + } + } catch (Throwable e) { + } + List authsList = new ArrayList(); + for (ByteString authBS : authsResponse.getAuthList()) { + authsList.add(Bytes.toString(authBS.toByteArray())); + } + assertEquals(2, authsList.size()); + assertTrue(authsList.contains(SECRET)); + assertTrue(authsList.contains(CONFIDENTIAL)); + return null; + } + }; + SUPERUSER.runAs(action); } @Test public void testClearUserAuths() throws Throwable { - String[] auths = { SECRET, CONFIDENTIAL, PRIVATE }; - String user = "testUser"; - VisibilityClient.setAuths(conf, auths, user); - // Removing the auths for SECRET and CONFIDENTIAL for the user. - // Passing a non existing auth also. - auths = new String[] { SECRET, PUBLIC, CONFIDENTIAL }; - VisibilityLabelsResponse response = VisibilityClient.clearAuths(conf, auths, user); - List resultList = response.getResultList(); - assertEquals(3, resultList.size()); - assertTrue(resultList.get(0).getException().getValue().isEmpty()); - assertEquals("org.apache.hadoop.hbase.security.visibility.InvalidLabelException", - resultList.get(1).getException().getName()); - assertTrue(resultList.get(2).getException().getValue().isEmpty()); - HTable ht = null; - try { - ht = new HTable(conf, LABELS_TABLE_NAME); - ResultScanner scanner = ht.getScanner(new Scan()); - Result result = null; - while ((result = scanner.next()) != null) { - Cell label = result.getColumnLatestCell(LABELS_TABLE_FAMILY, LABEL_QUALIFIER); - Cell userAuth = result.getColumnLatestCell(LABELS_TABLE_FAMILY, user.getBytes()); - if (Bytes.equals(PRIVATE.getBytes(), 0, PRIVATE.getBytes().length, label.getValueArray(), - label.getValueOffset(), label.getValueLength())) { - assertNotNull(userAuth); - } else { - assertNull(userAuth); + PrivilegedExceptionAction action = new PrivilegedExceptionAction() { + public Void run() throws Exception { + String[] auths = { SECRET, CONFIDENTIAL, PRIVATE }; + String user = "testUser"; + try { + VisibilityClient.setAuths(conf, auths, user); + } catch (Throwable e) { + fail("Should not have failed"); + } + // Removing the auths for SECRET and CONFIDENTIAL for the user. + // Passing a non existing auth also. + auths = new String[] { SECRET, PUBLIC, CONFIDENTIAL }; + VisibilityLabelsResponse response = null; + try { + response = VisibilityClient.clearAuths(conf, auths, user); + } catch (Throwable e) { + fail("Should not have failed"); + } + List resultList = response.getResultList(); + assertEquals(3, resultList.size()); + assertTrue(resultList.get(0).getException().getValue().isEmpty()); + assertEquals("org.apache.hadoop.hbase.security.visibility.InvalidLabelException", + resultList.get(1).getException().getName()); + assertTrue(resultList.get(2).getException().getValue().isEmpty()); + HTable ht = null; + try { + ht = new HTable(conf, LABELS_TABLE_NAME); + ResultScanner scanner = ht.getScanner(new Scan()); + Result result = null; + while ((result = scanner.next()) != null) { + Cell label = result.getColumnLatestCell(LABELS_TABLE_FAMILY, LABEL_QUALIFIER); + Cell userAuth = result.getColumnLatestCell(LABELS_TABLE_FAMILY, user.getBytes()); + if (Bytes.equals(PRIVATE.getBytes(), 0, PRIVATE.getBytes().length, + label.getValueArray(), label.getValueOffset(), label.getValueLength())) { + assertNotNull(userAuth); + } else { + assertNull(userAuth); + } + } + } finally { + if (ht != null) { + ht.close(); + } } - } - } finally { - if (ht != null) { - ht.close(); - } - } - GetAuthsResponse authsResponse = VisibilityClient.getAuths(conf, user); - List authsList = new ArrayList(); - for (ByteString authBS : authsResponse.getAuthList()) { - authsList.add(Bytes.toString(authBS.toByteArray())); - } - assertEquals(1, authsList.size()); - assertTrue(authsList.contains(PRIVATE)); + GetAuthsResponse authsResponse = null; + try { + authsResponse = VisibilityClient.getAuths(conf, user); + } catch (Throwable e) { + fail("Should not have failed"); + } + List authsList = new ArrayList(); + for (ByteString authBS : authsResponse.getAuthList()) { + authsList.add(Bytes.toString(authBS.toByteArray())); + } + assertEquals(1, authsList.size()); + assertTrue(authsList.contains(PRIVATE)); + return null; + } + }; + SUPERUSER.runAs(action); } @Test diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java index 24c5210b904..ee3d5f1a492 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java @@ -48,7 +48,6 @@ import org.apache.hadoop.hbase.security.access.AccessController; import org.apache.hadoop.hbase.security.access.Permission; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.util.Bytes; - import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; @@ -75,7 +74,8 @@ public class TestVisibilityLabelsWithACL { @Rule public final TestName TEST_NAME = new TestName(); private static User SUPERUSER; - private static User NORMAL_USER; + private static User NORMAL_USER1; + private static User NORMAL_USER2; @BeforeClass public static void setupBeforeClass() throws Exception { @@ -95,7 +95,8 @@ public class TestVisibilityLabelsWithACL { // Create users for testing SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); - NORMAL_USER = User.createUserForTesting(conf, "user1", new String[] {}); + NORMAL_USER1 = User.createUserForTesting(conf, "user1", new String[] {}); + NORMAL_USER2 = User.createUserForTesting(conf, "user2", new String[] {}); // Grant NORMAL_USER EXEC privilege on the labels table. For the purposes of this // test, we want to insure that access is denied even with the ability to access // the endpoint. @@ -104,8 +105,10 @@ public class TestVisibilityLabelsWithACL { BlockingRpcChannel service = acl.coprocessorService(LABELS_TABLE_NAME.getName()); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); - ProtobufUtil.grant(protocol, NORMAL_USER.getShortName(), LABELS_TABLE_NAME, null, null, + ProtobufUtil.grant(protocol, NORMAL_USER1.getShortName(), LABELS_TABLE_NAME, null, null, Permission.Action.EXEC); + ProtobufUtil.grant(protocol, NORMAL_USER2.getShortName(), LABELS_TABLE_NAME, null, null, + Permission.Action.EXEC); } finally { acl.close(); } @@ -119,11 +122,21 @@ public class TestVisibilityLabelsWithACL { @Test public void testScanForUserWithFewerLabelAuthsThanLabelsInScanAuthorizations() throws Throwable { String[] auths = { SECRET }; - String user = "admin"; + String user = "user2"; VisibilityClient.setAuths(conf, auths, user); TableName tableName = TableName.valueOf(TEST_NAME.getMethodName()); final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL + "&!" + PRIVATE, SECRET + "&!" + PRIVATE); + HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME); + try { + BlockingRpcChannel service = acl.coprocessorService(tableName.getName()); + AccessControlService.BlockingInterface protocol = AccessControlService + .newBlockingStub(service); + ProtobufUtil.grant(protocol, NORMAL_USER2.getShortName(), tableName, null, null, + Permission.Action.READ); + } finally { + acl.close(); + } PrivilegedExceptionAction scanAction = new PrivilegedExceptionAction() { public Void run() throws Exception { Scan s = new Scan(); @@ -142,6 +155,57 @@ public class TestVisibilityLabelsWithACL { return null; } }; + NORMAL_USER2.runAs(scanAction); + } + + @Test + public void testScanForSuperUserWithFewerLabelAuths() throws Throwable { + String[] auths = { SECRET }; + String user = "admin"; + VisibilityClient.setAuths(conf, auths, user); + TableName tableName = TableName.valueOf(TEST_NAME.getMethodName()); + final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL + + "&!" + PRIVATE, SECRET + "&!" + PRIVATE); + PrivilegedExceptionAction scanAction = new PrivilegedExceptionAction() { + public Void run() throws Exception { + Scan s = new Scan(); + s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL)); + HTable t = new HTable(conf, table.getTableName()); + try { + ResultScanner scanner = t.getScanner(s); + Result[] result = scanner.next(5); + assertTrue(result.length == 2); + } finally { + t.close(); + } + return null; + } + }; + SUPERUSER.runAs(scanAction); + } + + @Test + public void testGetForSuperUserWithFewerLabelAuths() throws Throwable { + String[] auths = { SECRET }; + String user = "admin"; + VisibilityClient.setAuths(conf, auths, user); + TableName tableName = TableName.valueOf(TEST_NAME.getMethodName()); + final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL + + "&!" + PRIVATE, SECRET + "&!" + PRIVATE); + PrivilegedExceptionAction scanAction = new PrivilegedExceptionAction() { + public Void run() throws Exception { + Get g = new Get(row1); + g.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL)); + HTable t = new HTable(conf, table.getTableName()); + try { + Result result = t.get(g); + assertTrue(!result.isEmpty()); + } finally { + t.close(); + } + return null; + } + }; SUPERUSER.runAs(scanAction); } @@ -153,7 +217,20 @@ public class TestVisibilityLabelsWithACL { VisibilityClient.setAuths(conf, auths, "user1"); TableName tableName = TableName.valueOf(TEST_NAME.getMethodName()); final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET); - PrivilegedExceptionAction getAction = new PrivilegedExceptionAction() { + HTable acl = new HTable(conf, AccessControlLists.ACL_TABLE_NAME); + try { + BlockingRpcChannel service = acl.coprocessorService(tableName.getName()); + AccessControlService.BlockingInterface protocol = AccessControlService + .newBlockingStub(service); + ProtobufUtil.grant(protocol, NORMAL_USER1.getShortName(), tableName, null, null, + Permission.Action.READ); + ProtobufUtil.grant(protocol, NORMAL_USER2.getShortName(), tableName, null, null, + Permission.Action.READ); + } finally { + acl.close(); + } + + PrivilegedExceptionAction getAction = new PrivilegedExceptionAction() { public Void run() throws Exception { Get g = new Get(row1); g.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL)); @@ -167,7 +244,7 @@ public class TestVisibilityLabelsWithACL { return null; } }; - SUPERUSER.runAs(getAction); + NORMAL_USER2.runAs(getAction); } @Test @@ -182,7 +259,7 @@ public class TestVisibilityLabelsWithACL { return null; } }; - VisibilityLabelsResponse response = NORMAL_USER.runAs(action); + VisibilityLabelsResponse response = NORMAL_USER1.runAs(action); assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response .getResult(0).getException().getName()); assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response @@ -197,7 +274,7 @@ public class TestVisibilityLabelsWithACL { return null; } }; - response = NORMAL_USER.runAs(action); + response = NORMAL_USER1.runAs(action); assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response .getResult(0).getException().getName()); assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response @@ -225,7 +302,7 @@ public class TestVisibilityLabelsWithACL { return null; } }; - response = NORMAL_USER.runAs(action); + response = NORMAL_USER1.runAs(action); assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(0) .getException().getName()); assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(1) @@ -235,18 +312,18 @@ public class TestVisibilityLabelsWithACL { assertTrue(response.getResult(0).getException().getValue().isEmpty()); assertTrue(response.getResult(1).getException().getValue().isEmpty()); - VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user2"); + VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user3"); PrivilegedExceptionAction action1 = new PrivilegedExceptionAction() { public GetAuthsResponse run() throws Exception { try { - return VisibilityClient.getAuths(conf, "user2"); + return VisibilityClient.getAuths(conf, "user3"); } catch (Throwable e) { } return null; } }; - GetAuthsResponse authsResponse = NORMAL_USER.runAs(action1); + GetAuthsResponse authsResponse = NORMAL_USER1.runAs(action1); assertNull(authsResponse); authsResponse = SUPERUSER.runAs(action1); List authsList = new ArrayList();