You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by vi...@apache.org on 2012/06/05 21:02:31 UTC
svn commit: r1346535 [2/3] - in /accumulo/branches/ACCUMULO-259:
core/src/main/java/org/apache/accumulo/core/client/
core/src/main/java/org/apache/accumulo/core/conf/
server/src/main/java/org/apache/accumulo/server/client/
server/src/main/java/org/apac...
Added: accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/SecurityOperationImpl.java
URL: http://svn.apache.org/viewvc/accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/SecurityOperationImpl.java?rev=1346535&view=auto
==============================================================================
--- accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/SecurityOperationImpl.java (added)
+++ accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/SecurityOperationImpl.java Tue Jun 5 19:02:30 2012
@@ -0,0 +1,817 @@
+/**
+ * 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.Arrays;
+import java.util.Set;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.admin.SecurityOperationsImpl;
+import org.apache.accumulo.core.client.impl.thrift.ThriftTableOperationException;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TablePermission;
+import org.apache.accumulo.core.security.thrift.AuthInfo;
+import org.apache.accumulo.core.security.thrift.SecurityErrorCode;
+import org.apache.accumulo.core.security.thrift.ThriftSecurityException;
+import org.apache.accumulo.server.client.HdfsZooInstance;
+import org.apache.accumulo.server.master.Master;
+import org.apache.accumulo.server.zookeeper.ZooCache;
+import org.apache.log4j.Logger;
+
+/**
+ * Utility class for performing various security operations with the appropriate checks
+ */
+public class SecurityOperationImpl implements SecurityOperation {
+ private static final Logger log = Logger.getLogger(SecurityOperationsImpl.class);
+
+ private static Authorizor authorizor;
+ private static Authenticator authenticator;
+ private static String rootUserName = null;
+ private final ZooCache zooCache;
+ private final String ZKUserPath;
+
+ private static SecurityOperation instance;
+
+ public static synchronized SecurityOperation getInstance() {
+ String instanceId = HdfsZooInstance.getInstance().getInstanceID();
+ return getInstance(instanceId);
+ }
+
+ public static synchronized SecurityOperation getInstance(String instanceId) {
+ if (instance == null) {
+ instance = new AuditedSecurityOperation(new SecurityOperationImpl(getAuthorizor(instanceId), getAuthenticator(instanceId), instanceId));
+ }
+ return instance;
+ }
+
+ @SuppressWarnings("deprecation")
+ private static Authorizor getAuthorizor(String instanceId) {
+ Authorizor toRet = Master.createInstanceFromPropertyName(AccumuloConfiguration.getSiteConfiguration(), Property.INSTANCE_SECURITY_AUTHORIZOR,
+ Authorizor.class, ZKAuthorizor.getInstance());
+ toRet.initialize(instanceId);
+ return toRet;
+ }
+
+ @SuppressWarnings("deprecation")
+ private static Authenticator getAuthenticator(String instanceId) {
+ Authenticator toRet = Master.createInstanceFromPropertyName(AccumuloConfiguration.getSiteConfiguration(), Property.INSTANCE_SECURITY_AUTHENTICATOR,
+ Authenticator.class, ZKAuthenticator.getInstance());
+ toRet.initialize(instanceId);
+ return toRet;
+ }
+
+ public SecurityOperationImpl(Authorizor author, Authenticator authent, String instanceId) {
+ authorizor = author;
+ authenticator = authent;
+
+ if (!authorizor.validAuthenticator(authenticator) || !authenticator.validAuthorizor(authorizor))
+ throw new RuntimeException(authorizor + " and " + authenticator
+ + " do not play nice with eachother. Please choose authentication and authorization mechanisms that are compatible with one another.");
+
+ ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
+ zooCache = new ZooCache();
+ }
+
+ public void initializeSecurity(AuthInfo credentials, String rootuser, byte[] rootpass) throws AccumuloSecurityException, ThriftSecurityException {
+ authenticate(credentials);
+
+ if (!credentials.user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ authenticator.initializeSecurity(credentials, rootuser, rootpass);
+ authorizor.initializeSecurity(rootuser);
+ }
+
+ public synchronized String getRootUsername() {
+ if (rootUserName == null)
+ rootUserName = new String(zooCache.get(ZKUserPath));
+ return rootUserName;
+ }
+
+ private void authenticate(String user, ByteBuffer password, String instance) throws ThriftSecurityException {
+ if (!instance.equals(HdfsZooInstance.getInstance().getInstanceID()))
+ throw new ThriftSecurityException(user, SecurityErrorCode.INVALID_INSTANCEID);
+
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME)) {
+ if (Arrays.equals(SecurityConstants.getSystemCredentials().password.array(), password.array())
+ && instance.equals(SecurityConstants.getSystemCredentials().instanceId))
+ return;
+ else
+ throw new ThriftSecurityException(user, SecurityErrorCode.BAD_CREDENTIALS);
+ }
+
+ if (!authenticator.authenticateUser(user, password, instance))
+ throw new ThriftSecurityException(user, SecurityErrorCode.BAD_CREDENTIALS);
+ }
+
+ private void authenticate(AuthInfo credentials) throws ThriftSecurityException {
+ authenticate(credentials.user, credentials.password, credentials.instanceId);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param password
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean authenticateUser(AuthInfo credentials, String user, ByteBuffer password) throws ThriftSecurityException {
+ authenticate(credentials);
+
+ if (credentials.user.equals(user))
+ return true;
+
+ if (!canPerformSystemActions(credentials))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ return authenticator.authenticateUser(user, password, credentials.instanceId);
+
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @return The given user's authorizations
+ * @throws ThriftSecurityException
+ */
+ public Authorizations getUserAuthorizations(AuthInfo credentials, String user) throws ThriftSecurityException {
+ authenticate(credentials);
+
+ targetUserExists(user);
+
+ if (!credentials.user.equals(user) && !hasSystemPermission(credentials.user, SystemPermission.SYSTEM))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ // system user doesn't need record-level authorizations for the tables it reads (for now)
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME))
+ return Constants.NO_AUTHS;
+
+ try {
+ return authorizor.getUserAuthorizations(user);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+
+ /**
+ * @param credentials
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public Authorizations getUserAuthorizations(AuthInfo credentials) throws ThriftSecurityException {
+ return getUserAuthorizations(credentials, credentials.user);
+ }
+
+ /**
+ * Checks if a user has a system permission
+ *
+ * @return true if a user exists and has permission; false otherwise
+ */
+ private boolean hasSystemPermission(String user, SystemPermission permission) throws ThriftSecurityException {
+ if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
+ return true;
+
+ targetUserExists(user);
+
+ try {
+ return authorizor.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
+ * @throws ThriftTableOperationException
+ */
+ private boolean hasTablePermission(String user, String table, TablePermission permission) throws ThriftSecurityException {
+ if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
+ return true;
+
+ targetUserExists(user);
+
+ if (table.equals(Constants.METADATA_TABLE_ID) && permission.equals(TablePermission.READ))
+ return true;
+
+ try {
+ return authorizor.hasTablePermission(user, table, permission);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ } catch (TableNotFoundException e) {
+ throw new ThriftSecurityException(user, SecurityErrorCode.TABLE_DOESNT_EXIST);
+ }
+ }
+
+ // some people just aren't allowed to ask about other users; here are those who can ask
+ private boolean canAskAboutOtherUsers(AuthInfo credentials, String user) throws ThriftSecurityException {
+ authenticate(credentials);
+ return credentials.user.equals(user) || hasSystemPermission(credentials.user, SystemPermission.SYSTEM)
+ || hasSystemPermission(credentials, credentials.user, SystemPermission.CREATE_USER)
+ || hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
+ || hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_USER);
+ }
+
+ /**
+ * @param user
+ * @throws ThriftSecurityException
+ */
+ private void targetUserExists(String user) throws ThriftSecurityException {
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME) || user.equals(getRootUsername()))
+ return;
+
+ if (!authenticator.userExists(user))
+ throw new ThriftSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST);
+ }
+
+ /**
+ * @param credentials
+ * @param string
+ * @return
+ * @throws ThriftSecurityException
+ * @throws TableNotFoundException
+ */
+ public boolean canScan(AuthInfo credentials, String table) throws ThriftSecurityException {
+ authenticate(credentials);
+ return hasTablePermission(credentials.user, table, TablePermission.READ);
+ }
+
+ /**
+ * @param credentials
+ * @param string
+ * @return
+ * @throws ThriftSecurityException
+ * @throws TableNotFoundException
+ */
+ public boolean canWrite(AuthInfo credentials, String table) throws ThriftSecurityException {
+ authenticate(credentials);
+ return hasTablePermission(credentials.user, table, TablePermission.WRITE);
+ }
+
+ /**
+ * @param credentials
+ * @param string
+ * @return
+ * @throws ThriftSecurityException
+ * @throws TableNotFoundException
+ */
+ public boolean canSplitTablet(AuthInfo credentials, String table) throws ThriftSecurityException {
+ authenticate(credentials);
+ return hasSystemPermission(credentials.user, SystemPermission.ALTER_TABLE) || hasSystemPermission(credentials.user, SystemPermission.SYSTEM)
+ || hasTablePermission(credentials.user, table, TablePermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param credentials
+ * @return
+ * @throws ThriftSecurityException
+ *
+ * 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(AuthInfo credentials) throws ThriftSecurityException {
+ authenticate(credentials);
+ return hasSystemPermission(credentials.user, SystemPermission.SYSTEM);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @throws ThriftSecurityException
+ * @throws ThriftTableOperationException
+ */
+ public boolean canFlush(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasTablePermission(c.user, tableId, TablePermission.WRITE) || hasTablePermission(c.user, tableId, TablePermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @throws ThriftSecurityException
+ * @throws ThriftTableOperationException
+ */
+ public boolean canAlterTable(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasTablePermission(c.user, tableId, TablePermission.ALTER_TABLE) || hasSystemPermission(c.user, SystemPermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param c
+ * @throws ThriftSecurityException
+ */
+ public boolean canCreateTable(AuthInfo c) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.CREATE_TABLE);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canRenameTable(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.ALTER_TABLE) || hasTablePermission(c.user, tableId, TablePermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param c
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canCloneTable(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.CREATE_TABLE) && hasTablePermission(c.user, tableId, TablePermission.READ);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canDeleteTable(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.DROP_TABLE) || hasTablePermission(c.user, tableId, TablePermission.DROP_TABLE);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canOnlineOfflineTable(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.SYSTEM) || hasSystemPermission(c.user, SystemPermission.ALTER_TABLE)
+ || hasTablePermission(c.user, tableId, TablePermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canMerge(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.SYSTEM) || hasSystemPermission(c.user, SystemPermission.ALTER_TABLE)
+ || hasTablePermission(c.user, tableId, TablePermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canDeleteRange(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.SYSTEM) || hasTablePermission(c.user, tableId, TablePermission.WRITE);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canBulkImport(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasTablePermission(c.user, tableId, TablePermission.BULK_IMPORT);
+ }
+
+ /**
+ * @param c
+ * @param tableId
+ * @return
+ * @throws TableNotFoundException
+ * @throws ThriftSecurityException
+ */
+ public boolean canCompact(AuthInfo c, String tableId) throws ThriftSecurityException {
+ authenticate(c);
+ return hasSystemPermission(c.user, SystemPermission.ALTER_TABLE) || hasTablePermission(c.user, tableId, TablePermission.ALTER_TABLE)
+ || hasTablePermission(c.user, tableId, TablePermission.WRITE);
+ }
+
+ /**
+ * @param credentials
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canChangeAuthorizations(AuthInfo c, String user) throws ThriftSecurityException {
+ authenticate(c);
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+ return hasSystemPermission(c.user, SystemPermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canChangePassword(AuthInfo c, String user) throws ThriftSecurityException {
+ authenticate(c);
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+ return c.user.equals(user) || hasSystemPermission(c.user, SystemPermission.ALTER_TABLE);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canCreateUser(AuthInfo c, String user) throws ThriftSecurityException {
+ authenticate(c);
+
+ // don't allow creating a user with the same name as system user
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
+
+ return hasSystemPermission(c.user, SystemPermission.CREATE_USER);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canDropUser(AuthInfo c, String user) throws ThriftSecurityException {
+ authenticate(c);
+
+ // can't delete root or system users
+ if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
+
+ return hasSystemPermission(c.user, SystemPermission.DROP_USER);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param sysPerm
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canGrantSystem(AuthInfo c, String user, SystemPermission sysPerm) throws ThriftSecurityException {
+ authenticate(c);
+
+ // can't modify system user
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ // can't grant GRANT
+ if (sysPerm.equals(SystemPermission.GRANT))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.GRANT_INVALID);
+
+ return hasSystemPermission(c.user, SystemPermission.GRANT);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param table
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canGrantTable(AuthInfo c, String user, String table) throws ThriftSecurityException {
+ authenticate(c);
+
+ // can't modify system user
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ return hasSystemPermission(c.user, SystemPermission.ALTER_TABLE) || hasTablePermission(c.user, table, TablePermission.GRANT);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param sysPerm
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canRevokeSystem(AuthInfo c, String user, SystemPermission sysPerm) throws ThriftSecurityException {
+ authenticate(c);
+
+ // can't modify system or root user
+ if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ // can't revoke GRANT
+ if (sysPerm.equals(SystemPermission.GRANT))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.GRANT_INVALID);
+
+ return hasSystemPermission(c.user, SystemPermission.GRANT);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param table
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean canRevokeTable(AuthInfo c, String user, String table) throws ThriftSecurityException {
+ authenticate(c);
+
+ // can't modify system user
+ if (user.equals(SecurityConstants.SYSTEM_USERNAME))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ return hasSystemPermission(c.user, SystemPermission.ALTER_TABLE) || hasTablePermission(c.user, table, TablePermission.GRANT);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param authorizations
+ * @throws ThriftSecurityException
+ */
+ public void changeAuthorizations(AuthInfo credentials, String user, Authorizations authorizations) throws ThriftSecurityException {
+ if (!canChangeAuthorizations(credentials, user))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ targetUserExists(user);
+
+ try {
+ authorizor.changeAuthorizations(user, authorizations);
+ log.info("Changed authorizations for user " + user + " at the request of user " + credentials.user);
+ } catch (AccumuloSecurityException ase) {
+ throw ase.asThriftException();
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param bytes
+ * @throws ThriftSecurityException
+ */
+ public void changePassword(AuthInfo credentials, String user, byte[] pass) throws ThriftSecurityException {
+ if (!canChangePassword(credentials, user))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+ try {
+ authenticator.changePassword(user, pass);
+ log.info("Changed password for user " + user + " at the request of user " + credentials.user);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param bytes
+ * @param authorizations
+ * @throws ThriftSecurityException
+ */
+ public void createUser(AuthInfo credentials, String user, byte[] pass, Authorizations authorizations) throws ThriftSecurityException {
+ if (!canCreateUser(credentials, user))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+ try {
+ authenticator.createUser(user, pass);
+ authorizor.initUser(user);
+ log.info("Created user " + user + " at the request of user " + credentials.user);
+ if (canChangeAuthorizations(credentials, user))
+ authorizor.changeAuthorizations(user, authorizations);
+ } catch (AccumuloSecurityException ase) {
+ throw ase.asThriftException();
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @throws ThriftSecurityException
+ */
+ public void dropUser(AuthInfo credentials, String user) throws ThriftSecurityException {
+ if (!canDropUser(credentials, user))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+ try {
+ authorizor.dropUser(user);
+ authenticator.dropUser(user);
+ log.info("Deleted user " + user + " at the request of user " + credentials.user);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param permissionById
+ * @throws ThriftSecurityException
+ */
+ public void grantSystemPermission(AuthInfo credentials, String user, SystemPermission permissionById) throws ThriftSecurityException {
+ if (!canGrantSystem(credentials, user, permissionById))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ targetUserExists(user);
+
+ try {
+ authorizor.grantSystemPermission(user, permissionById);
+ log.info("Granted system permission " + permissionById + " for user " + user + " at the request of user " + credentials.user);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param tableId
+ * @param permission
+ * @throws ThriftSecurityException
+ */
+ public void grantTablePermission(AuthInfo c, String user, String tableId, TablePermission permission) throws ThriftSecurityException {
+ if (!canGrantTable(c, user, tableId))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ targetUserExists(user);
+
+ try {
+ authorizor.grantTablePermission(user, tableId, permission);
+ log.info("Granted table permission " + permission + " for user " + user + " on the table " + tableId + " at the request of user " + c.user);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ } catch (TableNotFoundException e) {
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.TABLE_DOESNT_EXIST);
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param permission
+ * @throws ThriftSecurityException
+ */
+ public void revokeSystemPermission(AuthInfo credentials, String user, SystemPermission permission) throws ThriftSecurityException {
+ if (!canRevokeSystem(credentials, user, permission))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ targetUserExists(user);
+
+ try {
+ authorizor.revokeSystemPermission(user, permission);
+ log.info("Revoked system permission " + permission + " for user " + user + " at the request of user " + credentials.user);
+
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param tableId
+ * @param permission
+ * @throws ThriftSecurityException
+ */
+ public void revokeTablePermission(AuthInfo c, String user, String tableId, TablePermission permission) throws ThriftSecurityException {
+ if (!canRevokeTable(c, user, tableId))
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.PERMISSION_DENIED);
+
+ targetUserExists(user);
+
+ try {
+ authorizor.revokeTablePermission(user, tableId, permission);
+ log.info("Revoked table permission " + permission + " for user " + user + " on the table " + tableId + " at the request of user " + c.user);
+
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ } catch (TableNotFoundException e) {
+ throw new ThriftSecurityException(c.user, SecurityErrorCode.TABLE_DOESNT_EXIST);
+ }
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param permissionById
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean hasSystemPermission(AuthInfo credentials, String user, SystemPermission permissionById) throws ThriftSecurityException {
+ if (!canAskAboutOtherUsers(credentials, user))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+ return hasSystemPermission(user, permissionById);
+ }
+
+ /**
+ * @param credentials
+ * @param user
+ * @param tableId
+ * @param permissionById
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public boolean hasTablePermission(AuthInfo credentials, String user, String tableId, TablePermission permissionById) throws ThriftSecurityException {
+ if (!canAskAboutOtherUsers(credentials, user))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+ return hasTablePermission(user, tableId, permissionById);
+ }
+
+ /**
+ * @param credentials
+ * @return
+ * @throws ThriftSecurityException
+ */
+ public Set<String> listUsers(AuthInfo credentials) throws ThriftSecurityException {
+ authenticate(credentials);
+ try {
+ return authenticator.listUsers();
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+
+ /**
+ * @param systemCredentials
+ * @param tableId
+ * @throws ThriftSecurityException
+ */
+ public void deleteTable(AuthInfo credentials, String tableId) throws ThriftSecurityException {
+ if (!canDeleteTable(credentials, tableId))
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
+ try {
+ authorizor.cleanTablePermissions(tableId);
+ } catch (AccumuloSecurityException e) {
+ e.setUser(credentials.user);
+ throw e.asThriftException();
+ } catch (TableNotFoundException e) {
+ throw new ThriftSecurityException(credentials.user, SecurityErrorCode.TABLE_DOESNT_EXIST);
+ }
+ }
+
+ @Override
+ public void clearCache(String user, boolean password, boolean auths, boolean system, Set<String> tables) throws ThriftSecurityException {
+ if (password)
+ authenticator.clearCache(user);
+
+ if (auths || system || tables.size() > 0)
+ try {
+ authorizor.clearCache(user, auths, system, tables);
+ } catch (TableNotFoundException e) {
+ throw new ThriftSecurityException(user, SecurityErrorCode.TABLE_DOESNT_EXIST);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+
+ }
+
+ @Override
+ public void clearCache(String table) throws ThriftSecurityException {
+ try {
+ authorizor.clearTableCache(table);
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ } catch (TableNotFoundException e) {
+ throw new ThriftSecurityException(table, SecurityErrorCode.TABLE_DOESNT_EXIST);
+ }
+ }
+
+ @Override
+ public boolean cachesToClear() throws ThriftSecurityException {
+ try {
+ return authenticator.cachesToClear() || authorizor.cachesToClear();
+ } catch (AccumuloSecurityException e) {
+ throw e.asThriftException();
+ }
+ }
+}
Propchange: accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/SecurityOperationImpl.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthenticator.java
URL: http://svn.apache.org/viewvc/accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthenticator.java?rev=1346535&r1=1346534&r2=1346535&view=diff
==============================================================================
--- accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthenticator.java (original)
+++ accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthenticator.java Tue Jun 5 19:02:30 2012
@@ -16,101 +16,48 @@
*/
package org.apache.accumulo.server.security;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
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.security.Authorizations;
-import org.apache.accumulo.core.security.SystemPermission;
-import org.apache.accumulo.core.security.TablePermission;
import org.apache.accumulo.core.security.thrift.AuthInfo;
import org.apache.accumulo.core.security.thrift.SecurityErrorCode;
import org.apache.accumulo.core.util.ByteBufferUtil;
import org.apache.accumulo.core.zookeeper.ZooUtil.NodeExistsPolicy;
import org.apache.accumulo.core.zookeeper.ZooUtil.NodeMissingPolicy;
-import org.apache.accumulo.server.client.HdfsZooInstance;
import org.apache.accumulo.server.zookeeper.IZooReaderWriter;
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 security info into ZK
+// Utility class for adding all authentication info into ZK
public final class ZKAuthenticator implements Authenticator {
- private static final Logger log = Logger.getLogger(ZKAuthenticator.class);
+ static final Logger log = Logger.getLogger(ZKAuthenticator.class);
private static Authenticator zkAuthenticatorInstance = null;
- private static String rootUserName = null;
-
- private final String ZKUserAuths = "/Authorizations";
- private final String ZKUserSysPerms = "/System";
- private final String ZKUserTablePerms = "/Tables";
-
- private final String ZKUserPath;
+
+ private String ZKUserPath;
private final ZooCache zooCache;
public static synchronized Authenticator getInstance() {
if (zkAuthenticatorInstance == null)
- zkAuthenticatorInstance = new Auditor(new ZKAuthenticator());
+ zkAuthenticatorInstance = new ZKAuthenticator();
return zkAuthenticatorInstance;
}
- private ZKAuthenticator() {
- this(HdfsZooInstance.getInstance().getInstanceID());
- }
-
- public ZKAuthenticator(String instanceId) {
- ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
+ public ZKAuthenticator() {
zooCache = new ZooCache();
}
- /**
- * Authenticate a user's credentials
- *
- * @return true if username/password combination match existing user; false otherwise
- * @throws AccumuloSecurityException
- */
- private boolean authenticate(AuthInfo credentials) throws AccumuloSecurityException {
- if (!credentials.instanceId.equals(HdfsZooInstance.getInstance().getInstanceID()))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.INVALID_INSTANCEID);
-
- if (credentials.user.equals(SecurityConstants.SYSTEM_USERNAME))
- return credentials.equals(SecurityConstants.getSystemCredentials());
-
- byte[] pass;
- String zpath = ZKUserPath + "/" + credentials.user;
- pass = zooCache.get(zpath);
- boolean result = Tool.checkPass(ByteBufferUtil.toBytes(credentials.password), pass);
- if (!result) {
- zooCache.clear(zpath);
- pass = zooCache.get(zpath);
- result = Tool.checkPass(ByteBufferUtil.toBytes(credentials.password), pass);
- }
- return result;
+ public void initialize(String instanceId) {
+ ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
}
-
- /**
- * Only SYSTEM user can call this method
- */
+
+ @Override
public void initializeSecurity(AuthInfo credentials, String rootuser, byte[] rootpass) throws AccumuloSecurityException {
- if (!credentials.user.equals(SecurityConstants.SYSTEM_USERNAME) || !authenticate(credentials))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
try {
// remove old settings from zookeeper first, if any
IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
@@ -124,16 +71,8 @@ public final class ZKAuthenticator imple
// prep parent node of users with root username
zoo.putPersistentData(ZKUserPath, rootuser.getBytes(), NodeExistsPolicy.FAIL);
- // create the root user with all system privileges, no table privileges, and no record-level authorizations
- Set<SystemPermission> rootPerms = new TreeSet<SystemPermission>();
- for (SystemPermission p : SystemPermission.values())
- rootPerms.add(p);
- Map<String,Set<TablePermission>> tablePerms = new HashMap<String,Set<TablePermission>>();
- // Allow the root user to flush the !METADATA table
- tablePerms.put(Constants.METADATA_TABLE_ID, Collections.singleton(TablePermission.ALTER_TABLE));
- constructUser(rootuser, Tool.createPass(rootpass), rootPerms, tablePerms, Constants.NO_AUTHS);
+ constructUser(rootuser, ZKSecurityTool.createPass(rootpass));
}
- log.info("Initialized root user with username: " + rootuser + " at the request of user " + credentials.user);
} catch (KeeperException e) {
log.error(e, e);
throw new RuntimeException(e);
@@ -149,81 +88,27 @@ public final class ZKAuthenticator imple
/**
* Sets up the user in ZK for the provided user. No checking for existence is done here, it should be done before calling.
*/
- private void constructUser(String user, byte[] pass, Set<SystemPermission> sysPerms, Map<String,Set<TablePermission>> tablePerms, Authorizations auths)
+ 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);
- zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, Tool.convertAuthorizations(auths), NodeExistsPolicy.FAIL);
- zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, Tool.convertSystemPermissions(sysPerms), NodeExistsPolicy.FAIL);
- zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms, new byte[0], NodeExistsPolicy.FAIL);
- for (Entry<String,Set<TablePermission>> entry : tablePerms.entrySet())
- createTablePerm(user, entry.getKey(), entry.getValue());
- }
- }
-
- /**
- * Sets up a new table configuration for the provided user/table. No checking for existance is done here, it should be done before calling.
- */
- private void createTablePerm(String user, String table, Set<TablePermission> perms) throws KeeperException, InterruptedException {
- synchronized (zooCache) {
- zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, Tool.convertTablePermissions(perms),
- NodeExistsPolicy.FAIL);
}
}
- public synchronized String getRootUsername() {
- if (rootUserName == null)
- rootUserName = new String(zooCache.get(ZKUserPath));
- return rootUserName;
- }
-
- public boolean authenticateUser(AuthInfo credentials, String user, ByteBuffer pass) throws AccumuloSecurityException {
- if (!authenticate(credentials))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
- if (!credentials.user.equals(user) && !hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- return authenticate(new AuthInfo(user, pass, credentials.instanceId));
- }
-
- public boolean authenticateUser(AuthInfo credentials, String user, byte[] pass) throws AccumuloSecurityException {
- return authenticateUser(credentials, user, ByteBuffer.wrap(pass));
- }
-
@Override
- public Set<String> listUsers(AuthInfo credentials) throws AccumuloSecurityException {
- if (!authenticate(credentials))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
-
+ public Set<String> listUsers() {
return new TreeSet<String>(zooCache.getChildren(ZKUserPath));
}
/**
* Creates a user with no permissions whatsoever
*/
- public void createUser(AuthInfo credentials, String user, byte[] pass, Authorizations authorizations) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.CREATE_USER))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)) {
- Authorizations creatorAuths = getUserAuthorizations(credentials, credentials.user);
- for (byte[] auth : authorizations.getAuthorizations())
- if (!creatorAuths.contains(auth)) {
- log.info("User " + credentials.user + " attempted to create a user " + user + " with authorization " + new String(auth) + " they did not have");
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_AUTHORIZATIONS);
- }
- }
-
- // don't allow creating a user with the same name as system user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- throw new AccumuloSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
-
+ @Override
+ public void createUser(String user, byte[] pass) throws AccumuloSecurityException {
try {
- constructUser(user, Tool.createPass(pass), new TreeSet<SystemPermission>(), new HashMap<String,Set<TablePermission>>(), authorizations);
- log.info("Created user " + user + " at the request of user " + credentials.user);
+ constructUser(user, ZKSecurityTool.createPass(pass));
} catch (KeeperException e) {
log.error(e, e);
if (e.code().equals(KeeperException.Code.NODEEXISTS))
@@ -238,20 +123,13 @@ public final class ZKAuthenticator imple
}
}
- public void dropUser(AuthInfo credentials, String user) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_USER))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // can't delete root or system users
- if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
- throw new AccumuloSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
-
+ @Override
+ public void dropUser(String user) throws AccumuloSecurityException {
try {
synchronized (zooCache) {
zooCache.clear();
ZooReaderWriter.getRetryingInstance().recursiveDelete(ZKUserPath + "/" + user, NodeMissingPolicy.FAIL);
}
- log.info("Deleted user " + user + " at the request of user " + credentials.user);
} catch (InterruptedException e) {
log.error(e, e);
throw new RuntimeException(e);
@@ -263,21 +141,14 @@ public final class ZKAuthenticator imple
}
}
- public void changePassword(AuthInfo credentials, String user, byte[] pass) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER) && !credentials.user.equals(user))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // can't modify system user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- throw new AccumuloSecurityException(user, SecurityErrorCode.PERMISSION_DENIED);
-
+ @Override
+ public void changePassword(String user, byte[] pass) throws AccumuloSecurityException {
if (userExists(user)) {
try {
synchronized (zooCache) {
- zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPrivatePersistentData(ZKUserPath + "/" + user, Tool.createPass(pass), NodeExistsPolicy.OVERWRITE);
+ zooCache.clear(ZKUserPath + "/" + user);
+ ZooReaderWriter.getRetryingInstance().putPrivatePersistentData(ZKUserPath + "/" + user, ZKSecurityTool.createPass(pass), NodeExistsPolicy.OVERWRITE);
}
- log.info("Changed password for user " + user + " at the request of user " + credentials.user);
} catch (KeeperException e) {
log.error(e, e);
throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
@@ -295,427 +166,37 @@ public final class ZKAuthenticator imple
/**
* Checks if a user exists
*/
- private boolean userExists(String user) {
- if (zooCache.get(ZKUserPath + "/" + user) != null)
- return true;
- zooCache.clear(ZKUserPath + "/" + user);
+ @Override
+ public boolean userExists(String user) {
return zooCache.get(ZKUserPath + "/" + user) != null;
}
- public void changeAuthorizations(AuthInfo credentials, String user, Authorizations authorizations) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // can't modify system user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- if (userExists(user)) {
- try {
- synchronized (zooCache) {
- zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, Tool.convertAuthorizations(authorizations),
- NodeExistsPolicy.OVERWRITE);
- }
- log.info("Changed authorizations for user " + user + " at the request of user " + credentials.user);
- } catch (KeeperException e) {
- log.error(e, e);
- throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
- } catch (InterruptedException e) {
- log.error(e, e);
- throw new RuntimeException(e);
- }
- } else
- throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
- }
-
- public Authorizations getUserAuthorizations(AuthInfo credentials, String user) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM) && !credentials.user.equals(user))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // system user doesn't need record-level authorizations for the tables it reads (for now)
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- return Constants.NO_AUTHS;
-
- if (userExists(user)) {
- byte[] authsBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserAuths);
- if (authsBytes != null)
- return Tool.convertAuthorizations(authsBytes);
- }
- throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
- }
-
- /**
- * Checks if a user has a system permission
- *
- * @return true if a user exists and has permission; false otherwise
- */
@Override
- public boolean hasSystemPermission(AuthInfo credentials, String user, SystemPermission permission) throws AccumuloSecurityException {
- if (!authenticate(credentials))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
-
- // some people just aren't allowed to ask about other users; here are those who can ask
- if (!credentials.user.equals(user) && !hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM)
- && !hasSystemPermission(credentials, credentials.user, SystemPermission.CREATE_USER)
- && !hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
- && !hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_USER))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- if (user.equals(getRootUsername()) || user.equals(SecurityConstants.SYSTEM_USERNAME))
- return true;
-
- byte[] perms = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
- if (perms != null) {
- if (Tool.convertSystemPermissions(perms).contains(permission))
- return true;
- zooCache.clear(ZKUserPath + "/" + user + ZKUserSysPerms);
- perms = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
- if (perms == null)
- return false;
- return Tool.convertSystemPermissions(perms).contains(permission);
- }
- throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
+ public void clearCache(String user) {
+ zooCache.clear(ZKUserPath + "/" + user);
}
-
+
@Override
- public boolean hasTablePermission(AuthInfo credentials, String user, String table, TablePermission permission) throws AccumuloSecurityException {
- if (!_hasTablePermission(credentials, user, table, permission)) {
- zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- return _hasTablePermission(credentials, user, table, permission);
- }
-
+ public boolean validAuthorizor(Authorizor auth) {
return true;
}
- private boolean _hasTablePermission(AuthInfo credentials, String user, String table, TablePermission permission) throws AccumuloSecurityException {
- if (!authenticate(credentials))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.BAD_CREDENTIALS);
-
- // some people just aren't allowed to ask about other users; here are those who can ask
- if (!credentials.user.equals(user) && !hasSystemPermission(credentials, credentials.user, SystemPermission.SYSTEM)
- && !hasSystemPermission(credentials, credentials.user, SystemPermission.CREATE_USER)
- && !hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
- && !hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_USER))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // always allow system user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- return true;
-
- // Don't let nonexistant users scan
- if (!userExists(user))
- throw new AccumuloSecurityException(user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
-
- // allow anybody to read the METADATA table
- if (table.equals(Constants.METADATA_TABLE_ID) && permission.equals(TablePermission.READ))
- return true;
-
- byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- if (serializedPerms != null) {
- return Tool.convertTablePermissions(serializedPerms).contains(permission);
- }
- return false;
- }
-
@Override
- public void grantSystemPermission(AuthInfo credentials, String user, SystemPermission permission) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.GRANT))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // can't modify system user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- if (permission.equals(SystemPermission.GRANT))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.GRANT_INVALID);
-
- if (userExists(user)) {
- try {
- byte[] permBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
- if (permBytes == null) {
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
- }
-
- Set<SystemPermission> perms = Tool.convertSystemPermissions(permBytes);
- if (perms.add(permission)) {
- synchronized (zooCache) {
- zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, Tool.convertSystemPermissions(perms),
- NodeExistsPolicy.OVERWRITE);
- }
- }
- log.info("Granted system permission " + permission + " for user " + user + " at the request of user " + credentials.user);
- } catch (KeeperException e) {
- log.error(e, e);
- throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
- } catch (InterruptedException e) {
- log.error(e, e);
- throw new RuntimeException(e);
- }
- } else
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
- }
-
- @Override
- public void grantTablePermission(AuthInfo credentials, String user, String table, TablePermission permission) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
- && !hasTablePermission(credentials, credentials.user, table, TablePermission.GRANT))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // can't modify system user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- if (userExists(user)) {
- Set<TablePermission> tablePerms;
- byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- if (serializedPerms != null)
- tablePerms = Tool.convertTablePermissions(serializedPerms);
- else
- tablePerms = new TreeSet<TablePermission>();
-
- try {
- if (tablePerms.add(permission)) {
- synchronized (zooCache) {
- zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
- Tool.convertTablePermissions(tablePerms), NodeExistsPolicy.OVERWRITE);
- }
- }
- log.info("Granted table permission " + permission + " for user " + user + " on the table " + table + " at the request of user " + credentials.user);
- } catch (KeeperException e) {
- log.error(e, e);
- throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
- } catch (InterruptedException e) {
- log.error(e, e);
- throw new RuntimeException(e);
- }
- } else
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
- }
-
- @Override
- public void revokeSystemPermission(AuthInfo credentials, String user, SystemPermission permission) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.GRANT))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // can't modify system user or revoke permissions from root user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME) || user.equals(getRootUsername()))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- if (permission.equals(SystemPermission.GRANT))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.GRANT_INVALID);
-
- if (userExists(user)) {
- byte[] sysPermBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
- if (sysPermBytes == null)
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST);
-
- Set<SystemPermission> sysPerms = Tool.convertSystemPermissions(sysPermBytes);
-
- try {
- if (sysPerms.remove(permission)) {
- synchronized (zooCache) {
- zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, Tool.convertSystemPermissions(sysPerms),
- NodeExistsPolicy.OVERWRITE);
- }
- }
- log.info("Revoked system permission " + permission + " for user " + user + " at the request of user " + credentials.user);
- } catch (KeeperException e) {
- log.error(e, e);
- throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
- } catch (InterruptedException e) {
- log.error(e, e);
- throw new RuntimeException(e);
- }
- } else
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST);
- }
-
- @Override
- public void revokeTablePermission(AuthInfo credentials, String user, String table, TablePermission permission) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.ALTER_USER)
- && !hasTablePermission(credentials, credentials.user, table, TablePermission.GRANT))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- // can't modify system user
- if (user.equals(SecurityConstants.SYSTEM_USERNAME))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- if (userExists(user)) {
-
- byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- if (serializedPerms == null)
- return;
- Set<TablePermission> tablePerms = Tool.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, Tool.convertTablePermissions(tablePerms),
- NodeExistsPolicy.OVERWRITE);
- }
- } catch (KeeperException e) {
- log.error(e, e);
- throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
- } catch (InterruptedException e) {
- log.error(e, e);
- throw new RuntimeException(e);
- }
- log.info("Revoked table permission " + permission + " for user " + user + " on the table " + table + " at the request of user " + credentials.user);
- } else
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.USER_DOESNT_EXIST);
- }
-
- @Override
- public void deleteTable(AuthInfo credentials, String table) throws AccumuloSecurityException {
- if (!hasSystemPermission(credentials, credentials.user, SystemPermission.DROP_TABLE)
- && !hasTablePermission(credentials, credentials.user, table, TablePermission.DROP_TABLE))
- throw new AccumuloSecurityException(credentials.user, SecurityErrorCode.PERMISSION_DENIED);
-
- try {
- synchronized (zooCache) {
- zooCache.clear();
- 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(credentials.user, SecurityErrorCode.CONNECTION_ERROR, e);
- } catch (InterruptedException e) {
- log.error(e, e);
- throw new RuntimeException(e);
- }
- }
-
- /**
- * All the static too methods used for this class, so that we can separate out stuff that isn't using ZooKeeper. That way, we can check the synchronization
- * model more easily, as we only need to check to make sure zooCache is cleared when things are written to ZooKeeper in methods that might use it. These
- * won't, and so don't need to be checked.
- */
- static class Tool {
- private static final int SALT_LENGTH = 8;
-
- // Generates a byte array salt of length SALT_LENGTH
- private static byte[] generateSalt() {
- final SecureRandom random = new SecureRandom();
- byte[] salt = new byte[SALT_LENGTH];
- random.nextBytes(salt);
- return salt;
- }
-
- private static byte[] hash(byte[] raw) throws NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance(Constants.PW_HASH_ALGORITHM);
- md.update(raw);
- return md.digest();
- }
-
- public static boolean checkPass(byte[] password, byte[] zkData) {
- if (zkData == null)
- return false;
-
- byte[] salt = new byte[SALT_LENGTH];
- System.arraycopy(zkData, 0, salt, 0, SALT_LENGTH);
- byte[] passwordToCheck;
- try {
- passwordToCheck = convertPass(password, salt);
- } catch (NoSuchAlgorithmException e) {
- log.error("Count not create hashed password", e);
- return false;
- }
- return java.util.Arrays.equals(passwordToCheck, zkData);
- }
-
- public static byte[] createPass(byte[] password) throws AccumuloException {
- byte[] salt = generateSalt();
- try {
- return convertPass(password, salt);
- } catch (NoSuchAlgorithmException e) {
- log.error("Count not create hashed password", e);
- throw new AccumuloException("Count not create hashed password", e);
- }
- }
-
- private static byte[] convertPass(byte[] password, byte[] salt) throws NoSuchAlgorithmException {
- byte[] plainSalt = new byte[password.length + SALT_LENGTH];
- System.arraycopy(password, 0, plainSalt, 0, password.length);
- System.arraycopy(salt, 0, plainSalt, password.length, SALT_LENGTH);
- byte[] hashed = hash(plainSalt);
- byte[] saltedHash = new byte[SALT_LENGTH + hashed.length];
- System.arraycopy(salt, 0, saltedHash, 0, SALT_LENGTH);
- System.arraycopy(hashed, 0, saltedHash, SALT_LENGTH, hashed.length);
- return saltedHash; // contains salt+hash(password+salt)
- }
-
- public static Authorizations convertAuthorizations(byte[] authorizations) {
- return new Authorizations(authorizations);
- }
-
- public static byte[] convertAuthorizations(Authorizations authorizations) {
- return authorizations.getAuthorizationsArray();
- }
-
- public static byte[] convertSystemPermissions(Set<SystemPermission> systempermissions) {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream(systempermissions.size());
- DataOutputStream out = new DataOutputStream(bytes);
- try {
- for (SystemPermission sp : systempermissions)
- out.writeByte(sp.getId());
- } catch (IOException e) {
- log.error(e, e);
- throw new RuntimeException(e); // this is impossible with ByteArrayOutputStream; crash hard if this happens
- }
- return bytes.toByteArray();
- }
-
- public static Set<SystemPermission> convertSystemPermissions(byte[] systempermissions) {
- ByteArrayInputStream bytes = new ByteArrayInputStream(systempermissions);
- DataInputStream in = new DataInputStream(bytes);
- Set<SystemPermission> toReturn = new HashSet<SystemPermission>();
- try {
- while (in.available() > 0)
- toReturn.add(SystemPermission.getPermissionById(in.readByte()));
- } catch (IOException e) {
- log.error("User database is corrupt; error converting system permissions", e);
- toReturn.clear();
- }
- return toReturn;
- }
-
- public static byte[] convertTablePermissions(Set<TablePermission> tablepermissions) {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream(tablepermissions.size());
- DataOutputStream out = new DataOutputStream(bytes);
- try {
- for (TablePermission tp : tablepermissions)
- out.writeByte(tp.getId());
- } catch (IOException e) {
- log.error(e, e);
- throw new RuntimeException(e); // this is impossible with ByteArrayOutputStream; crash hard if this happens
- }
- return bytes.toByteArray();
- }
-
- public static Set<TablePermission> convertTablePermissions(byte[] tablepermissions) {
- Set<TablePermission> toReturn = new HashSet<TablePermission>();
- for (byte b : tablepermissions)
- toReturn.add(TablePermission.getPermissionById(b));
- return toReturn;
+ public boolean authenticateUser(String user, ByteBuffer password, String instanceId) {
+ byte[] pass;
+ String zpath = ZKUserPath + "/" + user;
+ pass = zooCache.get(zpath);
+ boolean result = ZKSecurityTool.checkPass(ByteBufferUtil.toBytes(password), pass);
+ if (!result) {
+ zooCache.clear(zpath);
+ pass = zooCache.get(zpath);
+ result = ZKSecurityTool.checkPass(ByteBufferUtil.toBytes(password), pass);
}
+ return result;
}
-
- @Override
- public void clearCache(String user) {
- zooCache.clear(ZKUserPath + "/" + user);
- }
-
+
@Override
- public void clearCache(String user, String tableId) {
- zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + tableId);
+ public boolean cachesToClear() {
+ return true;
}
}
Added: accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthorizor.java
URL: http://svn.apache.org/viewvc/accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthorizor.java?rev=1346535&view=auto
==============================================================================
--- accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthorizor.java (added)
+++ accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthorizor.java Tue Jun 5 19:02:30 2012
@@ -0,0 +1,349 @@
+/**
+ * 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.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.security.Authorizations;
+import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TablePermission;
+import org.apache.accumulo.core.security.thrift.SecurityErrorCode;
+import org.apache.accumulo.core.zookeeper.ZooUtil.NodeExistsPolicy;
+import org.apache.accumulo.core.zookeeper.ZooUtil.NodeMissingPolicy;
+import org.apache.accumulo.server.zookeeper.IZooReaderWriter;
+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 final String ZKUserSysPerms = "/System";
+ private final String ZKUserTablePerms = "/Tables";
+
+ 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();
+ }
+
+ public void initialize(String instanceId) {
+ ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
+ }
+
+ public Authorizations getUserAuthorizations(String user) {
+ byte[] authsBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserAuths);
+ if (authsBytes != null)
+ return ZKSecurityTool.convertAuthorizations(authsBytes);
+ return Constants.NO_AUTHS;
+ }
+
+ @Override
+ public boolean hasTablePermission(String user, String table, TablePermission permission) {
+ byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
+ if (serializedPerms != null) {
+ return ZKSecurityTool.convertTablePermissions(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 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 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 boolean validAuthenticator(Authenticator auth) {
+ return true;
+ }
+
+ @Override
+ public void initializeSecurity(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 table
+ tablePerms.put(Constants.METADATA_TABLE_ID, Collections.singleton(TablePermission.ALTER_TABLE));
+
+ try {
+ initUser(rootuser);
+ zoo.putPersistentData(ZKUserPath + "/" + rootuser + ZKUserAuths, ZKSecurityTool.convertAuthorizations(Constants.NO_AUTHS), NodeExistsPolicy.FAIL);
+ zoo.putPersistentData(ZKUserPath + "/" + rootuser + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(rootPerms), NodeExistsPolicy.FAIL);
+ zoo.putPersistentData(ZKUserPath + "/" + rootuser + ZKUserTablePerms, new byte[0], NodeExistsPolicy.FAIL);
+ for (Entry<String,Set<TablePermission>> entry : tablePerms.entrySet())
+ createTablePerm(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
+ */
+ 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);
+ } 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 existance is done here, it should be done before calling.
+ */
+ private void createTablePerm(String user, String table, Set<TablePermission> perms) throws KeeperException, InterruptedException {
+ synchronized (zooCache) {
+ zooCache.clear();
+ ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
+ ZKSecurityTool.convertTablePermissions(perms), NodeExistsPolicy.FAIL);
+ }
+ }
+
+ @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 hasSystemPermission(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 void clearUserCache(String user) {
+ zooCache.clear(ZKUserPath + "/" + user);
+ }
+
+ @Override
+ public void clearTableCache(String table) {
+ for (String user : zooCache.getChildren(ZKUserPath))
+ zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
+ }
+
+ @Override
+ public void clearCache(String user, String tableId) {
+ zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + tableId);
+ }
+
+ @Override
+ public boolean cachesToClear() {
+ return true;
+ }
+
+ @Override
+ public void clearCache(String user, boolean auths, boolean system, Set<String> tables) {
+ if (auths)
+ zooCache.clear(ZKUserPath + "/" + user + ZKUserAuths);
+
+ if (system)
+ zooCache.clear(ZKUserPath + "/" + user + ZKUserSysPerms);
+
+ for (String table : tables)
+ clearCache(user, table);
+ }
+
+ @Override
+ public void dropUser(String user) throws AccumuloSecurityException {
+ try {
+ synchronized (zooCache) {
+ zooCache.clear(ZKUserPath + "/" + user);
+ ZooReaderWriter.getRetryingInstance().recursiveDelete(ZKUserPath + "/" + user + ZKUserAuths, NodeMissingPolicy.FAIL);
+ ZooReaderWriter.getRetryingInstance().recursiveDelete(ZKUserPath + "/" + user + ZKUserSysPerms, NodeMissingPolicy.FAIL);
+ ZooReaderWriter.getRetryingInstance().recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms, NodeMissingPolicy.FAIL);
+ }
+ } 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);
+
+ }
+ }
+}
Propchange: accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKAuthorizor.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKSecurityTool.java
URL: http://svn.apache.org/viewvc/accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKSecurityTool.java?rev=1346535&view=auto
==============================================================================
--- accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKSecurityTool.java (added)
+++ accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKSecurityTool.java Tue Jun 5 19:02:30 2012
@@ -0,0 +1,149 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.server.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TablePermission;
+
+/**
+ * All the static too methods used for this class, so that we can separate out stuff that isn't using ZooKeeper. That way, we can check the synchronization
+ * model more easily, as we only need to check to make sure zooCache is cleared when things are written to ZooKeeper in methods that might use it. These
+ * won't, and so don't need to be checked.
+ */
+class ZKSecurityTool {
+ private static final int SALT_LENGTH = 8;
+
+ // Generates a byte array salt of length SALT_LENGTH
+ private static byte[] generateSalt() {
+ final SecureRandom random = new SecureRandom();
+ byte[] salt = new byte[SALT_LENGTH];
+ random.nextBytes(salt);
+ return salt;
+ }
+
+ private static byte[] hash(byte[] raw) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance(Constants.PW_HASH_ALGORITHM);
+ md.update(raw);
+ return md.digest();
+ }
+
+ public static boolean checkPass(byte[] password, byte[] zkData) {
+ if (zkData == null)
+ return false;
+
+ byte[] salt = new byte[SALT_LENGTH];
+ System.arraycopy(zkData, 0, salt, 0, SALT_LENGTH);
+ byte[] passwordToCheck;
+ try {
+ passwordToCheck = convertPass(password, salt);
+ } catch (NoSuchAlgorithmException e) {
+ ZKAuthenticator.log.error("Count not create hashed password", e);
+ return false;
+ }
+ return java.util.Arrays.equals(passwordToCheck, zkData);
+ }
+
+ public static byte[] createPass(byte[] password) throws AccumuloException {
+ byte[] salt = generateSalt();
+ try {
+ return convertPass(password, salt);
+ } catch (NoSuchAlgorithmException e) {
+ ZKAuthenticator.log.error("Count not create hashed password", e);
+ throw new AccumuloException("Count not create hashed password", e);
+ }
+ }
+
+ private static byte[] convertPass(byte[] password, byte[] salt) throws NoSuchAlgorithmException {
+ byte[] plainSalt = new byte[password.length + SALT_LENGTH];
+ System.arraycopy(password, 0, plainSalt, 0, password.length);
+ System.arraycopy(salt, 0, plainSalt, password.length, SALT_LENGTH);
+ byte[] hashed = hash(plainSalt);
+ byte[] saltedHash = new byte[SALT_LENGTH + hashed.length];
+ System.arraycopy(salt, 0, saltedHash, 0, SALT_LENGTH);
+ System.arraycopy(hashed, 0, saltedHash, SALT_LENGTH, hashed.length);
+ return saltedHash; // contains salt+hash(password+salt)
+ }
+
+ public static Authorizations convertAuthorizations(byte[] authorizations) {
+ return new Authorizations(authorizations);
+ }
+
+ public static byte[] convertAuthorizations(Authorizations authorizations) {
+ return authorizations.getAuthorizationsArray();
+ }
+
+ public static byte[] convertSystemPermissions(Set<SystemPermission> systempermissions) {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream(systempermissions.size());
+ DataOutputStream out = new DataOutputStream(bytes);
+ try {
+ for (SystemPermission sp : systempermissions)
+ out.writeByte(sp.getId());
+ } catch (IOException e) {
+ ZKAuthenticator.log.error(e, e);
+ throw new RuntimeException(e); // this is impossible with ByteArrayOutputStream; crash hard if this happens
+ }
+ return bytes.toByteArray();
+ }
+
+ public static Set<SystemPermission> convertSystemPermissions(byte[] systempermissions) {
+ ByteArrayInputStream bytes = new ByteArrayInputStream(systempermissions);
+ DataInputStream in = new DataInputStream(bytes);
+ Set<SystemPermission> toReturn = new HashSet<SystemPermission>();
+ try {
+ while (in.available() > 0)
+ toReturn.add(SystemPermission.getPermissionById(in.readByte()));
+ } catch (IOException e) {
+ ZKAuthenticator.log.error("User database is corrupt; error converting system permissions", e);
+ toReturn.clear();
+ }
+ return toReturn;
+ }
+
+ public static byte[] convertTablePermissions(Set<TablePermission> tablepermissions) {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream(tablepermissions.size());
+ DataOutputStream out = new DataOutputStream(bytes);
+ try {
+ for (TablePermission tp : tablepermissions)
+ out.writeByte(tp.getId());
+ } catch (IOException e) {
+ ZKAuthenticator.log.error(e, e);
+ throw new RuntimeException(e); // this is impossible with ByteArrayOutputStream; crash hard if this happens
+ }
+ return bytes.toByteArray();
+ }
+
+ public static Set<TablePermission> convertTablePermissions(byte[] tablepermissions) {
+ Set<TablePermission> toReturn = new HashSet<TablePermission>();
+ for (byte b : tablepermissions)
+ toReturn.add(TablePermission.getPermissionById(b));
+ return toReturn;
+ }
+}
\ No newline at end of file
Propchange: accumulo/branches/ACCUMULO-259/server/src/main/java/org/apache/accumulo/server/security/ZKSecurityTool.java
------------------------------------------------------------------------------
svn:mime-type = text/plain