accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject [14/50] [abbrv] Merge branch '1.5' into 1.6
Date Sat, 01 Nov 2014 04:57:08 GMT
http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java
index d0e6aea,0000000..258080c
mode 100644,000000..100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java
@@@ -1,775 -1,0 +1,777 @@@
 +/*
 + * 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 static com.google.common.base.Charsets.UTF_8;
++
 +import java.nio.ByteBuffer;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.AccumuloSecurityException;
 +import org.apache.accumulo.core.client.NamespaceNotFoundException;
 +import org.apache.accumulo.core.client.TableNotFoundException;
 +import org.apache.accumulo.core.client.impl.SecurityOperationsImpl;
 +import org.apache.accumulo.core.client.impl.Namespaces;
 +import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
 +import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException;
 +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
 +import org.apache.accumulo.core.conf.Property;
 +import org.apache.accumulo.core.data.thrift.IterInfo;
 +import org.apache.accumulo.core.data.thrift.TColumn;
 +import org.apache.accumulo.core.data.thrift.TKeyExtent;
 +import org.apache.accumulo.core.data.thrift.TRange;
 +import org.apache.accumulo.core.master.thrift.FateOperation;
 +import org.apache.accumulo.core.metadata.MetadataTable;
 +import org.apache.accumulo.core.metadata.RootTable;
 +import org.apache.accumulo.core.security.Authorizations;
 +import org.apache.accumulo.core.security.Credentials;
 +import org.apache.accumulo.core.security.NamespacePermission;
 +import org.apache.accumulo.core.security.SystemPermission;
 +import org.apache.accumulo.core.security.TablePermission;
 +import org.apache.accumulo.core.security.thrift.TCredentials;
 +import org.apache.accumulo.server.client.HdfsZooInstance;
 +import org.apache.accumulo.server.conf.ServerConfiguration;
 +import org.apache.accumulo.server.security.handler.Authenticator;
 +import org.apache.accumulo.server.security.handler.Authorizor;
 +import org.apache.accumulo.server.security.handler.PermissionHandler;
 +import org.apache.accumulo.server.security.handler.ZKAuthenticator;
 +import org.apache.accumulo.server.security.handler.ZKAuthorizor;
 +import org.apache.accumulo.server.security.handler.ZKPermHandler;
 +import org.apache.accumulo.server.zookeeper.ZooCache;
 +import org.apache.hadoop.io.Text;
 +import org.apache.log4j.Logger;
 +
 +/**
 + * Utility class for performing various security operations with the appropriate checks
 + */
 +public class SecurityOperation {
 +  private static final Logger log = Logger.getLogger(SecurityOperationsImpl.class);
 +
 +  protected Authorizor authorizor;
 +  protected Authenticator authenticator;
 +  protected PermissionHandler permHandle;
 +  private static String rootUserName = null;
 +  private final ZooCache zooCache;
 +  private final String ZKUserPath;
 +
 +  static SecurityOperation instance;
 +
 +  public static synchronized SecurityOperation getInstance() {
 +    String instanceId = HdfsZooInstance.getInstance().getInstanceID();
 +    return getInstance(instanceId, false);
 +  }
 +
 +  public static synchronized SecurityOperation getInstance(String instanceId, boolean initialize) {
 +    if (instance == null) {
 +      instance = new SecurityOperation(getAuthorizor(instanceId, initialize), getAuthenticator(instanceId, initialize), getPermHandler(instanceId, initialize),
 +          instanceId);
 +    }
 +    return instance;
 +  }
 +
 +  protected static Authorizor getAuthorizor(String instanceId, boolean initialize) {
 +    Authorizor toRet = ServerConfiguration.getSiteConfiguration().instantiateClassProperty(Property.INSTANCE_SECURITY_AUTHORIZOR, Authorizor.class,
 +        ZKAuthorizor.getInstance());
 +    toRet.initialize(instanceId, initialize);
 +    return toRet;
 +  }
 +
 +  protected static Authenticator getAuthenticator(String instanceId, boolean initialize) {
 +    Authenticator toRet = ServerConfiguration.getSiteConfiguration().instantiateClassProperty(Property.INSTANCE_SECURITY_AUTHENTICATOR, Authenticator.class,
 +        ZKAuthenticator.getInstance());
 +    toRet.initialize(instanceId, initialize);
 +    return toRet;
 +  }
 +
 +  protected static PermissionHandler getPermHandler(String instanceId, boolean initialize) {
 +    PermissionHandler toRet = ServerConfiguration.getSiteConfiguration().instantiateClassProperty(Property.INSTANCE_SECURITY_PERMISSION_HANDLER,
 +        PermissionHandler.class, ZKPermHandler.getInstance());
 +    toRet.initialize(instanceId, initialize);
 +    return toRet;
 +  }
 +
 +  protected SecurityOperation(String instanceId) {
 +    ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
 +    zooCache = new ZooCache();
 +  }
 +
 +  public SecurityOperation(Authorizor author, Authenticator authent, PermissionHandler pm, String instanceId) {
 +    this(instanceId);
 +    authorizor = author;
 +    authenticator = authent;
 +    permHandle = pm;
 +
 +    if (!authorizor.validSecurityHandlers(authenticator, pm) || !authenticator.validSecurityHandlers(authorizor, pm)
 +        || !permHandle.validSecurityHandlers(authent, author))
 +      throw new RuntimeException(authorizor + ", " + authenticator + ", and " + pm
 +          + " do not play nice with eachother. Please choose authentication and authorization mechanisms that are compatible with one another.");
 +  }
 +
 +  public void initializeSecurity(TCredentials credentials, String rootPrincipal, byte[] token) throws AccumuloSecurityException, ThriftSecurityException {
 +    authenticate(credentials);
 +
 +    if (!isSystemUser(credentials))
 +      throw new AccumuloSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    authenticator.initializeSecurity(credentials, rootPrincipal, token);
 +    authorizor.initializeSecurity(credentials, rootPrincipal);
 +    permHandle.initializeSecurity(credentials, rootPrincipal);
 +    try {
 +      permHandle.grantTablePermission(rootPrincipal, MetadataTable.ID, TablePermission.ALTER_TABLE);
 +    } catch (TableNotFoundException e) {
 +      // Shouldn't happen
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  public synchronized String getRootUsername() {
 +    if (rootUserName == null)
-       rootUserName = new String(zooCache.get(ZKUserPath), Constants.UTF8);
++      rootUserName = new String(zooCache.get(ZKUserPath), UTF_8);
 +    return rootUserName;
 +  }
 +
 +  public boolean isSystemUser(TCredentials credentials) {
 +    return SystemCredentials.get().getToken().getClass().getName().equals(credentials.getTokenClassName());
 +  }
 +
 +  protected void authenticate(TCredentials credentials) throws ThriftSecurityException {
 +    if (!credentials.getInstanceId().equals(HdfsZooInstance.getInstance().getInstanceID()))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.INVALID_INSTANCEID);
 +
 +    Credentials creds = Credentials.fromThrift(credentials);
 +    if (isSystemUser(credentials)) {
 +      if (!(SystemCredentials.get().equals(creds))) {
 +        throw new ThriftSecurityException(creds.getPrincipal(), SecurityErrorCode.BAD_CREDENTIALS);
 +      }
 +    } else {
 +      try {
 +        if (!authenticator.authenticateUser(creds.getPrincipal(), creds.getToken())) {
 +          throw new ThriftSecurityException(creds.getPrincipal(), SecurityErrorCode.BAD_CREDENTIALS);
 +        }
 +      } catch (AccumuloSecurityException e) {
 +        log.debug(e);
 +        throw e.asThriftException();
 +      }
 +    }
 +  }
 +
 +  public boolean canAskAboutUser(TCredentials credentials, String user) throws ThriftSecurityException {
 +    // Authentication done in canPerformSystemActions
 +    if (!(canPerformSystemActions(credentials) || credentials.getPrincipal().equals(user)))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    return true;
 +  }
 +
 +  public boolean authenticateUser(TCredentials credentials, TCredentials toAuth) throws ThriftSecurityException {
 +    canAskAboutUser(credentials, toAuth.getPrincipal());
 +    // User is already authenticated from canAskAboutUser
 +    if (credentials.equals(toAuth))
 +      return true;
 +    try {
 +      Credentials toCreds = Credentials.fromThrift(toAuth);
 +      return authenticator.authenticateUser(toCreds.getPrincipal(), toCreds.getToken());
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public Authorizations getUserAuthorizations(TCredentials credentials, String user) throws ThriftSecurityException {
 +    authenticate(credentials);
 +
 +    targetUserExists(user);
 +
 +    if (!credentials.getPrincipal().equals(user) && !hasSystemPermission(credentials, SystemPermission.SYSTEM, false))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    try {
 +      return authorizor.getCachedUserAuthorizations(user);
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public Authorizations getUserAuthorizations(TCredentials credentials) throws ThriftSecurityException {
 +    // system user doesn't need record-level authorizations for the tables it reads
 +    if (isSystemUser(credentials)) {
 +      authenticate(credentials);
 +      return Authorizations.EMPTY;
 +    }
 +    return getUserAuthorizations(credentials, credentials.getPrincipal());
 +  }
 +
 +  public boolean userHasAuthorizations(TCredentials credentials, List<ByteBuffer> list) throws ThriftSecurityException {
 +    authenticate(credentials);
 +
 +    if (isSystemUser(credentials)) {
 +      // system user doesn't need record-level authorizations for the tables it reads (for now)
 +      return list.isEmpty();
 +    }
 +
 +    try {
 +      return authorizor.isValidAuthorizations(credentials.getPrincipal(), list);
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  private boolean hasSystemPermission(TCredentials credentials, SystemPermission permission, boolean useCached) throws ThriftSecurityException {
 +    return hasSystemPermissionWithNamespaceId(credentials, permission, null, useCached);
 +  }
 +
 +  /**
 +   * Checks if a user has a system permission
 +   * 
 +   * @return true if a user exists and has permission; false otherwise
 +   */
 +  private boolean hasSystemPermissionWithNamespaceId(TCredentials credentials, SystemPermission permission, String namespaceId, boolean useCached)
 +      throws ThriftSecurityException {
 +    if (isSystemUser(credentials))
 +      return true;
 +
 +    if (_hasSystemPermission(credentials.getPrincipal(), permission, useCached))
 +      return true;
 +    if (namespaceId != null) {
 +      return _hasNamespacePermission(credentials.getPrincipal(), namespaceId, NamespacePermission.getEquivalent(permission), useCached);
 +    }
 +
 +    return false;
 +  }
 +
 +  /**
 +   * Checks if a user has a system permission<br/>
 +   * This cannot check if a system user has permission.
 +   * 
 +   * @return true if a user exists and has permission; false otherwise
 +   */
 +  private boolean _hasSystemPermission(String user, SystemPermission permission, boolean useCached) throws ThriftSecurityException {
 +    if (user.equals(getRootUsername()))
 +      return true;
 +
 +    targetUserExists(user);
 +
 +    try {
 +      if (useCached)
 +        return permHandle.hasCachedSystemPermission(user, permission);
 +      return permHandle.hasSystemPermission(user, permission);
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  /**
 +   * Checks if a user has a table permission
 +   * 
 +   * @return true if a user exists and has permission; false otherwise
 +   */
 +  protected boolean hasTablePermission(TCredentials credentials, String tableId, String namespaceId, TablePermission permission, boolean useCached) throws ThriftSecurityException {
 +    if (isSystemUser(credentials))
 +      return true;
 +    return _hasTablePermission(credentials.getPrincipal(), tableId, permission, useCached)
 +        || _hasNamespacePermission(credentials.getPrincipal(), namespaceId, NamespacePermission.getEquivalent(permission), useCached);
 +  }
 +
 +  /**
 +   * Checks if a user has a table permission<br/>
 +   * This cannot check if a system user has permission.
 +   * 
 +   * @return true if a user exists and has permission; false otherwise
 +   */
 +  protected boolean _hasTablePermission(String user, String table, TablePermission permission, boolean useCached) throws ThriftSecurityException {
 +    targetUserExists(user);
 +
 +    if ((table.equals(MetadataTable.ID) || table.equals(RootTable.ID)) && permission.equals(TablePermission.READ))
 +      return true;
 +
 +    try {
 +      if (useCached)
 +        return permHandle.hasCachedTablePermission(user, table, permission);
 +      return permHandle.hasTablePermission(user, table, permission);
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    } catch (TableNotFoundException e) {
 +      throw new ThriftSecurityException(user, SecurityErrorCode.TABLE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  /**
 +   * Checks if a user has a namespace permission<br/>
 +   * This cannot check if a system user has permission.
 +   * 
 +   * @return true if a user exists and has permission; false otherwise
 +   */
 +  protected boolean _hasNamespacePermission(String user, String namespace, NamespacePermission permission, boolean useCached) throws ThriftSecurityException {
 +    if (permission == null)
 +      return false;
 +
 +    targetUserExists(user);
 +
 +    if (namespace.equals(Namespaces.ACCUMULO_NAMESPACE_ID) && permission.equals(NamespacePermission.READ))
 +      return true;
 +
 +    try {
 +      if (useCached)
 +        return permHandle.hasCachedNamespacePermission(user, namespace, permission);
 +      return permHandle.hasNamespacePermission(user, namespace, permission);
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    } catch (NamespaceNotFoundException e) {
 +      throw new ThriftSecurityException(user, SecurityErrorCode.NAMESPACE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  // some people just aren't allowed to ask about other users; here are those who can ask
 +  private boolean canAskAboutOtherUsers(TCredentials credentials, String user) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return credentials.getPrincipal().equals(user) || hasSystemPermission(credentials, SystemPermission.SYSTEM, false)
 +        || hasSystemPermission(credentials, SystemPermission.CREATE_USER, false) || hasSystemPermission(credentials, SystemPermission.ALTER_USER, false)
 +        || hasSystemPermission(credentials, SystemPermission.DROP_USER, false);
 +  }
 +
 +  private void targetUserExists(String user) throws ThriftSecurityException {
 +    if (user.equals(getRootUsername()))
 +      return;
 +    try {
 +      if (!authenticator.userExists(user))
 +        throw new ThriftSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST);
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public boolean canScan(TCredentials credentials, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasTablePermission(credentials, tableId, namespaceId, TablePermission.READ, true);
 +  }
 +
 +  public boolean canScan(TCredentials credentials, String tableId, String namespaceId, TRange range, List<TColumn> columns, List<IterInfo> ssiList,
 +      Map<String,Map<String,String>> ssio, List<ByteBuffer> authorizations) throws ThriftSecurityException {
 +    return canScan(credentials, tableId, namespaceId);
 +  }
 +
 +  public boolean canScan(TCredentials credentials, String table, String namespaceId, Map<TKeyExtent,List<TRange>> tbatch, List<TColumn> tcolumns, List<IterInfo> ssiList,
 +      Map<String,Map<String,String>> ssio, List<ByteBuffer> authorizations) throws ThriftSecurityException {
 +    return canScan(credentials, table, namespaceId);
 +  }
 +
 +  public boolean canWrite(TCredentials credentials, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasTablePermission(credentials, tableId, namespaceId, TablePermission.WRITE, true);
 +  }
 +
 +  public boolean canConditionallyUpdate(TCredentials credentials, String tableID, String namespaceId, List<ByteBuffer> authorizations) throws ThriftSecurityException {
 +
 +    authenticate(credentials);
 +
 +    return hasTablePermission(credentials, tableID, namespaceId, TablePermission.WRITE, true) && hasTablePermission(credentials, tableID, namespaceId, TablePermission.READ, true);
 +  }
 +
 +  public boolean canSplitTablet(TCredentials credentials, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasSystemPermissionWithNamespaceId(credentials, SystemPermission.ALTER_TABLE, namespaceId, false)
 +        || hasSystemPermissionWithNamespaceId(credentials, SystemPermission.SYSTEM, namespaceId, false)
 +        || hasTablePermission(credentials, tableId, namespaceId, TablePermission.ALTER_TABLE, false);
 +  }
 +
 +  /**
 +   * This is the check to perform any system action. This includes tserver's loading of a tablet, shutting the system down, or altering system properties.
 +   */
 +  public boolean canPerformSystemActions(TCredentials credentials) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasSystemPermission(credentials, SystemPermission.SYSTEM, false);
 +  }
 +
 +  public boolean canFlush(TCredentials c, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasTablePermission(c, tableId, namespaceId, TablePermission.WRITE, false) || hasTablePermission(c, tableId, namespaceId, TablePermission.ALTER_TABLE, false);
 +  }
 +
 +  public boolean canAlterTable(TCredentials c, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasTablePermission(c, tableId, namespaceId, TablePermission.ALTER_TABLE, false)
 +        || hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_TABLE, namespaceId, false);
 +  }
 +
 +  public boolean canCreateTable(TCredentials c, String table, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.CREATE_TABLE, namespaceId, false);
 +  }
 +
 +  public boolean canRenameTable(TCredentials c, String tableId, String oldTableName, String newTableName, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_TABLE, namespaceId, false)
 +        || hasTablePermission(c, tableId, namespaceId, TablePermission.ALTER_TABLE, false);
 +  }
 +
 +  public boolean canCloneTable(TCredentials c, String tableId, String tableName, String destinationNamespaceId, String srcNamespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.CREATE_TABLE, destinationNamespaceId, false) && hasTablePermission(c, tableId, srcNamespaceId, TablePermission.READ, false);
 +  }
 +
 +  public boolean canDeleteTable(TCredentials c, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.DROP_TABLE, namespaceId, false) || hasTablePermission(c, tableId, namespaceId, TablePermission.DROP_TABLE, false);
 +  }
 +
 +  public boolean canOnlineOfflineTable(TCredentials c, String tableId, FateOperation op, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.SYSTEM, namespaceId, false)
 +        || hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_TABLE, namespaceId, false)
 +        || hasTablePermission(c, tableId, namespaceId, TablePermission.ALTER_TABLE, false);
 +  }
 +
 +  public boolean canMerge(TCredentials c, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.SYSTEM, namespaceId, false)
 +        || hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_TABLE, namespaceId, false)
 +        || hasTablePermission(c, tableId, namespaceId, TablePermission.ALTER_TABLE, false);
 +  }
 +
 +  public boolean canDeleteRange(TCredentials c, String tableId, String tableName, Text startRow, Text endRow, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.SYSTEM, namespaceId, false) || hasTablePermission(c, tableId, namespaceId, TablePermission.WRITE, false);
 +  }
 +
 +  public boolean canBulkImport(TCredentials c, String tableId, String tableName, String dir, String failDir, String namespaceId) throws ThriftSecurityException {
 +    return canBulkImport(c, tableId, namespaceId);
 +  }
 +
 +  public boolean canBulkImport(TCredentials c, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasTablePermission(c, tableId, namespaceId, TablePermission.BULK_IMPORT, false);
 +  }
 +
 +  public boolean canCompact(TCredentials c, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_TABLE, namespaceId, false)
 +        || hasTablePermission(c, tableId, namespaceId, TablePermission.ALTER_TABLE, false) || hasTablePermission(c, tableId, namespaceId, TablePermission.WRITE, false);
 +  }
 +
 +  public boolean canChangeAuthorizations(TCredentials c, String user) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermission(c, SystemPermission.ALTER_USER, false);
 +  }
 +
 +  public boolean canChangePassword(TCredentials c, String user) throws ThriftSecurityException {
 +    authenticate(c);
 +    return c.getPrincipal().equals(user) || hasSystemPermission(c, SystemPermission.ALTER_USER, false);
 +  }
 +
 +  public boolean canCreateUser(TCredentials c, String user) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermission(c, SystemPermission.CREATE_USER, false);
 +  }
 +
 +  public boolean canDropUser(TCredentials c, String user) throws ThriftSecurityException {
 +    authenticate(c);
 +    if (user.equals(getRootUsername()))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    return hasSystemPermission(c, SystemPermission.DROP_USER, false);
 +  }
 +
 +  public boolean canGrantSystem(TCredentials c, String user, SystemPermission sysPerm) throws ThriftSecurityException {
 +    authenticate(c);
 +    // can't grant GRANT
 +    if (sysPerm.equals(SystemPermission.GRANT))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.GRANT_INVALID);
 +    return hasSystemPermission(c, SystemPermission.GRANT, false);
 +  }
 +
 +  public boolean canGrantTable(TCredentials c, String user, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_TABLE, namespaceId, false) || hasTablePermission(c, tableId, namespaceId, TablePermission.GRANT, false);
 +  }
 +
 +  public boolean canGrantNamespace(TCredentials c, String user, String namespace) throws ThriftSecurityException {
 +    return canModifyNamespacePermission(c, user, namespace);
 +  }
 +
 +  private boolean canModifyNamespacePermission(TCredentials c, String user, String namespace) throws ThriftSecurityException {
 +    authenticate(c);
 +    // The one case where Table/SystemPermission -> NamespacePermission breaks down. The alternative is to make SystemPermission.ALTER_NAMESPACE provide
 +    // NamespacePermission.GRANT & ALTER_NAMESPACE, but then it would cause some permission checks to succeed with GRANT when they shouldn't
 +    
 +    // This is a bit hackier then I (vines) wanted, but I think this one hackiness makes the overall SecurityOperations more succinct.
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_NAMESPACE, namespace, false)
 +        || hasNamespacePermission(c, c.principal, namespace, NamespacePermission.GRANT);
 +  }
 +
 +  public boolean canRevokeSystem(TCredentials c, String user, SystemPermission sysPerm) throws ThriftSecurityException {
 +    authenticate(c);
 +    // can't modify root user
 +    if (user.equals(getRootUsername()))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    // can't revoke GRANT
 +    if (sysPerm.equals(SystemPermission.GRANT))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.GRANT_INVALID);
 +
 +    return hasSystemPermission(c, SystemPermission.GRANT, false);
 +  }
 +
 +  public boolean canRevokeTable(TCredentials c, String user, String tableId, String namespaceId) throws ThriftSecurityException {
 +    authenticate(c);
 +    return hasSystemPermissionWithNamespaceId(c, SystemPermission.ALTER_TABLE, namespaceId, false) || hasTablePermission(c, tableId, namespaceId, TablePermission.GRANT, false);
 +  }
 +
 +  public boolean canRevokeNamespace(TCredentials c, String user, String namespace) throws ThriftSecurityException {
 +    return canModifyNamespacePermission(c, user, namespace);
 +  }
 +
 +  public void changeAuthorizations(TCredentials credentials, String user, Authorizations authorizations) throws ThriftSecurityException {
 +    if (!canChangeAuthorizations(credentials, user))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    targetUserExists(user);
 +
 +    try {
 +      authorizor.changeAuthorizations(user, authorizations);
 +      log.info("Changed authorizations for user " + user + " at the request of user " + credentials.getPrincipal());
 +    } catch (AccumuloSecurityException ase) {
 +      throw ase.asThriftException();
 +    }
 +  }
 +
 +  public void changePassword(TCredentials credentials, Credentials toChange) throws ThriftSecurityException {
 +    if (!canChangePassword(credentials, toChange.getPrincipal()))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    try {
 +      AuthenticationToken token = toChange.getToken();
 +      authenticator.changePassword(toChange.getPrincipal(), token);
 +      log.info("Changed password for user " + toChange.getPrincipal() + " at the request of user " + credentials.getPrincipal());
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public void createUser(TCredentials credentials, Credentials newUser, Authorizations authorizations) throws ThriftSecurityException {
 +    if (!canCreateUser(credentials, newUser.getPrincipal()))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    try {
 +      AuthenticationToken token = newUser.getToken();
 +      authenticator.createUser(newUser.getPrincipal(), token);
 +      authorizor.initUser(newUser.getPrincipal());
 +      permHandle.initUser(newUser.getPrincipal());
 +      log.info("Created user " + newUser.getPrincipal() + " at the request of user " + credentials.getPrincipal());
 +      if (canChangeAuthorizations(credentials, newUser.getPrincipal()))
 +        authorizor.changeAuthorizations(newUser.getPrincipal(), authorizations);
 +    } catch (AccumuloSecurityException ase) {
 +      throw ase.asThriftException();
 +    }
 +  }
 +
 +  public void dropUser(TCredentials credentials, String user) throws ThriftSecurityException {
 +    if (!canDropUser(credentials, user))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    try {
 +      authorizor.dropUser(user);
 +      authenticator.dropUser(user);
 +      permHandle.cleanUser(user);
 +      log.info("Deleted user " + user + " at the request of user " + credentials.getPrincipal());
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public void grantSystemPermission(TCredentials credentials, String user, SystemPermission permissionById) throws ThriftSecurityException {
 +    if (!canGrantSystem(credentials, user, permissionById))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    targetUserExists(user);
 +
 +    try {
 +      permHandle.grantSystemPermission(user, permissionById);
 +      log.info("Granted system permission " + permissionById + " for user " + user + " at the request of user " + credentials.getPrincipal());
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public void grantTablePermission(TCredentials c, String user, String tableId, TablePermission permission, String namespaceId) throws ThriftSecurityException {
 +    if (!canGrantTable(c, user, tableId, namespaceId))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    targetUserExists(user);
 +
 +    try {
 +      permHandle.grantTablePermission(user, tableId, permission);
 +      log.info("Granted table permission " + permission + " for user " + user + " on the table " + tableId + " at the request of user " + c.getPrincipal());
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    } catch (TableNotFoundException e) {
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.TABLE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  public void grantNamespacePermission(TCredentials c, String user, String namespace, NamespacePermission permission) throws ThriftSecurityException {
 +    if (!canGrantNamespace(c, user, namespace))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    targetUserExists(user);
 +
 +    try {
 +      permHandle.grantNamespacePermission(user, namespace, permission);
 +      log.info("Granted namespace permission " + permission + " for user " + user + " on the namespace " + namespace + " at the request of user "
 +          + c.getPrincipal());
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    } catch (NamespaceNotFoundException e) {
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.NAMESPACE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  public void revokeSystemPermission(TCredentials credentials, String user, SystemPermission permission) throws ThriftSecurityException {
 +    if (!canRevokeSystem(credentials, user, permission))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    targetUserExists(user);
 +
 +    try {
 +      permHandle.revokeSystemPermission(user, permission);
 +      log.info("Revoked system permission " + permission + " for user " + user + " at the request of user " + credentials.getPrincipal());
 +
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public void revokeTablePermission(TCredentials c, String user, String tableId, TablePermission permission, String namespaceId) throws ThriftSecurityException {
 +    if (!canRevokeTable(c, user, tableId, namespaceId))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    targetUserExists(user);
 +
 +    try {
 +      permHandle.revokeTablePermission(user, tableId, permission);
 +      log.info("Revoked table permission " + permission + " for user " + user + " on the table " + tableId + " at the request of user " + c.getPrincipal());
 +
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    } catch (TableNotFoundException e) {
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.TABLE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  public void revokeNamespacePermission(TCredentials c, String user, String namespace, NamespacePermission permission) throws ThriftSecurityException {
 +    if (!canRevokeNamespace(c, user, namespace))
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +
 +    targetUserExists(user);
 +
 +    try {
 +      permHandle.revokeNamespacePermission(user, namespace, permission);
 +      log.info("Revoked namespace permission " + permission + " for user " + user + " on the namespace " + namespace + " at the request of user "
 +          + c.getPrincipal());
 +
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    } catch (NamespaceNotFoundException e) {
 +      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.NAMESPACE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  public boolean hasSystemPermission(TCredentials credentials, String user, SystemPermission permissionById) throws ThriftSecurityException {
 +    if (!canAskAboutOtherUsers(credentials, user))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    return _hasSystemPermission(user, permissionById, false);
 +  }
 +
 +  public boolean hasTablePermission(TCredentials credentials, String user, String tableId, TablePermission permissionById) throws ThriftSecurityException {
 +    if (!canAskAboutOtherUsers(credentials, user))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    return _hasTablePermission(user, tableId, permissionById, false);
 +  }
 +
 +  public boolean hasNamespacePermission(TCredentials credentials, String user, String namespace, NamespacePermission permissionById)
 +      throws ThriftSecurityException {
 +    if (!canAskAboutOtherUsers(credentials, user))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    return _hasNamespacePermission(user, namespace, permissionById, false);
 +  }
 +
 +  public Set<String> listUsers(TCredentials credentials) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    try {
 +      return authenticator.listUsers();
 +    } catch (AccumuloSecurityException e) {
 +      throw e.asThriftException();
 +    }
 +  }
 +
 +  public void deleteTable(TCredentials credentials, String tableId, String namespaceId) throws ThriftSecurityException {
 +    if (!canDeleteTable(credentials, tableId, namespaceId))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    try {
 +      permHandle.cleanTablePermissions(tableId);
 +    } catch (AccumuloSecurityException e) {
 +      e.setUser(credentials.getPrincipal());
 +      throw e.asThriftException();
 +    } catch (TableNotFoundException e) {
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.TABLE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  public void deleteNamespace(TCredentials credentials, String namespace) throws ThriftSecurityException {
 +    if (!canDeleteNamespace(credentials, namespace))
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
 +    try {
 +      permHandle.cleanNamespacePermissions(namespace);
 +    } catch (AccumuloSecurityException e) {
 +      e.setUser(credentials.getPrincipal());
 +      throw e.asThriftException();
 +    } catch (NamespaceNotFoundException e) {
 +      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.NAMESPACE_DOESNT_EXIST);
 +    }
 +  }
 +
 +  public boolean canExport(TCredentials credentials, String tableId, String tableName, String exportDir, String namespaceId) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasTablePermission(credentials, tableId, namespaceId, TablePermission.READ, false);
 +  }
 +
 +  public boolean canImport(TCredentials credentials, String tableName, String importDir, String namespaceId) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasSystemPermissionWithNamespaceId(credentials, SystemPermission.CREATE_TABLE, namespaceId, false);
 +  }
 +
 +  public boolean canAlterNamespace(TCredentials credentials, String namespaceId) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasSystemPermissionWithNamespaceId(credentials, SystemPermission.ALTER_NAMESPACE, namespaceId, false);
 +  }
 +
 +  public boolean canCreateNamespace(TCredentials credentials, String namespace) throws ThriftSecurityException {
 +    return canCreateNamespace(credentials);
 +  }
 +
 +  private boolean canCreateNamespace(TCredentials credentials) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasSystemPermission(credentials, SystemPermission.CREATE_NAMESPACE, false);
 +  }
 +
 +  public boolean canDeleteNamespace(TCredentials credentials, String namespaceId) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasSystemPermissionWithNamespaceId(credentials, SystemPermission.DROP_NAMESPACE, namespaceId, false);
 +  }
 +
 +  public boolean canRenameNamespace(TCredentials credentials, String namespaceId, String oldName, String newName) throws ThriftSecurityException {
 +    authenticate(credentials);
 +    return hasSystemPermissionWithNamespaceId(credentials, SystemPermission.ALTER_NAMESPACE, namespaceId, false);
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/base/src/main/java/org/apache/accumulo/server/security/SystemCredentials.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/security/SystemCredentials.java
index 19e7ff7,0000000..872fe11
mode 100644,000000..100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/SystemCredentials.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/SystemCredentials.java
@@@ -1,149 -1,0 +1,151 @@@
 +/*
 + * 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 static com.google.common.base.Charsets.UTF_8;
++
 +import java.io.ByteArrayOutputStream;
 +import java.io.DataOutputStream;
 +import java.io.IOException;
 +import java.security.MessageDigest;
 +import java.security.NoSuchAlgorithmException;
 +import java.security.SecurityPermission;
 +import java.util.Map.Entry;
 +
 +import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.Instance;
 +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
 +import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 +import org.apache.accumulo.core.conf.Property;
 +import org.apache.accumulo.core.security.Credentials;
 +import org.apache.accumulo.core.security.thrift.TCredentials;
 +import org.apache.accumulo.core.util.Base64;
 +import org.apache.accumulo.server.ServerConstants;
 +import org.apache.accumulo.server.client.HdfsZooInstance;
 +import org.apache.accumulo.server.conf.ServerConfiguration;
 +import org.apache.hadoop.io.Writable;
 +
 +/**
 + * Credentials for the system services.
 + * 
 + * @since 1.6.0
 + */
 +public final class SystemCredentials extends Credentials {
 +
 +  private static final SecurityPermission SYSTEM_CREDENTIALS_PERMISSION = new SecurityPermission("systemCredentialsPermission");
 +
 +  private static SystemCredentials SYSTEM_CREDS = null;
 +  private static final String SYSTEM_PRINCIPAL = "!SYSTEM";
 +
 +  private final TCredentials AS_THRIFT;
 +
 +  SystemCredentials(Instance instance) {
 +    super(SYSTEM_PRINCIPAL, SystemToken.get(instance));
 +    AS_THRIFT = super.toThrift(instance);
 +  }
 +
 +  public static SystemCredentials get() {
 +    check_permission();
 +    if (SYSTEM_CREDS == null) {
 +      SYSTEM_CREDS = new SystemCredentials(HdfsZooInstance.getInstance());
 +    }
 +    return SYSTEM_CREDS;
 +  }
 +
 +  private static void check_permission() {
 +    SecurityManager sm = System.getSecurityManager();
 +    if (sm != null) {
 +      sm.checkPermission(SYSTEM_CREDENTIALS_PERMISSION);
 +    }
 +  }
 +
 +  public static SystemCredentials get(Instance instance) {
 +    check_permission();
 +    /* Special case to avoid duplicating SYSTEM_CREDS */
 +    if (null != SYSTEM_CREDS) {
 +      if (SYSTEM_CREDS.AS_THRIFT.getInstanceId().equals(instance.getInstanceID())) {
 +        return SYSTEM_CREDS;
 +      }
 +    }
 +    return new SystemCredentials(instance);
 +  }
 +
 +  @Override
 +  public TCredentials toThrift(Instance instance) {
 +    if (!AS_THRIFT.getInstanceId().equals(instance.getInstanceID()))
 +      throw new IllegalArgumentException("Unexpected instance used for " + SystemCredentials.class.getSimpleName() + ": " + instance.getInstanceID());
 +    return AS_THRIFT;
 +  }
 +
 +  /**
 +   * An {@link AuthenticationToken} type for Accumulo servers for inter-server communication.
 +   * 
 +   * @since 1.6.0
 +   */
 +  public static final class SystemToken extends PasswordToken {
 +
 +    /**
 +     * A Constructor for {@link Writable}.
 +     */
 +    public SystemToken() {}
 +
 +    private SystemToken(byte[] systemPassword) {
 +      super(systemPassword);
 +    }
 +
 +    private static SystemToken get(Instance instance) {
-       byte[] instanceIdBytes = instance.getInstanceID().getBytes(Constants.UTF8);
++      byte[] instanceIdBytes = instance.getInstanceID().getBytes(UTF_8);
 +      byte[] confChecksum;
 +      MessageDigest md;
 +      try {
 +        md = MessageDigest.getInstance(Constants.PW_HASH_ALGORITHM);
 +      } catch (NoSuchAlgorithmException e) {
 +        throw new RuntimeException("Failed to compute configuration checksum", e);
 +      }
 +
 +      // seed the config with the version and instance id, so at least it's not empty
-       md.update(ServerConstants.WIRE_VERSION.toString().getBytes(Constants.UTF8));
++      md.update(ServerConstants.WIRE_VERSION.toString().getBytes(UTF_8));
 +      md.update(instanceIdBytes);
 +
 +      for (Entry<String,String> entry : ServerConfiguration.getSiteConfiguration()) {
 +        // only include instance properties
 +        if (entry.getKey().startsWith(Property.INSTANCE_PREFIX.toString())) {
-           md.update(entry.getKey().getBytes(Constants.UTF8));
-           md.update(entry.getValue().getBytes(Constants.UTF8));
++          md.update(entry.getKey().getBytes(UTF_8));
++          md.update(entry.getValue().getBytes(UTF_8));
 +        }
 +      }
 +      confChecksum = md.digest();
 +
 +      int wireVersion = ServerConstants.WIRE_VERSION;
 +
 +      ByteArrayOutputStream bytes = new ByteArrayOutputStream(3 * (Integer.SIZE / Byte.SIZE) + instanceIdBytes.length + confChecksum.length);
 +      DataOutputStream out = new DataOutputStream(bytes);
 +      try {
 +        out.write(wireVersion * -1);
 +        out.write(instanceIdBytes.length);
 +        out.write(instanceIdBytes);
 +        out.write(confChecksum.length);
 +        out.write(confChecksum);
 +      } catch (IOException e) {
 +        // this is impossible with ByteArrayOutputStream; crash hard if this happens
 +        throw new RuntimeException(e);
 +      }
 +      return new SystemToken(Base64.encodeBase64(bytes.toByteArray()));
 +    }
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
index 5f6ff71,0000000..fa1632c
mode 100644,000000..100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
@@@ -1,214 -1,0 +1,216 @@@
 +/*
 + * 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.handler;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.util.HashSet;
 +import java.util.Set;
 +import java.util.TreeSet;
 +
 +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.thrift.SecurityErrorCode;
 +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
 +import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 +import org.apache.accumulo.core.security.thrift.TCredentials;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
 +import org.apache.accumulo.server.zookeeper.ZooCache;
 +import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
 +import org.apache.log4j.Logger;
 +import org.apache.zookeeper.KeeperException;
 +
 +// Utility class for adding all authentication info into ZK
 +public final class ZKAuthenticator implements Authenticator {
 +  static final Logger log = Logger.getLogger(ZKAuthenticator.class);
 +  private static Authenticator zkAuthenticatorInstance = null;
 +
 +  private String ZKUserPath;
 +  private final ZooCache zooCache;
 +
 +  public static synchronized Authenticator getInstance() {
 +    if (zkAuthenticatorInstance == null)
 +      zkAuthenticatorInstance = new ZKAuthenticator();
 +    return zkAuthenticatorInstance;
 +  }
 +
 +  public ZKAuthenticator() {
 +    zooCache = new ZooCache();
 +  }
 +
 +  @Override
 +  public void initialize(String instanceId, boolean initialize) {
 +    ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
 +  }
 +
 +  @Override
 +  public void initializeSecurity(TCredentials credentials, String principal, byte[] token) throws AccumuloSecurityException {
 +    try {
 +      // remove old settings from zookeeper first, if any
 +      IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +      synchronized (zooCache) {
 +        zooCache.clear();
 +        if (zoo.exists(ZKUserPath)) {
 +          zoo.recursiveDelete(ZKUserPath, NodeMissingPolicy.SKIP);
 +          log.info("Removed " + ZKUserPath + "/" + " from zookeeper");
 +        }
 +
 +        // prep parent node of users with root username
-         zoo.putPersistentData(ZKUserPath, principal.getBytes(Constants.UTF8), NodeExistsPolicy.FAIL);
++        zoo.putPersistentData(ZKUserPath, principal.getBytes(UTF_8), NodeExistsPolicy.FAIL);
 +
 +        constructUser(principal, ZKSecurityTool.createPass(token));
 +      }
 +    } 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) throws KeeperException, InterruptedException {
 +    synchronized (zooCache) {
 +      zooCache.clear();
 +      IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +      zoo.putPrivatePersistentData(ZKUserPath + "/" + user, pass, NodeExistsPolicy.FAIL);
 +    }
 +  }
 +
 +  @Override
 +  public Set<String> listUsers() {
 +    return new TreeSet<String>(zooCache.getChildren(ZKUserPath));
 +  }
 +
 +  /**
 +   * Creates a user with no permissions whatsoever
 +   */
 +  @Override
 +  public void createUser(String principal, AuthenticationToken token) throws AccumuloSecurityException {
 +    try {
 +      if (!(token instanceof PasswordToken))
 +        throw new AccumuloSecurityException(principal, SecurityErrorCode.INVALID_TOKEN);
 +      PasswordToken pt = (PasswordToken) token;
 +      constructUser(principal, ZKSecurityTool.createPass(pt.getPassword()));
 +    } catch (KeeperException e) {
 +      if (e.code().equals(KeeperException.Code.NODEEXISTS))
 +        throw new AccumuloSecurityException(principal, SecurityErrorCode.USER_EXISTS, e);
 +      throw new AccumuloSecurityException(principal, 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(principal, SecurityErrorCode.DEFAULT_SECURITY_ERROR, e);
 +    }
 +  }
 +
 +  @Override
 +  public void dropUser(String user) throws AccumuloSecurityException {
 +    try {
 +      synchronized (zooCache) {
 +        zooCache.clear();
 +        ZooReaderWriter.getInstance().recursiveDelete(ZKUserPath + "/" + user, NodeMissingPolicy.FAIL);
 +      }
 +    } catch (InterruptedException e) {
 +      log.error(e, e);
 +      throw new RuntimeException(e);
 +    } catch (KeeperException e) {
 +      if (e.code().equals(KeeperException.Code.NONODE))
 +        throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST, e);
 +      log.error(e, e);
 +      throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
 +    }
 +  }
 +
 +  @Override
 +  public void changePassword(String principal, AuthenticationToken token) throws AccumuloSecurityException {
 +    if (!(token instanceof PasswordToken))
 +      throw new AccumuloSecurityException(principal, SecurityErrorCode.INVALID_TOKEN);
 +    PasswordToken pt = (PasswordToken) token;
 +    if (userExists(principal)) {
 +      try {
 +        synchronized (zooCache) {
 +          zooCache.clear(ZKUserPath + "/" + principal);
 +          ZooReaderWriter.getInstance().putPrivatePersistentData(ZKUserPath + "/" + principal, ZKSecurityTool.createPass(pt.getPassword()),
 +              NodeExistsPolicy.OVERWRITE);
 +        }
 +      } catch (KeeperException e) {
 +        log.error(e, e);
 +        throw new AccumuloSecurityException(principal, 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(principal, SecurityErrorCode.DEFAULT_SECURITY_ERROR, e);
 +      }
 +    } else
 +      throw new AccumuloSecurityException(principal, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
 +  }
 +
 +  /**
 +   * Checks if a user exists
 +   */
 +  @Override
 +  public boolean userExists(String user) {
 +    return zooCache.get(ZKUserPath + "/" + user) != null;
 +  }
 +
 +  @Override
 +  public boolean validSecurityHandlers(Authorizor auth, PermissionHandler pm) {
 +    return true;
 +  }
 +
 +  @Override
 +  public boolean authenticateUser(String principal, AuthenticationToken token) throws AccumuloSecurityException {
 +    if (!(token instanceof PasswordToken))
 +      throw new AccumuloSecurityException(principal, SecurityErrorCode.INVALID_TOKEN);
 +    PasswordToken pt = (PasswordToken) token;
 +    byte[] pass;
 +    String zpath = ZKUserPath + "/" + principal;
 +    pass = zooCache.get(zpath);
 +    boolean result = ZKSecurityTool.checkPass(pt.getPassword(), pass);
 +    if (!result) {
 +      zooCache.clear(zpath);
 +      pass = zooCache.get(zpath);
 +      result = ZKSecurityTool.checkPass(pt.getPassword(), pass);
 +    }
 +    return result;
 +  }
 +
 +  @Override
 +  public Set<Class<? extends AuthenticationToken>> getSupportedTokenTypes() {
 +    Set<Class<? extends AuthenticationToken>> cs = new HashSet<Class<? extends AuthenticationToken>>();
 +    cs.add(PasswordToken.class);
 +    return cs;
 +  }
 +
 +  @Override
 +  public boolean validTokenClass(String tokenClass) {
 +    return tokenClass.equals(PasswordToken.class.getName());
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
index 75b73fc,0000000..78597ad
mode 100644,000000..100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
@@@ -1,171 -1,0 +1,172 @@@
 +/*
 + * 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.handler;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.nio.ByteBuffer;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import java.util.TreeSet;
 +
- import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.AccumuloSecurityException;
 +import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
 +import org.apache.accumulo.core.metadata.MetadataTable;
 +import org.apache.accumulo.core.metadata.RootTable;
 +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.TCredentials;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
 +import org.apache.accumulo.server.zookeeper.ZooCache;
 +import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
 +import org.apache.log4j.Logger;
 +import org.apache.zookeeper.KeeperException;
 +
 +public class ZKAuthorizor implements Authorizor {
 +  private static final Logger log = Logger.getLogger(ZKAuthorizor.class);
 +  private static Authorizor zkAuthorizorInstance = null;
 +
 +  private final String ZKUserAuths = "/Authorizations";
 +
 +  private String ZKUserPath;
 +  private final ZooCache zooCache;
 +
 +  public static synchronized Authorizor getInstance() {
 +    if (zkAuthorizorInstance == null)
 +      zkAuthorizorInstance = new ZKAuthorizor();
 +    return zkAuthorizorInstance;
 +  }
 +
 +  public ZKAuthorizor() {
 +    zooCache = new ZooCache();
 +  }
 +
 +  @Override
 +  public void initialize(String instanceId, boolean initialize) {
 +    ZKUserPath = ZKSecurityTool.getInstancePath(instanceId) + "/users";
 +  }
 +
 +  @Override
 +  public Authorizations getCachedUserAuthorizations(String user) {
 +    byte[] authsBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserAuths);
 +    if (authsBytes != null)
 +      return ZKSecurityTool.convertAuthorizations(authsBytes);
 +    return Authorizations.EMPTY;
 +  }
 +
 +  @Override
 +  public boolean validSecurityHandlers(Authenticator auth, PermissionHandler pm) {
 +    return true;
 +  }
 +
 +  @Override
 +  public void initializeSecurity(TCredentials itw, String rootuser) throws AccumuloSecurityException {
 +    IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +
 +    // 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 tables
 +    tablePerms.put(MetadataTable.ID, Collections.singleton(TablePermission.ALTER_TABLE));
 +    tablePerms.put(RootTable.ID, Collections.singleton(TablePermission.ALTER_TABLE));
 +
 +    try {
 +      // prep parent node of users with root username
 +      if (!zoo.exists(ZKUserPath))
-         zoo.putPersistentData(ZKUserPath, rootuser.getBytes(Constants.UTF8), NodeExistsPolicy.FAIL);
++        zoo.putPersistentData(ZKUserPath, rootuser.getBytes(UTF_8), NodeExistsPolicy.FAIL);
 +
 +      initUser(rootuser);
 +      zoo.putPersistentData(ZKUserPath + "/" + rootuser + ZKUserAuths, ZKSecurityTool.convertAuthorizations(Authorizations.EMPTY), NodeExistsPolicy.FAIL);
 +    } catch (KeeperException e) {
 +      log.error(e, e);
 +      throw new RuntimeException(e);
 +    } catch (InterruptedException e) {
 +      log.error(e, e);
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  @Override
 +  public void initUser(String user) throws AccumuloSecurityException {
 +    IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +    try {
 +      zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
 +    } 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);
 +    }
 +  }
 +
 +  @Override
 +  public void dropUser(String user) throws AccumuloSecurityException {
 +    try {
 +      synchronized (zooCache) {
 +        IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +        zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserAuths, NodeMissingPolicy.SKIP);
 +        zooCache.clear(ZKUserPath + "/" + 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);
 +
 +    }
 +  }
 +
 +  @Override
 +  public void changeAuthorizations(String user, Authorizations authorizations) throws AccumuloSecurityException {
 +    try {
 +      synchronized (zooCache) {
 +        zooCache.clear();
 +        ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, ZKSecurityTool.convertAuthorizations(authorizations),
 +            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);
 +    }
 +  }
 +
 +  @Override
 +  public boolean isValidAuthorizations(String user, List<ByteBuffer> auths) throws AccumuloSecurityException {
 +    Collection<ByteBuffer> userauths = getCachedUserAuthorizations(user).getAuthorizationsBB();
 +    for (ByteBuffer auth : auths)
 +      if (!userauths.contains(auth))
 +        return false;
 +    return true;
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
index be4806b,0000000..41f880d
mode 100644,000000..100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
@@@ -1,515 -1,0 +1,516 @@@
 +/*
 + * 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.handler;
 +
++import static com.google.common.base.Charsets.UTF_8;
++
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.Map;
 +import java.util.Map.Entry;
 +import java.util.Set;
 +import java.util.TreeSet;
 +
- import org.apache.accumulo.core.Constants;
 +import org.apache.accumulo.core.client.AccumuloSecurityException;
 +import org.apache.accumulo.core.client.NamespaceNotFoundException;
 +import org.apache.accumulo.core.client.TableNotFoundException;
 +import org.apache.accumulo.core.client.impl.Namespaces;
 +import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
 +import org.apache.accumulo.core.metadata.MetadataTable;
 +import org.apache.accumulo.core.metadata.RootTable;
 +import org.apache.accumulo.core.security.NamespacePermission;
 +import org.apache.accumulo.core.security.SystemPermission;
 +import org.apache.accumulo.core.security.TablePermission;
 +import org.apache.accumulo.core.security.thrift.TCredentials;
 +import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 +import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
 +import org.apache.accumulo.server.zookeeper.ZooCache;
 +import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
 +import org.apache.log4j.Logger;
 +import org.apache.zookeeper.KeeperException;
 +import org.apache.zookeeper.KeeperException.Code;
 +
 +/**
 + *
 + */
 +public class ZKPermHandler implements PermissionHandler {
 +  private static final Logger log = Logger.getLogger(ZKAuthorizor.class);
 +  private static PermissionHandler zkPermHandlerInstance = null;
 +
 +  private String ZKUserPath;
 +  private String ZKTablePath;
 +  private String ZKNamespacePath;
 +  private final ZooCache zooCache;
 +  private final String ZKUserSysPerms = "/System";
 +  private final String ZKUserTablePerms = "/Tables";
 +  private final String ZKUserNamespacePerms = "/Namespaces";
 +
 +  public static synchronized PermissionHandler getInstance() {
 +    if (zkPermHandlerInstance == null)
 +      zkPermHandlerInstance = new ZKPermHandler();
 +    return zkPermHandlerInstance;
 +  }
 +
 +  @Override
 +  public void initialize(String instanceId, boolean initialize) {
 +    ZKUserPath = ZKSecurityTool.getInstancePath(instanceId) + "/users";
 +    ZKTablePath = ZKSecurityTool.getInstancePath(instanceId) + "/tables";
 +    ZKNamespacePath = ZKSecurityTool.getInstancePath(instanceId) + "/namespaces";
 +  }
 +
 +  public ZKPermHandler() {
 +    zooCache = new ZooCache();
 +  }
 +
 +  @Override
 +  public boolean hasTablePermission(String user, String table, TablePermission permission) throws TableNotFoundException {
 +    byte[] serializedPerms;
 +    final ZooReaderWriter zrw = ZooReaderWriter.getInstance();
 +    try {
 +      String path = ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table;
 +      zrw.sync(path);
 +      serializedPerms = zrw.getData(path, null);
 +    } catch (KeeperException e) {
 +      if (e.code() == Code.NONODE) {
 +        // maybe the table was just deleted?
 +        try {
 +          // check for existence:
 +          zrw.getData(ZKTablePath + "/" + table, null);
 +          // it's there, you don't have permission
 +          return false;
 +        } catch (InterruptedException ex) {
 +          log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
 +          return false;
 +        } catch (KeeperException ex) {
 +          // not there, throw an informative exception
 +          if (e.code() == Code.NONODE) {
 +            throw new TableNotFoundException(null, table, "while checking permissions");
 +          }
 +          log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
 +        }
 +        return false;
 +      }
 +      log.warn("Unhandled KeeperException, failing closed for table permission check", e);
 +      return false;
 +    } catch (InterruptedException e) {
 +      log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
 +      return false;
 +    }
 +    if (serializedPerms != null) {
 +      return ZKSecurityTool.convertTablePermissions(serializedPerms).contains(permission);
 +    }
 +    return false;
 +  }
 +
 +  @Override
 +  public boolean hasCachedTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException, TableNotFoundException {
 +    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
 +    if (serializedPerms != null) {
 +      return ZKSecurityTool.convertTablePermissions(serializedPerms).contains(permission);
 +    }
 +    return false;
 +  }
 +
 +  @Override
 +  public boolean hasNamespacePermission(String user, String namespace, NamespacePermission permission) throws NamespaceNotFoundException {
 +    byte[] serializedPerms;
 +    final ZooReaderWriter zrw = ZooReaderWriter.getInstance();
 +    try {
 +      String path = ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace;
 +      zrw.sync(path);
 +      serializedPerms = zrw.getData(path, null);
 +    } catch (KeeperException e) {
 +      if (e.code() == Code.NONODE) {
 +        // maybe the namespace was just deleted?
 +        try {
 +          // check for existence:
 +          zrw.getData(ZKNamespacePath + "/" + namespace, null);
 +          // it's there, you don't have permission
 +          return false;
 +        } catch (InterruptedException ex) {
 +          log.warn("Unhandled InterruptedException, failing closed for namespace permission check", e);
 +          return false;
 +        } catch (KeeperException ex) {
 +          // not there, throw an informative exception
 +          if (e.code() == Code.NONODE) {
 +            throw new NamespaceNotFoundException(null, namespace, "while checking permissions");
 +          }
 +          log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
 +        }
 +        return false;
 +      }
 +      log.warn("Unhandled KeeperException, failing closed for table permission check", e);
 +      return false;
 +    } catch (InterruptedException e) {
 +      log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
 +      return false;
 +    }
 +    if (serializedPerms != null) {
 +      return ZKSecurityTool.convertNamespacePermissions(serializedPerms).contains(permission);
 +    }
 +    return false;
 +  }
 +
 +  @Override
 +  public boolean hasCachedNamespacePermission(String user, String namespace, NamespacePermission permission) throws AccumuloSecurityException,
 +      NamespaceNotFoundException {
 +    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
 +    if (serializedPerms != null) {
 +      return ZKSecurityTool.convertNamespacePermissions(serializedPerms).contains(permission);
 +    }
 +    return false;
 +  }
 +
 +  @Override
 +  public void grantSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
 +    try {
 +      byte[] permBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
 +      Set<SystemPermission> perms;
 +      if (permBytes == null) {
 +        perms = new TreeSet<SystemPermission>();
 +      } else {
 +        perms = ZKSecurityTool.convertSystemPermissions(permBytes);
 +      }
 +
 +      if (perms.add(permission)) {
 +        synchronized (zooCache) {
 +          zooCache.clear();
 +          ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(perms),
 +              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);
 +    }
 +  }
 +
 +  @Override
 +  public void grantTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException {
 +    Set<TablePermission> tablePerms;
 +    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
 +    if (serializedPerms != null)
 +      tablePerms = ZKSecurityTool.convertTablePermissions(serializedPerms);
 +    else
 +      tablePerms = new TreeSet<TablePermission>();
 +
 +    try {
 +      if (tablePerms.add(permission)) {
 +        synchronized (zooCache) {
 +          zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
 +          ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
 +              ZKSecurityTool.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);
 +    }
 +  }
 +
 +  @Override
 +  public void grantNamespacePermission(String user, String namespace, NamespacePermission permission) throws AccumuloSecurityException {
 +    Set<NamespacePermission> namespacePerms;
 +    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
 +    if (serializedPerms != null)
 +      namespacePerms = ZKSecurityTool.convertNamespacePermissions(serializedPerms);
 +    else
 +      namespacePerms = new TreeSet<NamespacePermission>();
 +
 +    try {
 +      if (namespacePerms.add(permission)) {
 +        synchronized (zooCache) {
 +          zooCache.clear(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
 +          ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
 +              ZKSecurityTool.convertNamespacePermissions(namespacePerms),
 +              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);
 +    }
 +  }
 +
 +  @Override
 +  public void revokeSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
 +    byte[] sysPermBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
 +
 +    // User had no system permission, nothing to revoke.
 +    if (sysPermBytes == null)
 +      return;
 +
 +    Set<SystemPermission> sysPerms = ZKSecurityTool.convertSystemPermissions(sysPermBytes);
 +
 +    try {
 +      if (sysPerms.remove(permission)) {
 +        synchronized (zooCache) {
 +          zooCache.clear();
 +          ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(sysPerms),
 +              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);
 +    }
 +  }
 +
 +  @Override
 +  public void revokeTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException {
 +    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
 +
 +    // User had no table permission, nothing to revoke.
 +    if (serializedPerms == null)
 +      return;
 +
 +    Set<TablePermission> tablePerms = ZKSecurityTool.convertTablePermissions(serializedPerms);
 +    try {
 +      if (tablePerms.remove(permission)) {
 +        zooCache.clear();
 +        IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +        if (tablePerms.size() == 0)
 +          zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
 +        else
 +          zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, ZKSecurityTool.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);
 +    }
 +  }
 +
 +  @Override
 +  public void revokeNamespacePermission(String user, String namespace, NamespacePermission permission) throws AccumuloSecurityException {
 +    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
 +
 +    // User had no namespace permission, nothing to revoke.
 +    if (serializedPerms == null)
 +      return;
 +
 +    Set<NamespacePermission> namespacePerms = ZKSecurityTool.convertNamespacePermissions(serializedPerms);
 +    try {
 +      if (namespacePerms.remove(permission)) {
 +        zooCache.clear();
 +        IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +        if (namespacePerms.size() == 0)
 +          zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, NodeMissingPolicy.SKIP);
 +        else
 +          zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, ZKSecurityTool.convertNamespacePermissions(namespacePerms),
 +              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);
 +    }
 +  }
 +
 +  @Override
 +  public void cleanTablePermissions(String table) throws AccumuloSecurityException {
 +    try {
 +      synchronized (zooCache) {
 +        zooCache.clear();
 +        IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +        for (String user : zooCache.getChildren(ZKUserPath))
 +          zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
 +      }
 +    } catch (KeeperException e) {
 +      log.error(e, e);
 +      throw new AccumuloSecurityException("unknownUser", SecurityErrorCode.CONNECTION_ERROR, e);
 +    } catch (InterruptedException e) {
 +      log.error(e, e);
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  @Override
 +  public void cleanNamespacePermissions(String namespace) throws AccumuloSecurityException {
 +    try {
 +      synchronized (zooCache) {
 +        zooCache.clear();
 +        IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +        for (String user : zooCache.getChildren(ZKUserPath))
 +          zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, NodeMissingPolicy.SKIP);
 +      }
 +    } catch (KeeperException e) {
 +      log.error(e, e);
 +      throw new AccumuloSecurityException("unknownUser", SecurityErrorCode.CONNECTION_ERROR, e);
 +    } catch (InterruptedException e) {
 +      log.error(e, e);
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  @Override
 +  public void initializeSecurity(TCredentials itw, String rootuser) throws AccumuloSecurityException {
 +    IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +
 +    // 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 system tables
 +    tablePerms.put(RootTable.ID, Collections.singleton(TablePermission.ALTER_TABLE));
 +    tablePerms.put(MetadataTable.ID, Collections.singleton(TablePermission.ALTER_TABLE));
 +    // essentially the same but on the system namespace, the ALTER_TABLE permission is now redundant
 +    Map<String,Set<NamespacePermission>> namespacePerms = new HashMap<String,Set<NamespacePermission>>();
 +    namespacePerms.put(Namespaces.ACCUMULO_NAMESPACE_ID, Collections.singleton(NamespacePermission.ALTER_NAMESPACE));
 +    namespacePerms.put(Namespaces.ACCUMULO_NAMESPACE_ID, Collections.singleton(NamespacePermission.ALTER_TABLE));
 +
 +    try {
 +      // prep parent node of users with root username
 +      if (!zoo.exists(ZKUserPath))
-         zoo.putPersistentData(ZKUserPath, rootuser.getBytes(Constants.UTF8), NodeExistsPolicy.FAIL);
++        zoo.putPersistentData(ZKUserPath, rootuser.getBytes(UTF_8), NodeExistsPolicy.FAIL);
 +
 +      initUser(rootuser);
 +      zoo.putPersistentData(ZKUserPath + "/" + rootuser + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(rootPerms), NodeExistsPolicy.FAIL);
 +      for (Entry<String,Set<TablePermission>> entry : tablePerms.entrySet())
 +        createTablePerm(rootuser, entry.getKey(), entry.getValue());
 +      for (Entry<String,Set<NamespacePermission>> entry : namespacePerms.entrySet())
 +        createNamespacePerm(rootuser, entry.getKey(), entry.getValue());
 +    } catch (KeeperException e) {
 +      log.error(e, e);
 +      throw new RuntimeException(e);
 +    } catch (InterruptedException e) {
 +      log.error(e, e);
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  @Override
 +  public void initUser(String user) throws AccumuloSecurityException {
 +    IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +    try {
 +      zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
 +      zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms, new byte[0], NodeExistsPolicy.SKIP);
 +      zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms, new byte[0], NodeExistsPolicy.SKIP);
 +    } 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);
 +    }
 +  }
 +
 +  /**
 +   * Sets up a new table configuration for the provided user/table. No checking for existence 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();
 +      ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
 +          ZKSecurityTool.convertTablePermissions(perms), NodeExistsPolicy.FAIL);
 +    }
 +  }
 +
 +  /**
 +   * Sets up a new namespace configuration for the provided user/table. No checking for existence is done here, it should be done before calling.
 +   */
 +  private void createNamespacePerm(String user, String namespace, Set<NamespacePermission> perms) throws KeeperException, InterruptedException {
 +    synchronized (zooCache) {
 +      zooCache.clear();
 +      ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
 +          ZKSecurityTool.convertNamespacePermissions(perms), NodeExistsPolicy.FAIL);
 +    }
 +  }
 +
 +  @Override
 +  public void cleanUser(String user) throws AccumuloSecurityException {
 +    try {
 +      synchronized (zooCache) {
 +        IZooReaderWriter zoo = ZooReaderWriter.getInstance();
 +        zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserSysPerms, NodeMissingPolicy.SKIP);
 +        zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms, NodeMissingPolicy.SKIP);
 +        zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms, NodeMissingPolicy.SKIP);
 +        zooCache.clear(ZKUserPath + "/" + 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);
 +
 +    }
 +  }
 +
 +  @Override
 +  public boolean hasSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
 +    byte[] perms;
 +    try {
 +      String path = ZKUserPath + "/" + user + ZKUserSysPerms;
 +      ZooReaderWriter.getInstance().sync(path);
 +      perms = ZooReaderWriter.getInstance().getData(path, null);
 +    } catch (KeeperException e) {
 +      if (e.code() == Code.NONODE) {
 +        return false;
 +      }
 +      log.warn("Unhandled KeeperException, failing closed for table permission check", e);
 +      return false;
 +    } catch (InterruptedException e) {
 +      log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
 +      return false;
 +    }
 +
 +    if (perms == null)
 +      return false;
 +    return ZKSecurityTool.convertSystemPermissions(perms).contains(permission);
 +  }
 +
 +  @Override
 +  public boolean hasCachedSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
 +    byte[] perms = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
 +    if (perms == null)
 +      return false;
 +    return ZKSecurityTool.convertSystemPermissions(perms).contains(permission);
 +  }
 +
 +  @Override
 +  public boolean validSecurityHandlers(Authenticator authent, Authorizor author) {
 +    return true;
 +  }
 +
 +  @Override
 +  public void initTable(String table) throws AccumuloSecurityException {
 +    // All proper housekeeping is done on delete and permission granting, no work needs to be done here
 +  }
 +}


Mime
View raw message