All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flume.sink.hbase.HBaseSinkSecurityManager Maven / Gradle / Ivy

/*
 * 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.flume.sink.hbase;

import com.google.common.base.Preconditions;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import org.apache.flume.FlumeException;
import org.apache.flume.sink.hdfs.KerberosUser;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class to handle logging into HBase with the credentials passed in.
 */
public class HBaseSinkSecurityManager {

  /*
   * volatile for safe publication. Since this is updated only by
   * a single thread (configuration) and read later by the sink threads,
   * this can just be volatile, no need of Atomic reference.
   */
  private volatile static KerberosUser loggedInUser;
  private static final String FLUME_KEYTAB_KEY = "flume.keytab.key";
  private static final String FLUME_PRINCIPAL_KEY = "flume.principal.key";
  private static final Logger LOG =
          LoggerFactory.getLogger(HBaseSinkSecurityManager.class);

  /**
   * Checks if security is enabled for the HBase cluster.
   *
   * @return - true if security is enabled on the HBase cluster and
   * the underlying HDFS cluster.
   */
  public static boolean isSecurityEnabled(Configuration conf) {
    return User.isSecurityEnabled() && User.isHBaseSecurityEnabled(conf);
  }

  /**
   * Login the user using the configuration, and the hostname specified to use
   * for logging in.
   *
   * @param conf - Configuration to use for logging the user in.
   * @param hostname - The hostname to use for logging the user in. If no
   * hostname is specified (null or empty string), the canonical hostname for
   * the address returned by {@linkplain InetAddress#getLocalHost()} will be
   * used.
   * @return The logged in HBase {@linkplain User}.
   * @throws IOException if login failed, or hostname lookup failed.
   */
  public static synchronized User login(Configuration conf, String hostname,
          String kerberosPrincipal, String kerberosKeytab) throws IOException {
    if (kerberosPrincipal.isEmpty()) {
      String msg = "Login failed, since kerberos principal was not specified.";
      LOG.error(msg);
      throw new IllegalArgumentException(msg);
    }
    if (kerberosKeytab.isEmpty()) {
      String msg = "Login failed, since kerberos keytab was not specified.";
      LOG.error(msg);
      throw new IllegalArgumentException(msg);
    } else {
      //If keytab is specified, user should want it take effect.
      //HDFSEventSink will halt when keytab file is non-exist or unreadable
      File kfile = new File(kerberosKeytab);
      if (!(kfile.isFile() && kfile.canRead())) {
        throw new IllegalArgumentException("The keyTab file: "
                + kerberosKeytab + " is nonexistent or can't read. "
                + "Please specify a readable keytab file for Kerberos auth.");
      }
    }
    String principal = kerberosPrincipal;
    try {
      // resolves _HOST pattern using standard Hadoop search/replace
      // via DNS lookup when 2nd argument is empty
      principal = SecurityUtil.getServerPrincipal(kerberosPrincipal,"");
    } catch (IOException e) {
      LOG.error("Host lookup error resolving kerberos principal ("
              + kerberosPrincipal + "). Exception follows.", e);
      throw e;
    }
    Preconditions.checkNotNull(principal, "Principal must not be null");
    KerberosUser newUser = new KerberosUser(principal, kerberosKeytab);
    //The HDFS Sink does not allow login credentials to change.
    //To be uniform, we will do the same thing here.
    User hbaseUser = null;
    boolean loggedIn = false;
    if (loggedInUser != null) {
      Preconditions.checkArgument(newUser.equals(loggedInUser),
              "Cannot switch kerberos credentials during a reconfiguration. "
              + "Please restart the agent to set the new credentials.");
      try {
        hbaseUser = User.create(UserGroupInformation.getLoginUser());
        loggedIn = true;
      } catch (IOException ex) {
        LOG.warn("Previous login does not exist, "
                + "will authenticate against KDC");
      }
    }
    if (!loggedIn) {
      if (hostname == null || hostname.isEmpty()) {
        hostname = InetAddress.getLocalHost().getCanonicalHostName();
      }
      conf.set(FLUME_KEYTAB_KEY, kerberosKeytab);
      conf.set(FLUME_PRINCIPAL_KEY, principal);
      User.login(conf, FLUME_KEYTAB_KEY, FLUME_PRINCIPAL_KEY, hostname);
      hbaseUser = User.create(UserGroupInformation.getLoginUser());
      loggedInUser = newUser;
      //TODO: Set the loggedInUser to the current user.
      LOG.info("Logged into HBase as user: " + hbaseUser.getName());
    }
    return hbaseUser;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy