Uploaded image for project: 'HBase'
  1. HBase
  2. HBASE-22503

Failed to upgrade to 2.2+ as the global permission which storaged in zk is not right

VotersWatch issueWatchersCreate sub-taskLinkCloneUpdate Comment AuthorReplace String in CommentUpdate Comment VisibilityDelete Comments


    • Type: Bug
    • Status: Resolved
    • Priority: Blocker
    • Resolution: Fixed
    • Affects Version/s: 2.2.0
    • Fix Version/s: 3.0.0-alpha-1, 2.2.0, 2.3.0
    • Component/s: None
    • Labels:


      Before 2.2, the global permission which storaged in zk is not right. It was storaged as a table permission. After HBASE-21255, 2.2+ will read it as a global permission and will throw a cast error.


      Caused by: java.lang.ClassCastException: org.apache.hadoop.hbase.security.access.TablePermission cannot be cast to org.apache.hadoop.hbase.security.access.GlobalPermission
      at org.apache.hadoop.hbase.security.access.AuthManager.updateGlobalCache(AuthManager.java:171)
      at org.apache.hadoop.hbase.security.access.AuthManager.refreshTableCacheFromWritable(AuthManager.java:129)
      at org.apache.hadoop.hbase.security.access.ZKPermissionWatcher.refreshAuthManager(ZKPermissionWatcher.java:252)
      at org.apache.hadoop.hbase.security.access.ZKPermissionWatcher.refreshNodes(ZKPermissionWatcher.java:235)


      Before 2.2, the acl update logic is complicated. Client sent the grant/revoke rpc call to AccessControl coprocessor directly. And only the RS which has acl region will put a acl record to hbase:acl table. And the AccessControl override postPut/postDelete method, too. It will update zk when postPut/postDelete found this is a put/delete for acl region...And there is a TODO "global entry should be handled differently". The global entry was handled as a table permission, too.


      private static Pair<String, TablePermission> parsePermissionRecord(
          byte[] entryName, Cell kv) {
        // return X given a set of permissions encoded in the permissionRecord kv.
        byte[] family = CellUtil.cloneFamily(kv);
        if (!Bytes.equals(family, ACL_LIST_FAMILY)) {
          return null;
        byte[] key = CellUtil.cloneQualifier(kv);
        byte[] value = CellUtil.cloneValue(kv);
        if (LOG.isDebugEnabled()) {
          LOG.debug("Read acl: kv ["+
              Bytes.toStringBinary(key)+": "+
        // check for a column family appended to the key
        // TODO: avoid the string conversion to make this more efficient
        String username = Bytes.toString(key);
        //Handle namespace entry
        if(isNamespaceEntry(entryName)) {
          return new Pair<>(username, new TablePermission(Bytes.toString(fromNamespaceEntry(entryName)), value));
        //Handle table and global entry
        //TODO global entry should be handled differently
        int idx = username.indexOf(ACL_KEY_DELIMITER);
        byte[] permFamily = null;
        byte[] permQualifier = null;
        if (idx > 0 && idx < username.length()-1) {
          String remainder = username.substring(idx+1);
          username = username.substring(0, idx);
          idx = remainder.indexOf(ACL_KEY_DELIMITER);
          if (idx > 0 && idx < remainder.length()-1) {
            permFamily = Bytes.toBytes(remainder.substring(0, idx));
            permQualifier = Bytes.toBytes(remainder.substring(idx+1));
          } else {
            permFamily = Bytes.toBytes(remainder);
        return new Pair<>(username, new TablePermission(TableName.valueOf(entryName), permFamily, permQualifier, value));




        Issue Links



            • Assignee:
              zghao Guanghao Zhang
              zghao Guanghao Zhang


              • Created:

                Issue deployment