diff --git common/src/java/org/apache/hadoop/hive/conf/HiveConf.java common/src/java/org/apache/hadoop/hive/conf/HiveConf.java index 84ee78f..216e445 100644 --- common/src/java/org/apache/hadoop/hive/conf/HiveConf.java +++ common/src/java/org/apache/hadoop/hive/conf/HiveConf.java @@ -134,7 +134,8 @@ HiveConf.ConfVars.HMSHANDLERINTERVAL, HiveConf.ConfVars.HMSHANDLERFORCERELOADCONF, HiveConf.ConfVars.METASTORE_PARTITION_NAME_WHITELIST_PATTERN, - HiveConf.ConfVars.METASTORE_DISALLOW_INCOMPATIBLE_COL_TYPE_CHANGES + HiveConf.ConfVars.METASTORE_DISALLOW_INCOMPATIBLE_COL_TYPE_CHANGES, + HiveConf.ConfVars.USERS_IN_ADMIN_ROLE }; /** @@ -894,7 +895,8 @@ // none is the default(past) behavior. Implies only alphaNumeric and underscore are valid characters in identifiers. // column: implies column names can contain any character. HIVE_QUOTEDID_SUPPORT("hive.support.quoted.identifiers", "column", - new PatternValidator("none", "column")) + new PatternValidator("none", "column")), + USERS_IN_ADMIN_ROLE("hive.users.in.admin.role","") ; public final String varname; diff --git conf/hive-default.xml.template conf/hive-default.xml.template index 66d22f9..e13e4f4 100644 --- conf/hive-default.xml.template +++ conf/hive-default.xml.template @@ -1537,6 +1537,13 @@ + hive.users.in.admin.role + + Comma separated list of users who are in admin role for bootstrapping. + More users can be added in ADMIN role later. + + + hive.security.command.whitelist set,reset,dfs,add,delete Comma separated list of non-SQL Hive commands users are authorized to execute diff --git itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestAdminUser.java itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestAdminUser.java new file mode 100644 index 0000000..f2e75f7 --- /dev/null +++ itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestAdminUser.java @@ -0,0 +1,46 @@ +/** + * 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.hadoop.hive.metastore; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.hadoop.hive.metastore.HiveMetaStore.HMSHandler; +import org.apache.hadoop.hive.metastore.api.PrincipalType; +import org.apache.hadoop.hive.metastore.api.Role; +import org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory; + +public class TestAdminUser extends TestCase{ + + public void testCreateAdminNAddUser() throws IOException, Throwable { + HiveConf conf = new HiveConf(); + conf.setVar(ConfVars.USERS_IN_ADMIN_ROLE, "adminuser"); + conf.setVar(ConfVars.HIVE_AUTHORIZATION_MANAGER,SQLStdHiveAuthorizerFactory.class.getName()); + RawStore rawStore = new HMSHandler("testcreateroot", conf).getMS(); + Role adminRole = rawStore.getRole(HiveMetaStore.ADMIN); + assertTrue(adminRole.getOwnerName().equals(HiveMetaStore.ADMIN)); + assertEquals(rawStore.listPrincipalGlobalGrants(HiveMetaStore.ADMIN, PrincipalType.ROLE) + .get(0).getPrivilege(),"All"); + assertEquals(rawStore.listRoles("adminuser", PrincipalType.USER).get(0).getRole(). + getRoleName(),HiveMetaStore.ADMIN); + assertTrue(rawStore.revokeRole(adminRole, "adminuser", PrincipalType.USER)); + } +} \ No newline at end of file diff --git metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java index 58f9957..70dadf4 100644 --- metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java +++ metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java @@ -35,7 +35,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -43,6 +42,7 @@ import java.util.Properties; import java.util.Set; import java.util.Timer; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import org.apache.commons.cli.OptionBuilder; @@ -146,6 +146,7 @@ import com.facebook.fb303.FacebookBase; import com.facebook.fb303.fb_status; +import com.google.common.base.Splitter; /** * TODO:pc remove application logic to a separate interface. @@ -164,6 +165,7 @@ * default port on which to start the Hive server */ private static final int DEFAULT_HIVE_METASTORE_PORT = 9083; + public static final String ADMIN = "ADMIN"; private static HadoopThriftAuthBridge.Server saslServer; private static boolean useSasl; @@ -189,6 +191,7 @@ public TTransport getTransport(TTransport trans) { IHMSHandler { public static final Log LOG = HiveMetaStore.LOG; private static boolean createDefaultDB = false; + private static boolean adminCreated = false; private String rawStoreClassName; private final HiveConf hiveConf; // stores datastore (jpox) properties, // right now they come from jpox.properties @@ -341,7 +344,10 @@ private boolean init() throws MetaException { alterHandlerName), hiveConf); wh = new Warehouse(hiveConf); - createDefaultDB(); + synchronized (HMSHandler.class) { + createDefaultDB(); + createAdminRoleNAddUsers(); + } if (hiveConf.getBoolean("hive.metastore.metrics.enabled", false)) { try { @@ -448,22 +454,99 @@ private void createDefaultDB_core(RawStore ms) throws MetaException, InvalidObje * @throws MetaException */ private void createDefaultDB() throws MetaException { - synchronized (HMSHandler.class) { - if (HMSHandler.createDefaultDB || !checkForDefaultDb) { - return; - } + if (HMSHandler.createDefaultDB || !checkForDefaultDb) { + return; + } + try { + createDefaultDB_core(getMS()); + } catch (InvalidObjectException e) { + throw new MetaException(e.getMessage()); + } catch (MetaException e) { + throw e; + } catch (Exception e) { + assert (e instanceof RuntimeException); + throw (RuntimeException) e; + } + } + + private void createAdminRoleNAddUsers() throws MetaException { + if(adminCreated) { + return; + } + Class authCls; + Class authIface; + try { + authCls = hiveConf.getClassByName(hiveConf.getVar(ConfVars.HIVE_AUTHORIZATION_MANAGER)); + authIface = Class.forName("org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAuthorizerFactory"); + } catch (ClassNotFoundException e) { + LOG.debug("No auth manager specified", e); + return; + } + if(!authIface.isAssignableFrom(authCls)){ + LOG.info("Invalid value for auth manager in config " + authCls.getName()); + return; + } + RawStore ms = getMS(); + try { + ms.addRole(ADMIN, ADMIN); + } catch (InvalidObjectException e) { + LOG.debug("admin role already exists",e); + } catch (NoSuchObjectException e) { + // This should never be thrown. + LOG.warn("Unexpected exception while adding ADMIN role" , e); + } + LOG.info("Added admin role in metastore"); + // now grant all privs to admin + PrivilegeBag privs = new PrivilegeBag(); + privs.addToPrivileges(new HiveObjectPrivilege( new HiveObjectRef(HiveObjectType.GLOBAL, null, + null, null, null), ADMIN, PrincipalType.ROLE, new PrivilegeGrantInfo("All", 0, ADMIN, + PrincipalType.ROLE, true))); + try { + ms.grantPrivileges(privs); + } catch (InvalidObjectException e) { + // Surprisingly these privs are already granted. + LOG.debug("Failed while granting global privs to admin", e); + } catch (NoSuchObjectException e) { + // Unlikely to be thrown. + LOG.warn("Failed while granting global privs to admin", e); + } + + // now add pre-configured users to admin role + String userStr = HiveConf.getVar(hiveConf,ConfVars.USERS_IN_ADMIN_ROLE,"").trim(); + if (userStr.isEmpty()) { + LOG.info("No user is added in admin role, since config is empty"); + return; + } + // Since user names need to be valid unix user names, per IEEE Std 1003.1-2001 they cannot + // contain comma, so we can safely split above string on comma. + + Iterator users = Splitter.on(",").trimResults().omitEmptyStrings().split(userStr). + iterator(); + if (!users.hasNext()) { + LOG.info("No user is added in admin role, since config value "+ userStr + + " is in incorrect format."); + return; + } + LOG.info("Added " + userStr + " to admin role"); + Role adminRole; + try { + adminRole = ms.getRole(ADMIN); + } catch (NoSuchObjectException e) { + LOG.error("Failed to retrieve just added admin role",e); + return; + } + while (users.hasNext()) { + String userName = users.next(); try { - createDefaultDB_core(getMS()); + ms.grantRole(adminRole, userName, PrincipalType.USER, ADMIN, PrincipalType.ROLE, true); + } catch (NoSuchObjectException e) { + LOG.error("Failed to add "+ adminRole + " in admin role",e); } catch (InvalidObjectException e) { - throw new MetaException(e.getMessage()); - } catch (MetaException e) { - throw e; - } catch (Exception e) { - assert (e instanceof RuntimeException); - throw (RuntimeException) e; + LOG.debug(userName + " already in admin role", e); } } + adminCreated = true; } private void logInfo(String m) {