/** * Returns a new {@code PermissionCache} initialized with permission assignments * from the {@code hbase.superuser} configuration key. */ private PermissionCache<Permission> initGlobal(Configuration conf) throws IOException { UserProvider userProvider = UserProvider.instantiate(conf); User user = userProvider.getCurrent(); if (user == null) { throw new IOException("Unable to obtain the current user, " + "authorization checks for internal operations will not work correctly!"); } PermissionCache<Permission> newCache = new PermissionCache<Permission>(); String currentUser = user.getShortName(); // the system user is always included List<String> superusers = Lists.asList(currentUser, conf.getStrings( Superusers.SUPERUSER_CONF_KEY, new String[0])); if (superusers != null) { for (String name : superusers) { if (AuthUtil.isGroupPrincipal(name)) { newCache.putGroup(AuthUtil.getGroupName(name), new Permission(Permission.Action.values())); } else { newCache.putUser(name, new Permission(Permission.Action.values())); } } } return newCache; }
/** * Updates the internal global permissions cache * * @param userPerms */ private void updateGlobalCache(ListMultimap<String,TablePermission> userPerms) { PermissionCache<Permission> newCache = null; try { newCache = initGlobal(conf); for (Map.Entry<String,TablePermission> entry : userPerms.entries()) { if (AuthUtil.isGroupPrincipal(entry.getKey())) { newCache.putGroup(AuthUtil.getGroupName(entry.getKey()), new Permission(entry.getValue().getActions())); } else { newCache.putUser(entry.getKey(), new Permission(entry.getValue().getActions())); } } globalCache = newCache; mtime.incrementAndGet(); } catch (IOException e) { // Never happens LOG.error("Error occured while updating the global cache", e); } }
/** * Updates the internal permissions cache for a single table, splitting * the permissions listed into separate caches for users and groups to optimize * group lookups. * * @param table * @param tablePerms */ private void updateTableCache(TableName table, ListMultimap<String,TablePermission> tablePerms) { PermissionCache<TablePermission> newTablePerms = new PermissionCache<TablePermission>(); for (Map.Entry<String,TablePermission> entry : tablePerms.entries()) { if (AuthUtil.isGroupPrincipal(entry.getKey())) { newTablePerms.putGroup(AuthUtil.getGroupName(entry.getKey()), entry.getValue()); } else { newTablePerms.putUser(entry.getKey(), entry.getValue()); } } tableCache.put(table, newTablePerms); mtime.incrementAndGet(); }
/** * Updates the internal permissions cache for a single table, splitting * the permissions listed into separate caches for users and groups to optimize * group lookups. * * @param namespace * @param tablePerms */ private void updateNsCache(String namespace, ListMultimap<String, TablePermission> tablePerms) { PermissionCache<TablePermission> newTablePerms = new PermissionCache<TablePermission>(); for (Map.Entry<String, TablePermission> entry : tablePerms.entries()) { if (AuthUtil.isGroupPrincipal(entry.getKey())) { newTablePerms.putGroup(AuthUtil.getGroupName(entry.getKey()), entry.getValue()); } else { newTablePerms.putUser(entry.getKey(), entry.getValue()); } } nsCache.put(namespace, newTablePerms); mtime.incrementAndGet(); }
public static void main(String[] args) throws Exception { final Configuration conf = HBaseConfiguration.create(); final ChoreService choreService = new ChoreService("CANARY_TOOL"); final ScheduledChore authChore = AuthUtil.getAuthChore(conf); if (authChore != null) { choreService.scheduleChore(authChore); } // loading the generic options to conf new GenericOptionsParser(conf, args); int numThreads = conf.getInt("hbase.canary.threads.num", MAX_THREADS_NUM); LOG.info("Number of exection threads " + numThreads); ExecutorService executor = new ScheduledThreadPoolExecutor(numThreads); Class<? extends Sink> sinkClass = conf.getClass("hbase.canary.sink.class", RegionServerStdOutSink.class, Sink.class); Sink sink = ReflectionUtils.newInstance(sinkClass); int exitCode = ToolRunner.run(conf, new Canary(executor, sink), args); choreService.shutdown(); executor.shutdown(); System.exit(exitCode); }
private boolean checkACLForSuperUsers(String[] superUsers, List<ACL> acls) { for (String user : superUsers) { boolean hasAccess = false; // TODO: Validate super group members also when ZK supports setting node ACL for groups. if (!user.startsWith(AuthUtil.GROUP_PREFIX)) { for (ACL acl : acls) { if (user.equals(acl.getId().getId())) { if (acl.getPerms() == Perms.ALL) { hasAccess = true; } else { if (LOG.isDebugEnabled()) { LOG.debug(String.format( "superuser '%s' does not have correct permissions: have 0x%x, want 0x%x", acl.getId().getId(), acl.getPerms(), Perms.ALL)); } } break; } } if (!hasAccess) { return false; } } } return true; }
/** * Should be called only once to pre-load list of super users and super * groups from Configuration. This operation is idempotent. * @param conf configuration to load users from * @throws IOException if unable to initialize lists of superusers or super groups * @throws IllegalStateException if current user is null */ public static void initialize(Configuration conf) throws IOException { superUsers = new ArrayList<>(); superGroups = new ArrayList<>(); User user = User.getCurrent(); if (user == null) { throw new IllegalStateException("Unable to obtain the current user, " + "authorization checks for internal operations will not work correctly!"); } if (LOG.isTraceEnabled()) { LOG.trace("Current user name is " + user.getShortName()); } String currentUser = user.getShortName(); String[] superUserList = conf.getStrings(SUPERUSER_CONF_KEY, new String[0]); for (String name : superUserList) { if (AuthUtil.isGroupPrincipal(name)) { superGroups.add(AuthUtil.getGroupName(name)); } else { superUsers.add(name); } } superUsers.add(currentUser); }
/** * Returns a new {@code PermissionCache} initialized with permission assignments * from the {@code hbase.superuser} configuration key. */ private PermissionCache<Permission> initGlobal(Configuration conf) throws IOException { UserProvider userProvider = UserProvider.instantiate(conf); User user = userProvider.getCurrent(); if (user == null) { throw new IOException("Unable to obtain the current user, " + "authorization checks for internal operations will not work correctly!"); } PermissionCache<Permission> newCache = new PermissionCache<>(); String currentUser = user.getShortName(); // the system user is always included List<String> superusers = Lists.asList(currentUser, conf.getStrings( Superusers.SUPERUSER_CONF_KEY, new String[0])); if (superusers != null) { for (String name : superusers) { if (AuthUtil.isGroupPrincipal(name)) { newCache.putGroup(AuthUtil.getGroupName(name), new Permission(Permission.Action.values())); } else { newCache.putUser(name, new Permission(Permission.Action.values())); } } } return newCache; }
/** * Updates the internal global permissions cache * * @param userPerms */ private void updateGlobalCache(ListMultimap<String,TablePermission> userPerms) { PermissionCache<Permission> newCache = null; try { newCache = initGlobal(conf); for (Map.Entry<String,TablePermission> entry : userPerms.entries()) { if (AuthUtil.isGroupPrincipal(entry.getKey())) { newCache.putGroup(AuthUtil.getGroupName(entry.getKey()), new Permission(entry.getValue().getActions())); } else { newCache.putUser(entry.getKey(), new Permission(entry.getValue().getActions())); } } globalCache = newCache; mtime.incrementAndGet(); } catch (IOException e) { // Never happens LOG.error("Error occurred while updating the global cache", e); } }
/** * Updates the internal permissions cache for a single table, splitting * the permissions listed into separate caches for users and groups to optimize * group lookups. * * @param table * @param tablePerms */ private void updateTableCache(TableName table, ListMultimap<String,TablePermission> tablePerms) { PermissionCache<TablePermission> newTablePerms = new PermissionCache<>(); for (Map.Entry<String,TablePermission> entry : tablePerms.entries()) { if (AuthUtil.isGroupPrincipal(entry.getKey())) { newTablePerms.putGroup(AuthUtil.getGroupName(entry.getKey()), entry.getValue()); } else { newTablePerms.putUser(entry.getKey(), entry.getValue()); } } tableCache.put(table, newTablePerms); mtime.incrementAndGet(); }
/** * Updates the internal permissions cache for a single table, splitting * the permissions listed into separate caches for users and groups to optimize * group lookups. * * @param namespace * @param tablePerms */ private void updateNsCache(String namespace, ListMultimap<String, TablePermission> tablePerms) { PermissionCache<TablePermission> newTablePerms = new PermissionCache<>(); for (Map.Entry<String, TablePermission> entry : tablePerms.entries()) { if (AuthUtil.isGroupPrincipal(entry.getKey())) { newTablePerms.putGroup(AuthUtil.getGroupName(entry.getKey()), entry.getValue()); } else { newTablePerms.putUser(entry.getKey(), entry.getValue()); } } nsCache.put(namespace, newTablePerms); mtime.incrementAndGet(); }
private boolean checkACLForSuperUsers(String[] superUsers, List<ACL> acls) { for (String user : superUsers) { boolean hasAccess = false; // TODO: Validate super group members also when ZK supports setting node ACL for groups. if (!AuthUtil.isGroupPrincipal(user)) { for (ACL acl : acls) { if (user.equals(acl.getId().getId())) { if (acl.getPerms() == Perms.ALL) { hasAccess = true; } else { if (LOG.isDebugEnabled()) { LOG.debug(String.format( "superuser '%s' does not have correct permissions: have 0x%x, want 0x%x", acl.getId().getId(), acl.getPerms(), Perms.ALL)); } } break; } } if (!hasAccess) { return false; } } } return true; }
/** * Should be called only once to pre-load list of super users and super * groups from Configuration. This operation is idempotent. * @param conf configuration to load users from * @throws IOException if unable to initialize lists of superusers or super groups * @throws IllegalStateException if current user is null */ public static void initialize(Configuration conf) throws IOException { superUsers = new HashSet<>(); superGroups = new HashSet<>(); systemUser = User.getCurrent(); if (systemUser == null) { throw new IllegalStateException("Unable to obtain the current user, " + "authorization checks for internal operations will not work correctly!"); } String currentUser = systemUser.getShortName(); LOG.trace("Current user name is {}", currentUser); superUsers.add(currentUser); String[] superUserList = conf.getStrings(SUPERUSER_CONF_KEY, new String[0]); for (String name : superUserList) { if (AuthUtil.isGroupPrincipal(name)) { superGroups.add(AuthUtil.getGroupName(name)); } else { superUsers.add(name); } } }
@Override public List<String> getGroupAuths(String[] groups, boolean systemCall) throws IOException { assert (labelsRegion != null || systemCall); if (systemCall || labelsRegion == null) { return this.labelsCache.getGroupAuths(groups); } Scan s = new Scan(); if (groups != null && groups.length > 0) { for (String group : groups) { s.addColumn(LABELS_TABLE_FAMILY, Bytes.toBytes(AuthUtil.toGroupEntry(group))); } } Filter filter = VisibilityUtils.createVisibilityLabelFilter(this.labelsRegion, new Authorizations(SYSTEM_LABEL)); s.setFilter(filter); Set<String> auths = new HashSet<String>(); RegionScanner scanner = this.labelsRegion.getScanner(s); try { List<Cell> results = new ArrayList<Cell>(1); while (true) { scanner.next(results); if (results.isEmpty()) break; Cell cell = results.get(0); int ordinal = Bytes.toInt(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); String label = this.labelsCache.getLabel(ordinal); if (label != null) { auths.add(label); } results.clear(); } } finally { scanner.close(); } return new ArrayList<String>(auths); }
public static List<Permission> getCellPermissionsForUser(User user, Cell cell) throws IOException { // Save an object allocation where we can if (cell.getTagsLength() == 0) { return null; } List<Permission> results = Lists.newArrayList(); Iterator<Tag> tagsIterator = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength()); while (tagsIterator.hasNext()) { Tag tag = tagsIterator.next(); if (tag.getType() == ACL_TAG_TYPE) { // Deserialize the table permissions from the KV // TODO: This can be improved. Don't build UsersAndPermissions just to unpack it again, // use the builder AccessControlProtos.UsersAndPermissions.Builder builder = AccessControlProtos.UsersAndPermissions.newBuilder(); ProtobufUtil.mergeFrom(builder, tag.getBuffer(), tag.getTagOffset(), tag.getTagLength()); ListMultimap<String,Permission> kvPerms = ProtobufUtil.toUsersAndPermissions(builder.build()); // Are there permissions for this user? List<Permission> userPerms = kvPerms.get(user.getShortName()); if (userPerms != null) { results.addAll(userPerms); } // Are there permissions for any of the groups this user belongs to? String groupNames[] = user.getGroupNames(); if (groupNames != null) { for (String group : groupNames) { List<Permission> groupPerms = kvPerms.get(AuthUtil.toGroupEntry(group)); if (results != null) { results.addAll(groupPerms); } } } } } return results; }
/** * Returns a combined map of user and group permissions, with group names prefixed by * {@link AuthUtil#GROUP_PREFIX}. */ public ListMultimap<String,T> getAllPermissions() { ListMultimap<String,T> tmp = ArrayListMultimap.create(); tmp.putAll(userCache); for (String group : groupCache.keySet()) { tmp.putAll(AuthUtil.toGroupEntry(group), groupCache.get(group)); } return tmp; }
@BeforeClass public static void setupBeforeClass() throws Exception { // setup configuration conf = TEST_UTIL.getConfiguration(); conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10); // Enable security enableSecurity(conf); // Verify enableSecurity sets up what we require verifyConfiguration(conf); // We expect 0.98 cell ACL semantics conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false); TEST_UTIL.startMiniCluster(); MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster() .getMasterCoprocessorHost(); cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf); AccessController ac = (AccessController) cpHost.findCoprocessor(AccessController.class.getName()); cpHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0) .getRegionServerCoprocessorHost(); rsHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); // create a set of test users USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); USER_OTHER = User.createUserForTesting(conf, "other", new String[0]); GROUP_USER = User.createUserForTesting(conf, "group_user", new String[] { GROUP }); usersAndGroups = new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP) }; }
@BeforeClass public static void setupBeforeClass() throws Exception { // setup configuration conf = TEST_UTIL.getConfiguration(); // Enable security enableSecurity(conf); // Verify enableSecurity sets up what we require verifyConfiguration(conf); // We expect 0.98 cell ACL semantics conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false); TEST_UTIL.startMiniCluster(); MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster() .getMasterCoprocessorHost(); cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf); AccessController ac = (AccessController) cpHost.findCoprocessor(AccessController.class.getName()); cpHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0) .getRegionServerCoprocessorHost(); rsHost.createEnvironment(AccessController.class, ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); // create a set of test users USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); USER_OTHER = User.createUserForTesting(conf, "other", new String[0]); USER_OTHER2 = User.createUserForTesting(conf, "other2", new String[0]); GROUP_USER = User.createUserForTesting(conf, "group_user", new String[] { GROUP }); usersAndGroups = new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP) }; }
public static boolean isSuperUserId(String[] superUsers, Id id) { for (String user : superUsers) { // TODO: Validate super group members also when ZK supports setting node ACL for groups. if (!user.startsWith(AuthUtil.GROUP_PREFIX) && new Id("sasl", user).equals(id)) { return true; } } return false; }
public static ArrayList<ACL> createACL(ZooKeeperWatcher zkw, String node, boolean isSecureZooKeeper) { if (!node.startsWith(zkw.baseZNode)) { return Ids.OPEN_ACL_UNSAFE; } if (isSecureZooKeeper) { ArrayList<ACL> acls = new ArrayList<ACL>(); // add permission to hbase supper user String[] superUsers = zkw.getConfiguration().getStrings(Superusers.SUPERUSER_CONF_KEY); if (superUsers != null) { List<String> groups = new ArrayList<String>(); for (String user : superUsers) { if (user.startsWith(AuthUtil.GROUP_PREFIX)) { // TODO: Set node ACL for groups when ZK supports this feature groups.add(user); } else { acls.add(new ACL(Perms.ALL, new Id("auth", user))); } } if (!groups.isEmpty()) { LOG.warn("Znode ACL setting for group " + groups + " is skipped, Zookeeper doesn't support this feature presently."); } } // Certain znodes are accessed directly by the client, // so they must be readable by non-authenticated clients if (zkw.isClientReadable(node)) { acls.addAll(Ids.CREATOR_ALL_ACL); acls.addAll(Ids.READ_ACL_UNSAFE); } else { acls.addAll(Ids.CREATOR_ALL_ACL); } return acls; } else { return Ids.OPEN_ACL_UNSAFE; } }
@Override public List<String> getGroupAuths(String[] groups, boolean systemCall) throws IOException { assert (labelsRegion != null || systemCall); if (systemCall || labelsRegion == null) { return this.labelsCache.getGroupAuths(groups); } Scan s = new Scan(); if (groups != null && groups.length > 0) { for (String group : groups) { s.addColumn(LABELS_TABLE_FAMILY, Bytes.toBytes(AuthUtil.toGroupEntry(group))); } } Filter filter = VisibilityUtils.createVisibilityLabelFilter(this.labelsRegion, new Authorizations(SYSTEM_LABEL)); s.setFilter(filter); Set<String> auths = new HashSet<>(); RegionScanner scanner = this.labelsRegion.getScanner(s); try { List<Cell> results = new ArrayList<>(1); while (true) { scanner.next(results); if (results.isEmpty()) break; Cell cell = results.get(0); int ordinal = PrivateCellUtil.getRowAsInt(cell); String label = this.labelsCache.getLabel(ordinal); if (label != null) { auths.add(label); } results.clear(); } } finally { scanner.close(); } return new ArrayList<>(auths); }
/** * Returns a combined map of user and group permissions, with group names * distinguished according to {@link AuthUtil#isGroupPrincipal(String)}. */ public ListMultimap<String,T> getAllPermissions() { ListMultimap<String,T> tmp = ArrayListMultimap.create(); tmp.putAll(userCache); for (String group : groupCache.keySet()) { tmp.putAll(AuthUtil.toGroupEntry(group), groupCache.get(group)); } return tmp; }
@Override public List<String> getGroupAuths(String[] groups, boolean systemCall) throws IOException { assert (labelsRegion != null || systemCall); List<String> auths = new ArrayList<>(); if (groups != null && groups.length > 0) { for (String group : groups) { Get get = new Get(Bytes.toBytes(AuthUtil.toGroupEntry(group))); List<Cell> cells = null; if (labelsRegion == null) { Table table = null; Connection connection = null; try { connection = ConnectionFactory.createConnection(conf); table = connection.getTable(VisibilityConstants.LABELS_TABLE_NAME); Result result = table.get(get); cells = result.listCells(); } finally { if (table != null) { table.close(); connection.close(); } } } else { cells = this.labelsRegion.get(get, false); } if (cells != null) { for (Cell cell : cells) { String auth = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); auths.add(auth); } } } } return auths; }
@BeforeClass public static void setupBeforeClass() throws Exception { // setup configuration conf = TEST_UTIL.getConfiguration(); conf.setInt(HConstants.REGION_SERVER_HIGH_PRIORITY_HANDLER_COUNT, 10); // Enable security enableSecurity(conf); // Verify enableSecurity sets up what we require verifyConfiguration(conf); // We expect 0.98 cell ACL semantics conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false); TEST_UTIL.startMiniCluster(); MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster() .getMasterCoprocessorHost(); cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf); AccessController ac = cpHost.findCoprocessor(AccessController.class); cpHost.createEnvironment(ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0) .getRegionServerCoprocessorHost(); rsHost.createEnvironment(ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); // create a set of test users USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); USER_OTHER = User.createUserForTesting(conf, "other", new String[0]); GROUP_USER = User.createUserForTesting(conf, "group_user", new String[] { GROUP }); usersAndGroups = new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP) }; }
@BeforeClass public static void setupBeforeClass() throws Exception { // setup configuration conf = TEST_UTIL.getConfiguration(); // Enable security enableSecurity(conf); // Verify enableSecurity sets up what we require verifyConfiguration(conf); // We expect 0.98 cell ACL semantics conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false); TEST_UTIL.startMiniCluster(); MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster() .getMasterCoprocessorHost(); cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf); AccessController ac = cpHost.findCoprocessor(AccessController.class); cpHost.createEnvironment(ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); RegionServerCoprocessorHost rsHost = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0) .getRegionServerCoprocessorHost(); rsHost.createEnvironment(ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); // create a set of test users USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); USER_OTHER = User.createUserForTesting(conf, "other", new String[0]); USER_OTHER2 = User.createUserForTesting(conf, "other2", new String[0]); GROUP_USER = User.createUserForTesting(conf, "group_user", new String[] { GROUP }); usersAndGroups = new String[] { USER_OTHER.getShortName(), AuthUtil.toGroupEntry(GROUP) }; }
public static boolean isSuperUserId(String[] superUsers, Id id) { for (String user : superUsers) { // TODO: Validate super group members also when ZK supports setting node ACL for groups. if (!AuthUtil.isGroupPrincipal(user) && new Id("sasl", user).equals(id)) { return true; } } return false; }
@Override public int run(String[] args) throws Exception { int index = parseArgs(args); ChoreService choreService = null; // Launches chore for refreshing kerberos credentials if security is enabled. // Please see http://hbase.apache.org/book.html#_running_canary_in_a_kerberos_enabled_cluster // for more details. final ScheduledChore authChore = AuthUtil.getAuthChore(conf); if (authChore != null) { choreService = new ChoreService("CANARY_TOOL"); choreService.scheduleChore(authChore); } // Start to prepare the stuffs Monitor monitor = null; Thread monitorThread = null; long startTime = 0; long currentTimeLength = 0; // Get a connection to use in below. // try-with-resources jdk7 construct. See // http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html try (Connection connection = ConnectionFactory.createConnection(this.conf)) { do { // Do monitor !! try { monitor = this.newMonitor(connection, index, args); monitorThread = new Thread(monitor); startTime = System.currentTimeMillis(); monitorThread.start(); while (!monitor.isDone()) { // wait for 1 sec Thread.sleep(1000); // exit if any error occurs if (this.failOnError && monitor.hasError()) { monitorThread.interrupt(); if (monitor.initialized) { return monitor.errorCode; } else { return INIT_ERROR_EXIT_CODE; } } currentTimeLength = System.currentTimeMillis() - startTime; if (currentTimeLength > this.timeout) { LOG.error("The monitor is running too long (" + currentTimeLength + ") after timeout limit:" + this.timeout + " will be killed itself !!"); if (monitor.initialized) { return TIMEOUT_ERROR_EXIT_CODE; } else { return INIT_ERROR_EXIT_CODE; } } } if (this.failOnError && monitor.finalCheckForErrors()) { monitorThread.interrupt(); return monitor.errorCode; } } finally { if (monitor != null) monitor.close(); } Thread.sleep(interval); } while (interval > 0); } // try-with-resources close if (choreService != null) { choreService.shutdown(); } return monitor.errorCode; }
/** * Insure we are not granting access in the absence of any cells found * when scanning for covered cells. */ @Test (timeout=120000) public void testCoveringCheck() throws Exception { // Grant read access to USER_OTHER grantOnTable(TEST_UTIL, USER_OTHER.getShortName(), TEST_TABLE.getTableName(), TEST_FAMILY, null, Action.READ); // Grant read access to GROUP grantOnTable(TEST_UTIL, AuthUtil.toGroupEntry(GROUP), TEST_TABLE.getTableName(), TEST_FAMILY, null, Action.READ); // A write by USER_OTHER should be denied. // This is where we could have a big problem if there is an error in the // covering check logic. verfifyUserDeniedForWrite(USER_OTHER, ZERO); // A write by GROUP_USER from group GROUP should be denied. verfifyUserDeniedForWrite(GROUP_USER, ZERO); // Add the cell verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { try (Table t = new HTable(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName())) { Put p; p = new Put(TEST_ROW).add(TEST_FAMILY, TEST_Q1, ZERO); t.put(p); } return null; } }, USER_OWNER); // A write by USER_OTHER should still be denied, just to make sure verfifyUserDeniedForWrite(USER_OTHER, ONE); // A write by GROUP_USER from group GROUP should still be denied verfifyUserDeniedForWrite(GROUP_USER, ONE); // A read by USER_OTHER should be allowed, just to make sure verifyUserAllowedForRead(USER_OTHER); // A read by GROUP_USER from group GROUP should be allowed verifyUserAllowedForRead(GROUP_USER); }
public static void main(String[] args) throws Exception { final Configuration conf = HBaseConfiguration.create(); AuthUtil.launchAuthChore(conf); int exitCode = ToolRunner.run(conf, new Canary(), args); System.exit(exitCode); }
public static List<Permission> getCellPermissionsForUser(User user, Cell cell) throws IOException { // Save an object allocation where we can if (cell.getTagsLength() == 0) { return null; } List<Permission> results = Lists.newArrayList(); Iterator<Tag> tagsIterator = PrivateCellUtil.tagsIterator(cell); while (tagsIterator.hasNext()) { Tag tag = tagsIterator.next(); if (tag.getType() == ACL_TAG_TYPE) { // Deserialize the table permissions from the KV // TODO: This can be improved. Don't build UsersAndPermissions just to unpack it again, // use the builder AccessControlProtos.UsersAndPermissions.Builder builder = AccessControlProtos.UsersAndPermissions.newBuilder(); if (tag.hasArray()) { ProtobufUtil.mergeFrom(builder, tag.getValueArray(), tag.getValueOffset(), tag.getValueLength()); } else { ProtobufUtil.mergeFrom(builder, Tag.cloneValue(tag)); } ListMultimap<String,Permission> kvPerms = AccessControlUtil.toUsersAndPermissions(builder.build()); // Are there permissions for this user? List<Permission> userPerms = kvPerms.get(user.getShortName()); if (userPerms != null) { results.addAll(userPerms); } // Are there permissions for any of the groups this user belongs to? String groupNames[] = user.getGroupNames(); if (groupNames != null) { for (String group : groupNames) { List<Permission> groupPerms = kvPerms.get(AuthUtil.toGroupEntry(group)); if (results != null) { results.addAll(groupPerms); } } } } } return results; }
@Override public int run(String[] args) throws Exception { int index = parseArgs(args); ChoreService choreService = null; // Launches chore for refreshing kerberos credentials if security is enabled. // Please see http://hbase.apache.org/book.html#_running_canary_in_a_kerberos_enabled_cluster // for more details. final ScheduledChore authChore = AuthUtil.getAuthChore(conf); if (authChore != null) { choreService = new ChoreService("CANARY_TOOL"); choreService.scheduleChore(authChore); } // Start to prepare the stuffs Monitor monitor = null; Thread monitorThread = null; long startTime = 0; long currentTimeLength = 0; // Get a connection to use in below. try (Connection connection = ConnectionFactory.createConnection(this.conf)) { do { // Do monitor !! try { monitor = this.newMonitor(connection, index, args); monitorThread = new Thread(monitor, "CanaryMonitor-" + System.currentTimeMillis()); startTime = System.currentTimeMillis(); monitorThread.start(); while (!monitor.isDone()) { // wait for 1 sec Thread.sleep(1000); // exit if any error occurs if (this.failOnError && monitor.hasError()) { monitorThread.interrupt(); if (monitor.initialized) { return monitor.errorCode; } else { return INIT_ERROR_EXIT_CODE; } } currentTimeLength = System.currentTimeMillis() - startTime; if (currentTimeLength > this.timeout) { LOG.error("The monitor is running too long (" + currentTimeLength + ") after timeout limit:" + this.timeout + " will be killed itself !!"); if (monitor.initialized) { return TIMEOUT_ERROR_EXIT_CODE; } else { return INIT_ERROR_EXIT_CODE; } } } if (this.failOnError && monitor.finalCheckForErrors()) { monitorThread.interrupt(); return monitor.errorCode; } } finally { if (monitor != null) monitor.close(); } Thread.sleep(interval); } while (interval > 0); } // try-with-resources close if (choreService != null) { choreService.shutdown(); } return monitor.errorCode; }
/** * Insure we are not granting access in the absence of any cells found * when scanning for covered cells. */ @Test (timeout=120000) public void testCoveringCheck() throws Exception { // Grant read access to USER_OTHER grantOnTable(TEST_UTIL, USER_OTHER.getShortName(), TEST_TABLE.getTableName(), TEST_FAMILY, null, Action.READ); // Grant read access to GROUP grantOnTable(TEST_UTIL, AuthUtil.toGroupEntry(GROUP), TEST_TABLE.getTableName(), TEST_FAMILY, null, Action.READ); // A write by USER_OTHER should be denied. // This is where we could have a big problem if there is an error in the // covering check logic. verifyUserDeniedForWrite(USER_OTHER, ZERO); // A write by GROUP_USER from group GROUP should be denied. verifyUserDeniedForWrite(GROUP_USER, ZERO); // Add the cell verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { try(Connection connection = ConnectionFactory.createConnection(conf); Table t = connection.getTable(TEST_TABLE.getTableName())) { Put p; p = new Put(TEST_ROW).addColumn(TEST_FAMILY, TEST_Q1, ZERO); t.put(p); } return null; } }, USER_OWNER); // A write by USER_OTHER should still be denied, just to make sure verifyUserDeniedForWrite(USER_OTHER, ONE); // A write by GROUP_USER from group GROUP should still be denied verifyUserDeniedForWrite(GROUP_USER, ONE); // A read by USER_OTHER should be allowed, just to make sure verifyUserAllowedForRead(USER_OTHER); // A read by GROUP_USER from group GROUP should be allowed verifyUserAllowedForRead(GROUP_USER); }
@Test public void testCellPermissionsForIncrementWithMultipleVersions() throws Exception { final byte[] TEST_ROW1 = Bytes.toBytes("r1"); final byte[] TEST_Q1 = Bytes.toBytes("q1"); final byte[] TEST_Q2 = Bytes.toBytes("q2"); final byte[] ZERO = Bytes.toBytes(0L); final User user1 = User.createUserForTesting(conf, "user1", new String[0]); final User user2 = User.createUserForTesting(conf, "user2", new String[0]); verifyAllowed(new AccessTestAction() { @Override public Object run() throws Exception { try (Connection connection = ConnectionFactory.createConnection(conf)) { try (Table t = connection.getTable(TEST_TABLE.getTableName())) { Map<String, Permission> permsU1andOwner = prepareCellPermissions( new String[] { user1.getShortName(), USER_OWNER.getShortName() }, Action.READ, Action.WRITE); Map<String, Permission> permsU2andGUandOwner = prepareCellPermissions( new String[] { user2.getShortName(), AuthUtil.toGroupEntry(GROUP), USER_OWNER.getShortName() }, Action.READ, Action.WRITE); Put p = new Put(TEST_ROW1); p.addColumn(TEST_FAMILY1, TEST_Q1, 123, ZERO); p.setACL(permsU1andOwner); t.put(p); p = new Put(TEST_ROW1); p.addColumn(TEST_FAMILY1, TEST_Q2, 123, ZERO); p.setACL(permsU2andGUandOwner); t.put(p); p = new Put(TEST_ROW1); p.addColumn(TEST_FAMILY1, TEST_Q1, 127, ZERO); p.setACL(permsU2andGUandOwner); t.put(p); p = new Put(TEST_ROW1); p.addColumn(TEST_FAMILY1, TEST_Q2, 127, ZERO); p.setACL(permsU1andOwner); t.put(p); } } return null; } }, USER_OWNER); // Increment considers the TimeRange set on it. user1.runAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { try (Connection connection = ConnectionFactory.createConnection(conf)) { try (Table t = connection.getTable(TEST_TABLE.getTableName())) { Increment inc = new Increment(TEST_ROW1); inc.setTimeRange(0, 123); inc.addColumn(TEST_FAMILY1, TEST_Q1, 2L); t.increment(inc); t.incrementColumnValue(TEST_ROW1, TEST_FAMILY1, TEST_Q2, 1L); } } return null; } }); verifyUserDeniedForIncrementMultipleVersions(user2, TEST_ROW1, TEST_Q2); verifyUserDeniedForIncrementMultipleVersions(GROUP_USER, TEST_ROW1, TEST_Q2); }
public static ArrayList<ACL> createACL(ZKWatcher zkw, String node, boolean isSecureZooKeeper) { if (!node.startsWith(zkw.znodePaths.baseZNode)) { return Ids.OPEN_ACL_UNSAFE; } if (isSecureZooKeeper) { ArrayList<ACL> acls = new ArrayList<>(); // add permission to hbase supper user String[] superUsers = zkw.getConfiguration().getStrings(Superusers.SUPERUSER_CONF_KEY); String hbaseUser = null; try { hbaseUser = UserGroupInformation.getCurrentUser().getShortUserName(); } catch (IOException e) { LOG.debug("Could not acquire current User.", e); } if (superUsers != null) { List<String> groups = new ArrayList<>(); for (String user : superUsers) { if (AuthUtil.isGroupPrincipal(user)) { // TODO: Set node ACL for groups when ZK supports this feature groups.add(user); } else { if(!user.equals(hbaseUser)) { acls.add(new ACL(Perms.ALL, new Id("sasl", user))); } } } if (!groups.isEmpty()) { LOG.warn("Znode ACL setting for group " + groups + " is skipped, ZooKeeper doesn't support this feature presently."); } } // Certain znodes are accessed directly by the client, // so they must be readable by non-authenticated clients if (zkw.znodePaths.isClientReadable(node)) { acls.addAll(Ids.CREATOR_ALL_ACL); acls.addAll(Ids.READ_ACL_UNSAFE); } else { acls.addAll(Ids.CREATOR_ALL_ACL); } return acls; } else { return Ids.OPEN_ACL_UNSAFE; } }