Package org.apache.accumulo.server.security

Source Code of org.apache.accumulo.server.security.ZKAuthenticator$Tool

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.accumulo.server.security;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.Map.Entry;

import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
import org.apache.accumulo.core.client.impl.HdfsZooInstance;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.core.security.SystemPermission;
import org.apache.accumulo.core.security.TablePermission;
import org.apache.accumulo.core.security.thrift.AuthInfo;
import org.apache.accumulo.core.security.thrift.SecurityErrorCode;
import org.apache.accumulo.core.zookeeper.ZooCache;
import org.apache.accumulo.core.zookeeper.ZooUtil;
import org.apache.accumulo.core.zookeeper.ZooUtil.NodeExistsPolicy;
import org.apache.accumulo.core.zookeeper.ZooUtil.NodeMissingPolicy;
import org.apache.log4j.Logger;
import org.apache.zookeeper.KeeperException;

// Utility class for adding all security info into ZK
public final class ZKAuthenticator implements Authenticator {
  private static final Logger log = Logger.getLogger(ZKAuthenticator.class);
  private static ZKAuthenticator zkAuthenticatorInstance = null;
  private static String rootUserName = null;
 
  private final String ZKUserAuths = "/Authorizations";
  private final String ZKUserSysPerms = "/System";
  private final String ZKUserTablePerms = "/Tables";
 
  private final String ZKUserPath;
  private final ZooCache zooCache;
 
  public static synchronized ZKAuthenticator getInstance() {
    if (zkAuthenticatorInstance == null)
      zkAuthenticatorInstance = new ZKAuthenticator();
    return zkAuthenticatorInstance;
  }
 
  private ZKAuthenticator() {
    this(HdfsZooInstance.getInstance().getInstanceID());
  }
 
  public ZKAuthenticator(String instanceId) {
    ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
    zooCache = new ZooCache();
  }
 
  /**
   * Authenticate a user's credentials
   *
   * @return true if username/password combination match existing user; false otherwise
   * @throws AccumuloSecurityException
   */
  private boolean authenticate(AuthInfo credentials) throws AccumuloSecurityException {
    if (!credentials.instanceId.equals(HdfsZooInstance.getInstance().getInstanceID()))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.INVALID_INSTANCEID);
   
    if (credentials.user.equals(SecurityConstants.SYSTEM_USERNAME))
      return credentials.equals(SecurityConstants.systemCredentials);
   
