diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java index ffd642613a6..59698427e4b 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java @@ -1390,7 +1390,7 @@ boolean canSkipAccessCheck(User user, final String operation, String access, fin LOG.warn("canSkipAccessCheck: exiting{}", "Unexpeceted: User is null: access denied, not audited!"); throw new AccessDeniedException("No user associated with request (" + operation + ") for action: " + access + "on table:" + table); - } else if (isAccessForMetadataRead(access, table)) { + } else if (isAccessForMetadataRead(access, table, user)) { LOG.debug("canSkipAccessCheck: true: metadata read access always allowed, not audited"); result = true; @@ -1434,8 +1434,25 @@ boolean canSkipAccessCheck(User user, final String operation, String access, fin /* ---- EndpointObserver implementation ---- */ - boolean isAccessForMetadataRead(String access, String table) { + boolean isAccessForMetadataRead(String access, String table, User user) { if (authUtils.isReadAccess(access) && isSpecialTable(table)) { + if (StringUtils.equals(table, "hbase:acl")) { + boolean isSystemOrSuperUser = false; + try { + User currentUser = User.getCurrent(); + if (currentUser != null && user != null) { + isSystemOrSuperUser = Objects.equals(currentUser.getShortName(), user.getShortName()); + } + } catch (IOException e) { + LOG.warn("Unable to obtain the current user", e); + } + if (!isSystemOrSuperUser && user != null) { + isSystemOrSuperUser = userUtils.isSuperUser(user); + } + if (!isSystemOrSuperUser) { + return false; + } + } LOG.debug("isAccessForMetadataRead: Metadata tables read: access allowed!"); return true; diff --git a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessorTest.java b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessorTest.java index 340ac184927..1ce4773484f 100644 --- a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessorTest.java +++ b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessorTest.java @@ -391,12 +391,27 @@ public void test18_requirePermission_region_allowsOrDenies() throws Exception { } @Test - public void test19_isSpecialTable_and_metadataRead() { + public void test19_isSpecialTable_and_metadataRead() throws Exception { RangerAuthorizationCoprocessor cp = new RangerAuthorizationCoprocessor(); Assertions.assertTrue(cp.isSpecialTable("hbase:meta")); Assertions.assertFalse(cp.isSpecialTable("normal")); - Assertions.assertTrue(cp.isAccessForMetadataRead("read", "hbase:acl")); - Assertions.assertFalse(cp.isAccessForMetadataRead("write", "hbase:acl")); + Assertions.assertFalse(cp.isAccessForMetadataRead("read", "hbase:acl", null)); + Assertions.assertFalse(cp.isAccessForMetadataRead("write", "hbase:acl", null)); + + // Test for system user bypass on hbase:acl + User systemUser = mock(User.class); + when(systemUser.getShortName()).thenReturn(User.getCurrent().getShortName()); + Assertions.assertTrue(cp.isAccessForMetadataRead("read", "hbase:acl", systemUser)); + + // Test for super user bypass on hbase:acl + User superUser = mock(User.class); + when(superUser.getShortName()).thenReturn("some_super_user"); + HbaseUserUtils userUtils = mock(HbaseUserUtils.class); + lenient().when(userUtils.isSuperUser(superUser)).thenReturn(true); + Field userUtilsField = RangerAuthorizationCoprocessor.class.getDeclaredField("userUtils"); + userUtilsField.setAccessible(true); + userUtilsField.set(cp, userUtils); + Assertions.assertTrue(cp.isAccessForMetadataRead("read", "hbase:acl", superUser)); } @Test