org.apache.sentry.binding.hive.authz.HiveAuthzBinding.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sentry.binding.hive.authz.HiveAuthzBinding.java

Source

/*
 * 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.sentry.binding.hive.authz;

import java.lang.reflect.Constructor;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hadoop.hive.ql.metadata.AuthorizationException;
import org.apache.hadoop.hive.ql.plan.HiveOperation;
import org.apache.hadoop.hive.ql.session.SessionState;
import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
import org.apache.sentry.binding.hive.conf.HiveAuthzConf.AuthzConfVars;
import org.apache.sentry.core.Action;
import org.apache.sentry.core.Authorizable;
import org.apache.sentry.core.AuthorizationProvider;
import org.apache.sentry.core.NoAuthorizationProvider;
import org.apache.sentry.core.Server;
import org.apache.sentry.core.Subject;
import org.apache.sentry.core.Authorizable.AuthorizableType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;

public class HiveAuthzBinding {
    private static final Logger LOG = LoggerFactory.getLogger(HiveAuthzBinding.class);
    private static final Map<String, HiveAuthzBinding> authzBindingMap = new ConcurrentHashMap<String, HiveAuthzBinding>();
    private static final AtomicInteger queryID = new AtomicInteger();
    public static final String HIVE_BINDING_TAG = "hive.authz.bindings.tag";

    private final HiveAuthzConf authzConf;
    private final Server authServer;
    private final AuthorizationProvider authProvider;

    public HiveAuthzBinding(HiveConf hiveConf, HiveAuthzConf authzConf) throws Exception {
        this.authzConf = authzConf;
        this.authServer = new Server(authzConf.get(AuthzConfVars.AUTHZ_SERVER_NAME.getVar()));
        this.authProvider = getAuthProvider(hiveConf, authServer.getName());
    }

    /**
     * Retrieve the HiveAuthzBinding if the tag is saved in the given configuration
     * @param conf
     * @return HiveAuthzBinding or null
     */
    public static HiveAuthzBinding get(Configuration conf) {
        String tagName = conf.get(HIVE_BINDING_TAG);
        if (tagName == null) {
            return null;
        } else {
            return authzBindingMap.get(tagName);
        }
    }

    /**
     * store the HiveAuthzBinding in the authzBindingMap and save a tag in the given configuration
     * @param conf
     */
    public void set(Configuration conf) {
        String tagName = SessionState.get().getSessionId() + "_" + queryID.incrementAndGet();
        authzBindingMap.put(tagName, this);
        conf.set(HIVE_BINDING_TAG, tagName);
    }

    /**
     * remove the authzBindingMap entry for given tag
     * @param conf
     */
    public void clear(Configuration conf) {
        String tagName = conf.get(HIVE_BINDING_TAG);
        if (tagName == null) {
            authzBindingMap.remove(tagName);
        }
    }

    // Instantiate the configured authz provider
    private AuthorizationProvider getAuthProvider(HiveConf hiveConf, String serverName) throws Exception {
        boolean isTestingMode = Boolean.parseBoolean(
                Strings.nullToEmpty(authzConf.get(AuthzConfVars.ACCESS_TESTING_MODE.getVar())).trim());
        LOG.debug("Testing mode is " + isTestingMode);
        if (!isTestingMode) {
            String authMethod = Strings.nullToEmpty(hiveConf.getVar(ConfVars.HIVE_SERVER2_AUTHENTICATION)).trim();
            if ("none".equalsIgnoreCase(authMethod)) {
                LOG.error("HiveServer2 authentication method cannot be set to none unless testing mode is enabled");
                return new NoAuthorizationProvider();
            }
            boolean impersonation = hiveConf.getBoolVar(ConfVars.HIVE_SERVER2_KERBEROS_IMPERSONATION);
            boolean allowImpersonation = Boolean.parseBoolean(Strings
                    .nullToEmpty(authzConf.get(AuthzConfVars.AUTHZ_ALLOW_HIVE_IMPERSONATION.getVar())).trim());

            if (impersonation && !allowImpersonation) {
                LOG.error("Role based authorization does not work with HiveServer2 impersonation");
                return new NoAuthorizationProvider();
            }
        }
        String defaultUmask = hiveConf.get(CommonConfigurationKeys.FS_PERMISSIONS_UMASK_KEY);
        if ("077".equalsIgnoreCase(defaultUmask)) {
            LOG.error("HiveServer2 required a default umask of 077");
            return new NoAuthorizationProvider();
        }
        // get the provider class and resources from the authz config
        String authProviderName = authzConf.get(AuthzConfVars.AUTHZ_PROVIDER.getVar());
        String resourceName = authzConf.get(AuthzConfVars.AUTHZ_PROVIDER_RESOURCE.getVar());
        LOG.debug("Using authorization provide " + authProviderName + " with resource " + resourceName);

        // load the authz provider class
        Constructor<?> constrctor = Class.forName(authProviderName).getDeclaredConstructor(String.class,
                String.class);
        constrctor.setAccessible(true);
        return (AuthorizationProvider) constrctor.newInstance(new Object[] { resourceName, serverName });
    }

    /**
     * Validate the privilege for the given operation for the given subject
     * @param hiveOp
     * @param stmtAuthPrivileges
     * @param subject
     * @param currDB
     * @param inputEntities
     * @param outputEntities
     * @throws AuthorizationException
     */
    public void authorize(HiveOperation hiveOp, HiveAuthzPrivileges stmtAuthPrivileges, Subject subject,
            List<List<Authorizable>> inputHierarchyList, List<List<Authorizable>> outputHierarchyList)
            throws AuthorizationException {
        boolean isDebug = LOG.isDebugEnabled();
        if (isDebug) {
            LOG.debug("Going to authorize statement " + hiveOp.name() + " for subject " + subject.getName());
        }

        /* for each read and write entity captured by the compiler -
         *    check if that object type is part of the input/output privilege list
         *    If it is, then validate the access.
         * Note the hive compiler gathers information on additional entities like partitions,
         * etc which are not of our interest at this point. Hence its very
         * much possible that the we won't be validating all the entities in the given list
         */

        // Check read entities
        Map<AuthorizableType, EnumSet<Action>> requiredInputPrivileges = stmtAuthPrivileges.getInputPrivileges();
        for (List<Authorizable> inputHierarchy : inputHierarchyList) {
            if (isDebug) {
                LOG.debug("requiredInputPrivileges = " + requiredInputPrivileges);
                LOG.debug("inputHierarchy = " + inputHierarchy);
                LOG.debug("getAuthzType(inputHierarchy) = " + getAuthzType(inputHierarchy));
            }
            if (requiredInputPrivileges.containsKey(getAuthzType(inputHierarchy))) {
                EnumSet<Action> inputPrivSet = requiredInputPrivileges.get(getAuthzType(inputHierarchy));
                if (!authProvider.hasAccess(subject, inputHierarchy, inputPrivSet)) {
                    throw new AuthorizationException(
                            "User " + subject.getName() + " does not have privileges for " + hiveOp.name());
                }
            }
        }
        // Check write entities
        Map<AuthorizableType, EnumSet<Action>> requiredOutputPrivileges = stmtAuthPrivileges.getOutputPrivileges();
        for (List<Authorizable> outputHierarchy : outputHierarchyList) {
            if (isDebug) {
                LOG.debug("requiredOutputPrivileges = " + requiredOutputPrivileges);
                LOG.debug("outputHierarchy = " + outputHierarchy);
                LOG.debug("getAuthzType(outputHierarchy) = " + getAuthzType(outputHierarchy));
            }
            if (requiredOutputPrivileges.containsKey(getAuthzType(outputHierarchy))) {
                EnumSet<Action> outputPrivSet = requiredOutputPrivileges.get(getAuthzType(outputHierarchy));
                if (!authProvider.hasAccess(subject, outputHierarchy, outputPrivSet)) {
                    throw new AuthorizationException(
                            "User " + subject.getName() + " does not have priviliedges for " + hiveOp.name());
                }
            }
        }
    }

    public Server getAuthServer() {
        return authServer;
    }

    private AuthorizableType getAuthzType(List<Authorizable> hierarchy) {
        return hierarchy.get(hierarchy.size() - 1).getAuthzType();
    }
}