    byte[] pass;
    String zpath = ZKUserPath + "/" + credentials.user;
    pass = zooCache.get(zpath);
    if (pass == null)
      return false;
    return Tool.checkPass(credentials.password, pass);
  }
 
  /**
   * Only SYSTEM user can call this method
   */
  public void initializeSecurity(AuthInfo credentials, String rootuser, byte[] rootpass) throws AccumuloSecurityException {
    if (!credentials.user.equals(SecurityConstants.SYSTEM_USERNAME) || !authenticate(credentials))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    try {
      // remove old settings from zookeeper first, if any
      synchronized (zooCache) {
        zooCache.clear();
        if (ZooUtil.exists(ZKUserPath)) {
          ZooUtil.recursiveDelete(ZKUserPath, NodeMissingPolicy.SKIP);
          log.info("Removed " + ZKUserPath + "/" + " from zookeeper");
        }
       
        // prep parent node of users with root username
        ZooUtil.putPersistentData(ZKUserPath, rootuser.getBytes(), NodeExistsPolicy.FAIL);
       
        // create the root user with all system privileges, no table privileges, and no record-level authorizations
        Set<SystemPermission> rootPerms = new TreeSet<SystemPermission>();
        for (SystemPermission p : SystemPermission.values())
          rootPerms.add(p);
        Map<String,Set<TablePermission>> tablePerms = new HashMap<String,Set<TablePermission>>();
        // Allow the root user to flush the !METADATA table
        tablePerms.put(Constants.METADATA_TABLE_ID, Collections.singleton(TablePermission.ALTER_TABLE));
        constructUser(rootuser, Tool.createPass(rootpass), rootPerms, tablePerms, Constants.NO_AUTHS);
      }
      log.info("Initialized root user with username: " + rootuser + " at the request of user " + credentials.user);
    } catch (KeeperException e) {
      log.error(e, e);
      throw new RuntimeException(e);
    } catch (InterruptedException e) {
      log.error(e, e);
      throw new RuntimeException(e);
    } catch (AccumuloException e) {
      log.error(e, e);
      throw new RuntimeException(e);
    }
  }
 
  /**
   * Sets up the user in ZK for the provided user. No checking for existence is done here, it should be done before calling.
   */
  private void constructUser(String user, byte[] pass, Set<SystemPermission> sysPerms, Map<String,Set<TablePermission>> tablePerms, Authorizations auths)
      throws KeeperException, InterruptedException {
    synchronized (zooCache) {
      zooCache.clear();
      ZooUtil.putPersistentData(ZKUserPath + "/" + user, pass, NodeExistsPolicy.FAIL);
      ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, Tool.convertAuthorizations(auths), NodeExistsPolicy.FAIL);
      ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, Tool.convertSystemPermissions(sysPerms), NodeExistsPolicy.FAIL);
      ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms, new byte[0], NodeExistsPolicy.FAIL);
      for (Entry<String,Set<TablePermission>> entry : tablePerms.entrySet())
        createTablePerm(user, entry.getKey(), entry.getValue());
    }
  }
 
  /**
   * Sets up a new table configuration for the provided user/table. No checking for existance is done here, it should be done before calling.
   */
  private void createTablePerm(String user, String table, Set<TablePermission> perms) throws KeeperException, InterruptedException {
    synchronized (zooCache) {
      zooCache.clear();
      ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, Tool.convertTablePermissions(perms), NodeExistsPolicy.FAIL);
    }
  }
 
  public synchronized String getRootUsername() {
    if (rootUserName == null)
      rootUserName = new String(zooCache.get(ZKUserPath));
    return rootUserName;
  }
 
  public boolean authenticateUser(AuthInfo credentials, String user, byte[] pass) throws AccumuloSecurityException {
    if (!authenticate(credentials))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
    if (!credentials.user.equals(user) && !hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    return authenticate(new AuthInfo(user, pass, credentials.instanceId));
  }
 
  @Override
  public Set<String> listUsers(AuthInfo credentials) throws AccumuloSecurityException {
    if (!authenticate(credentials))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
   
    return new TreeSet<String>(zooCache.getChildren(ZKUserPath));
  }
 
  /**
   * Creates a user with no permissions whatsoever
   */
  public void createUser(AuthInfo credentials, String user, byte[] pass, Authorizations authorizations) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.CREATE_USER))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // don't allow creating a user with the same name as system user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      throw new AccumuloSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
   
    try {
      constructUser(user, Tool.createPass(pass), new TreeSet<SystemPermission>(), new HashMap<String,Set<TablePermission>>(), authorizations);
      log.info("Created user " + user + " at the request of user " + credentials.user);
    } catch (KeeperException e) {
      log.error(e, e);
      if (e.code().equals(KeeperException.Code.NODEEXISTS))
        throw new AccumuloSecurityException(user, SecurityErrorCode.USER_EXISTS, e);
      throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
    } catch (InterruptedException e) {
      log.error(e, e);
      throw new RuntimeException(e);
    } catch (AccumuloException e) {
      log.error(e, e);
      throw new AccumuloSecurityException(user, SecurityErrorCode.DEFAULT_SECURITY_ERROR, e);
    }
  }
 
  public void dropUser(AuthInfo credentials, String user) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_USER))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // can't delete root or system users
    if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
      throw new AccumuloSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
   
    try {
      synchronized (zooCache) {
        zooCache.clear();
        ZooUtil.recursiveDelete(ZKUserPath + "/" + user, NodeMissingPolicy.FAIL);
      }
      log.info("Deleted user " + user + " at the request of user " + credentials.user);
    } catch (InterruptedException e) {
      log.error(e, e);
      throw new RuntimeException(e);
    } catch (KeeperException e) {
      log.error(e, e);
      if (e.code().equals(KeeperException.Code.NONODE))
        throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST, e);
      throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
    }
  }
 
  public void changePassword(AuthInfo credentials, String user, byte[] pass) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER) && !credentials.user.equals(user))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // can't modify system user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      throw new AccumuloSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
   
    if (userExists(user)) {
      try {
        synchronized (zooCache) {
          zooCache.clear();
          ZooUtil.putPersistentData(ZKUserPath + "/" + user, Tool.createPass(pass), NodeExistsPolicy.OVERWRITE);
        }
        log.info("Changed password for user " + user + " at the request of user " + credentials.user);
      } catch (KeeperException e) {
        log.error(e, e);
        throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
      } catch (InterruptedException e) {
        log.error(e, e);
        throw new RuntimeException(e);
      } catch (AccumuloException e) {
        log.error(e, e);
        throw new AccumuloSecurityException(user, SecurityErrorCode.DEFAULT_SECURITY_ERROR, e);
      }
    } else
      throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
  }
 
  /**
   * Checks if a user exists
   */
  private boolean userExists(String user) {
    return zooCache.get(ZKUserPath + "/" + user) != null;
  }
 
  public void changeAuthorizations(AuthInfo credentials, String user, Authorizations authorizations) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // can't modify system user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    if (userExists(user)) {
      try {
        synchronized (zooCache) {
          zooCache.clear();
          ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, Tool.convertAuthorizations(authorizations), NodeExistsPolicy.OVERWRITE);
        }
        log.info("Changed authorizations for user " + user + " at the request of user " + credentials.user);
      } catch (KeeperException e) {
        log.error(e, e);
        throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
      } catch (InterruptedException e) {
        log.error(e, e);
        throw new RuntimeException(e);
      }
    } else
      throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
  }
 
  public Authorizations getUserAuthorizations(AuthInfo credentials, String user) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM) && !credentials.user.equals(user))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // system user doesn't need record-level authorizations for the tables it reads (for now)
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      return Constants.NO_AUTHS;
   
    if (userExists(user))
      return Tool.convertAuthorizations(zooCache.get(ZKUserPath + "/" + user + ZKUserAuths));
    throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
  }
 
  /**
   * Checks if a user has a system permission
   *
   * @return true if a user exists and has permission; false otherwise
   */
  @Override
  public boolean hasSystemPermission(AuthInfo credentials, String user, SystemPermission permission) throws AccumuloSecurityException {
    if (!authenticate(credentials))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
   
    // some people just aren't allowed to ask about other users; here are those who can ask
    if (!credentials.user.equals(user) && !hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM)
        && !hasSystemPermission(credentials, credentials.user, SystemPermission.CREATE_USER)
        && !hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
        && !hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_USER))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
      return true;
   
    if (userExists(user))
      return Tool.convertSystemPermissions(zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms)).contains(permission);
    throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
  }
 
  @Override
  public boolean hasTablePermission(AuthInfo credentials, String user, String table, TablePermission permission) throws AccumuloSecurityException {
    if (!authenticate(credentials))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
   
    // some people just aren't allowed to ask about other users; here are those who can ask
    if (!credentials.user.equals(user) && !hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM)
        && !hasSystemPermission(credentials, credentials.user, SystemPermission.CREATE_USER)
        && !hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
        && !hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_USER))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // always allow system user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      return true;
   
    // Don't let nonexistant users scan
    if (!userExists(user))
      throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
     
    // allow anybody to read the METADATA table
    if (table.equals(Constants.METADATA_TABLE_ID) && permission.equals(TablePermission.READ))
      return true;
   
    if (userTableExists(user, table)) {
      return Tool.convertTablePermissions(zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table)).contains(permission);
    }
    return false;
  }
 
  /**
   * Checks if a user has ANY permissions for a table. Assumes user exists
   */
  private boolean userTableExists(String user, String table) {
    return zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table) != null;
  }
 
  @Override
  public void grantSystemPermission(AuthInfo credentials, String user, SystemPermission permission) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.GRANT))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // can't modify system user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    if (permission.equals(SystemPermission.GRANT))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.GRANT_INVALID);
   
    if (userExists(user)) {
      Set<SystemPermission> perms = Tool.convertSystemPermissions(zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms));
      try {
        if (perms.add(permission)) {
          synchronized (zooCache) {
            zooCache.clear();
            ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, Tool.convertSystemPermissions(perms), NodeExistsPolicy.OVERWRITE);
          }
        }
        log.info("Granted system permission " + permission + " for user " + user + " at the request of user " + credentials.user);
      } catch (KeeperException e) {
        log.error(e, e);
        throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
      } catch (InterruptedException e) {
        log.error(e, e);
        throw new RuntimeException(e);
      }
    } else
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
  }
 
  @Override
  public void grantTablePermission(AuthInfo credentials, String user, String table, TablePermission permission) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
        && !hasTablePermission(credentials, credentials.user, table, TablePermission.GRANT))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // can't modify system user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    if (userExists(user)) {
      Set<TablePermission> tablePerms;
      boolean hasTable = userTableExists(user, table);
      if (hasTable)
        tablePerms = Tool.convertTablePermissions(zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table));
      else
        tablePerms = new TreeSet<TablePermission>();
     
      try {
        if (tablePerms.add(permission)) {
          synchronized (zooCache) {
            zooCache.clear();
            ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, Tool.convertTablePermissions(tablePerms),
                NodeExistsPolicy.OVERWRITE);
          }
        }
        log.info("Granted table permission " + permission + " for user " + user + " on the table " + table + " at the request of user " + credentials.user);
      } catch (KeeperException e) {
        log.error(e, e);
        throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
      } catch (InterruptedException e) {
        log.error(e, e);
        throw new RuntimeException(e);
      }
    } else
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
  }
 
  @Override
  public void revokeSystemPermission(AuthInfo credentials, String user, SystemPermission permission) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.GRANT))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // can't modify system user or revoke permissions from root user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME) || user.equals(getRootUsername()))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    if (permission.equals(SystemPermission.GRANT))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.GRANT_INVALID);
   
    if (userExists(user)) {
      Set<SystemPermission> sysPerms = Tool.convertSystemPermissions(zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms));
      try {
        if (sysPerms.remove(permission)) {
          synchronized (zooCache) {
            zooCache.clear();
            ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, Tool.convertSystemPermissions(sysPerms), NodeExistsPolicy.OVERWRITE);
          }
        }
        log.info("Revoked system permission " + permission + " for user " + user + " at the request of user " + credentials.user);
      } catch (KeeperException e) {
        log.error(e, e);
        throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
      } catch (InterruptedException e) {
        log.error(e, e);
        throw new RuntimeException(e);
      }
    } else
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST);
  }
 
  @Override
  public void revokeTablePermission(AuthInfo credentials, String user, String table, TablePermission permission) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
        && !hasTablePermission(credentials, credentials.user, table, TablePermission.GRANT))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    // can't modify system user
    if (user.equals(SecurityConstants.SYSTEM_USERNAME))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    if (userExists(user)) {
      if (!userTableExists(user, table))
        return;
      Set<TablePermission> tablePerms = Tool.convertTablePermissions(zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table));
      try {
        if (tablePerms.remove(permission)) {
          zooCache.clear();
          if (tablePerms.size() == 0)
            ZooUtil.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
          else
            ZooUtil.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, Tool.convertTablePermissions(tablePerms),
                NodeExistsPolicy.OVERWRITE);
        }
      } catch (KeeperException e) {
        log.error(e, e);
        throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
      } catch (InterruptedException e) {
        log.error(e, e);
        throw new RuntimeException(e);
      }
      log.info("Revoked table permission " + permission + " for user " + user + " on the table " + table + " at the request of user " + credentials.user);
    } else
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST);
  }
 
  @Override
  public void deleteTable(AuthInfo credentials, String table) throws AccumuloSecurityException {
    if (!hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_TABLE)
        && !hasTablePermission(credentials, credentials.user, table, TablePermission.DROP_TABLE))
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
   
    try {
      synchronized (zooCache) {
        zooCache.clear();
        for (String user : zooCache.getChildren(ZKUserPath))
          ZooUtil.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
      }
    } catch (KeeperException e) {
      log.error(e, e);
      throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.CONNECTION_ERROR, e);
    } catch (InterruptedException e) {
      log.error(e, e);
      throw new RuntimeException(e);
    }
  }
 
  /**
   * All the static too methods used for this class, so that we can separate out stuff that isn't using ZooKeeper. That way, we can check the synchronization
   * model more easily, as we only need to check to make sure zooCache is cleared when things are written to ZooKeeper in methods that might use it. These
   * won't, and so don't need to be checked.
   */
  static class Tool {
    private static final int SALT_LENGTH = 8;
   
    // Generates a byte array salt of length SALT_LENGTH
    private static byte[] generateSalt() {
      final SecureRandom random = new SecureRandom();
      byte[] salt = new byte[SALT_LENGTH];
      random.nextBytes(salt);
      return salt;
    }
   
    private static byte[] hash(byte[] raw) throws NoSuchAlgorithmException {
      MessageDigest md = MessageDigest.getInstance(Constants.PW_HASH_ALGORITHM);
      md.update(raw);
      return md.digest();
    }
   
    public static boolean checkPass(byte[] password, byte[] zkData) {
      byte[] salt = new byte[SALT_LENGTH];
      System.arraycopy(zkData, 0, salt, 0, SALT_LENGTH);
      byte[] passwordToCheck;
      try {
        passwordToCheck = convertPass(password, salt);
      } catch (NoSuchAlgorithmException e) {
        log.error("Count not create hashed password", e);
        return false;
      }
      return java.util.Arrays.equals(passwordToCheck, zkData);
    }
   
    public static byte[] createPass(byte[] password) throws AccumuloException {
      byte[] salt = generateSalt();
      try {
        return convertPass(password, salt);
      } catch (NoSuchAlgorithmException e) {
        log.error("Count not create hashed password", e);
        throw new AccumuloException("Count not create hashed password", e);
      }
    }
   
    private static byte[] convertPass(byte[] password, byte[] salt) throws NoSuchAlgorithmException {
      byte[] plainSalt = new byte[password.length + SALT_LENGTH];
      System.arraycopy(password, 0, plainSalt, 0, password.length);
      System.arraycopy(salt, 0, plainSalt, password.length, SALT_LENGTH);
      byte[] hashed = hash(plainSalt);
      byte[] saltedHash = new byte[SALT_LENGTH + hashed.length];
      System.arraycopy(salt, 0, saltedHash, 0, SALT_LENGTH);
      System.arraycopy(hashed, 0, saltedHash, SALT_LENGTH, hashed.length);
      return saltedHash; // contains salt+hash(password+salt)
    }
   
    public static Authorizations convertAuthorizations(byte[] authorizations) {
      return new Authorizations(authorizations);
    }
   
    public static byte[] convertAuthorizations(Authorizations authorizations) {
      return authorizations.getAuthorizationsArray();
    }
   
    public static byte[] convertSystemPermissions(Set<SystemPermission> systempermissions) {
      ByteArrayOutputStream bytes = new ByteArrayOutputStream(systempermissions.size());
      DataOutputStream out = new DataOutputStream(bytes);
      try {
        for (SystemPermission sp : systempermissions)
          out.writeByte(sp.getId());
      } catch (IOException e) {
        log.error(e, e);
        throw new RuntimeException(e); // this is impossible with ByteArrayOutputStream; crash hard if this happens
      }
      return bytes.toByteArray();
    }
   
    public static Set<SystemPermission> convertSystemPermissions(byte[] systempermissions) {
      ByteArrayInputStream bytes = new ByteArrayInputStream(systempermissions);
      DataInputStream in = new DataInputStream(bytes);
      Set<SystemPermission> toReturn = new HashSet<SystemPermission>();
      try {
        while (in.available() > 0)
          toReturn.add(SystemPermission.getPermissionById(in.readByte()));
      } catch (IOException e) {
        log.error("User database is corrupt; error converting system permissions", e);
        toReturn.clear();
      }
      return toReturn;
    }
   
    public static byte[] convertTablePermissions(Set<TablePermission> tablepermissions) {
      ByteArrayOutputStream bytes = new ByteArrayOutputStream(tablepermissions.size());
      DataOutputStream out = new DataOutputStream(bytes);
      try {
        for (TablePermission tp : tablepermissions)
          out.writeByte(tp.getId());
      } catch (IOException e) {
        log.error(e, e);
        throw new RuntimeException(e); // this is impossible with ByteArrayOutputStream; crash hard if this happens
      }
      return bytes.toByteArray();
    }
   
    public static Set<TablePermission> convertTablePermissions(byte[] tablepermissions) {
      Set<TablePermission> toReturn = new HashSet<TablePermission>();
      for (byte b : tablepermissions)
        toReturn.add(TablePermission.getPermissionById(b));
      return toReturn;
    }
  }
}
TOP

Related Classes of org.apache.accumulo.server.security.ZKAuthenticator$Tool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.