You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by el...@apache.org on 2014/02/04 18:55:13 UTC
[44/48] Merge branch '1.5.1-SNAPSHOT' into 1.6.0-SNAPSHOT
http://git-wip-us.apache.org/repos/asf/accumulo/blob/7688eaf0/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 d44d3da,0000000..f8b1702
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,787 -1,0 +1,787 @@@
+/*
+ * 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.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.admin.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.client.security.tokens.AuthenticationToken.AuthenticationTokenSerializer;
+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;
+
- protected static SecurityOperation instance;
++ 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));
++ rootUserName = new String(zooCache.get(ZKUserPath), Constants.UTF8);
+ return rootUserName;
+ }
+
+ public boolean isSystemUser(TCredentials credentials) {
+ return SystemCredentials.get().getToken().getClass().getName().equals(credentials.getTokenClassName());
+ }
+
+ private void authenticate(TCredentials credentials) throws ThriftSecurityException {
+ if (!credentials.getInstanceId().equals(HdfsZooInstance.getInstance().getInstanceID()))
+ throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.INVALID_INSTANCEID);
+
+ if (isSystemUser(credentials)) {
+ authenticateSystemUser(credentials);
+ } else {
+ try {
+ AuthenticationToken token = AuthenticationTokenSerializer.deserialize(credentials.getTokenClassName(), credentials.getToken());
+ if (!authenticator.authenticateUser(credentials.getPrincipal(), token)) {
+ throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.BAD_CREDENTIALS);
+ }
+ } catch (AccumuloSecurityException e) {
+ log.debug(e);
+ throw e.asThriftException();
+ }
+ }
+ }
+
+ private void authenticateSystemUser(TCredentials credentials) throws ThriftSecurityException {
+ if (SystemCredentials.get().getToken().equals(credentials.getToken()))
+ throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.BAD_CREDENTIALS);
+ }
+
+ 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 {
+ AuthenticationToken token = reassembleToken(toAuth);
+ return authenticator.authenticateUser(toAuth.getPrincipal(), token);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+
+ private AuthenticationToken reassembleToken(TCredentials toAuth) throws AccumuloSecurityException {
+ String tokenClass = toAuth.getTokenClassName();
+ if (authenticator.validTokenClass(tokenClass)) {
+ return AuthenticationTokenSerializer.deserialize(toAuth.getTokenClassName(), toAuth.getToken());
+ }
+ throw new AccumuloSecurityException(toAuth.getPrincipal(), SecurityErrorCode.INVALID_TOKEN);
+ }
+
+ 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/7688eaf0/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 4e327ec,0000000..1646a28
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,214 @@@
+/*
+ * 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 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.getRetryingInstance();
+ 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(), NodeExistsPolicy.FAIL);
++ zoo.putPersistentData(ZKUserPath, principal.getBytes(Constants.UTF8), 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.getRetryingInstance();
+ 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.getRetryingInstance().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.getRetryingInstance().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/7688eaf0/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 482a669,0000000..34d43f2
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,174 -1,0 +1,175 @@@
+/*
+ * 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 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.getRetryingInstance();
+
+ // 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(), NodeExistsPolicy.FAIL);
++ zoo.putPersistentData(ZKUserPath, rootuser.getBytes(Constants.UTF8), 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);
+ }
+ }
+
+ /**
+ * @param user
+ * @throws AccumuloSecurityException
+ */
+ @Override
+ public void initUser(String user) throws AccumuloSecurityException {
+ IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ 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.getRetryingInstance();
+ 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.getRetryingInstance().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/7688eaf0/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 0ea556f,0000000..6319653
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,516 -1,0 +1,517 @@@
+/*
+ * 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 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;
+ try {
+ String path = ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table;
+ ZooReaderWriter.getRetryingInstance().sync(path);
+ serializedPerms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ } catch (KeeperException e) {
+ if (e.code() == Code.NONODE) {
+ // maybe the table was just deleted?
+ try {
+ // check for existence:
+ ZooReaderWriter.getRetryingInstance().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;
+ try {
+ String path = ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace;
+ ZooReaderWriter.getRetryingInstance().sync(path);
+ serializedPerms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ } catch (KeeperException e) {
+ if (e.code() == Code.NONODE) {
+ // maybe the namespace was just deleted?
+ try {
+ // check for existence:
+ ZooReaderWriter.getRetryingInstance().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.getRetryingInstance().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);
+ IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ 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 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);
+ IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ 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 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.getRetryingInstance().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.getRetryingInstance();
+ 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.getRetryingInstance();
+ 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.getRetryingInstance();
+ 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.getRetryingInstance();
+ 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.getRetryingInstance();
+
+ // 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(), NodeExistsPolicy.FAIL);
++ zoo.putPersistentData(ZKUserPath, rootuser.getBytes(Constants.UTF8), 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);
+ }
+ }
+
+ /**
+ * @param user
+ * @throws AccumuloSecurityException
+ */
+ @Override
+ public void initUser(String user) throws AccumuloSecurityException {
+ IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ 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.getRetryingInstance().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.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
+ ZKSecurityTool.convertNamespacePermissions(perms), NodeExistsPolicy.FAIL);
+ }
+ }
+
+ @Override
+ public void cleanUser(String user) throws AccumuloSecurityException {
+ try {
+ synchronized (zooCache) {
+ IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ 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.getRetryingInstance().sync(path);
+ perms = ZooReaderWriter.getRetryingInstance().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
+ }
+}