hadoop ProviderUtils 源码

  • 2022-10-20
  • 浏览 (350)

haddop ProviderUtils 代码

文件路径:/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/ProviderUtils.java

/**
 * 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.security;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;

import org.apache.hadoop.classification.VisibleForTesting;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.alias.CredentialProviderFactory;
import org.apache.hadoop.security.alias.JavaKeyStoreProvider;
import org.apache.hadoop.security.alias.LocalJavaKeyStoreProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility methods for both key and credential provider APIs.
 *
 */
public final class ProviderUtils {
  @VisibleForTesting
  public static final String NO_PASSWORD_WARN =
      "WARNING: You have accepted the use of the default provider password\n" +
      "by not configuring a password in one of the two following locations:\n";
  @VisibleForTesting
  public static final String NO_PASSWORD_ERROR =
      "ERROR: The provider cannot find a password in the expected " +
      "locations.\nPlease supply a password using one of the " +
      "following two mechanisms:\n";
  @VisibleForTesting
  public static final String NO_PASSWORD_CONT =
      "Continuing with the default provider password.\n";
  @VisibleForTesting
  public static final String NO_PASSWORD_INSTRUCTIONS_DOC =
      "Please review the documentation regarding provider passwords in\n" +
      "the keystore passwords section of the Credential Provider API\n";

  private static final Logger LOG =
      LoggerFactory.getLogger(ProviderUtils.class);

  /**
   * Hidden ctor to ensure that this utility class isn't
   * instantiated explicitly.
   */
  private ProviderUtils() {
    // hide ctor for checkstyle compliance
  }

  /**
   * Convert a nested URI to decode the underlying path. The translation takes
   * the authority and parses it into the underlying scheme and authority.
   * For example, "myscheme://hdfs@nn/my/path" is converted to
   * "hdfs://nn/my/path".
   * @param nestedUri the URI from the nested URI
   * @return the unnested path
   */
  public static Path unnestUri(URI nestedUri) {
    StringBuilder result = new StringBuilder();
    String authority = nestedUri.getAuthority();
    if (authority != null) {
      String[] parts = nestedUri.getAuthority().split("@", 2);
      result.append(parts[0])
          .append("://");
      if (parts.length == 2) {
        result.append(parts[1]);
      }
    }
    result.append(nestedUri.getPath());
    if (nestedUri.getQuery() != null) {
      result.append("?");
      result.append(nestedUri.getQuery());
    }
    if (nestedUri.getFragment() != null) {
      result.append("#");
      result.append(nestedUri.getFragment());
    }
    return new Path(result.toString());
  }

  /**
   * Mangle given local java keystore file URI to allow use as a
   * LocalJavaKeyStoreProvider.
   * @param localFile absolute URI with file scheme and no authority component.
   *                  i.e. return of File.toURI,
   *                  e.g. file:///home/larry/creds.jceks
   * @return URI of the form localjceks://file/home/larry/creds.jceks
   * @throws IllegalArgumentException if localFile isn't not a file uri or if it
   *                                  has an authority component.
   * @throws URISyntaxException if the wrapping process violates RFC 2396
   */
  public static URI nestURIForLocalJavaKeyStoreProvider(final URI localFile)
      throws URISyntaxException {
    if (!("file".equals(localFile.getScheme()))) {
      throw new IllegalArgumentException("passed URI had a scheme other than " +
          "file.");
    }
    if (localFile.getAuthority() != null) {
      throw new IllegalArgumentException("passed URI must not have an " +
          "authority component. For non-local keystores, please use " +
          JavaKeyStoreProvider.class.getName());
    }
    return new URI(LocalJavaKeyStoreProvider.SCHEME_NAME,
        "//file" + localFile.getSchemeSpecificPart(), localFile.getFragment());
  }

  /**
   * There are certain integrations of the credential provider API in
   * which a recursive dependency between the provider and the hadoop
   * filesystem abstraction causes a problem. These integration points
   * need to leverage this utility method to remove problematic provider
   * types from the existing provider path within the configuration.
   *
   * @param config the existing configuration with provider path
   * @param fileSystemClass the class which providers must be compatible
   * @return Configuration clone with new provider path
   * @throws IOException raised on errors performing I/O.
   */
  public static Configuration excludeIncompatibleCredentialProviders(
      Configuration config, Class<? extends FileSystem> fileSystemClass)
          throws IOException {

    String providerPath = config.get(
        CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH);

    if (providerPath == null) {
      return config;
    }
    StringBuffer newProviderPath = new StringBuffer();
    String[] providers = providerPath.split(",");
    Path path = null;
    for (String provider: providers) {
      try {
        path = unnestUri(new URI(provider));
        Class<? extends FileSystem> clazz = null;
        try {
          String scheme = path.toUri().getScheme();
          clazz = FileSystem.getFileSystemClass(scheme, config);
        } catch (IOException ioe) {
          // not all providers are filesystem based
          // for instance user:/// will not be able to
          // have a filesystem class associated with it.
          if (newProviderPath.length() > 0) {
            newProviderPath.append(",");
          }
          newProviderPath.append(provider);
        }
        if (clazz != null) {
          if (fileSystemClass.isAssignableFrom(clazz)) {
            LOG.debug("Filesystem based provider excluded from provider " +
                "path due to recursive dependency: {}", provider);
          } else {
            if (newProviderPath.length() > 0) {
              newProviderPath.append(",");
            }
            newProviderPath.append(provider);
          }
        }
      } catch (URISyntaxException e) {
        LOG.warn("Credential Provider URI is invalid." + provider);
      }
    }

    String effectivePath = newProviderPath.toString();
    if (effectivePath.equals(providerPath)) {
      return config;
    }

    Configuration conf = new Configuration(config);
    if (effectivePath.equals("")) {
      conf.unset(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH);
    } else {
      conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH,
          effectivePath);
    }
    return conf;
  }

  /**
   * The password is either found in the environment or in a file. This
   * routine implements the logic for locating the password in these
   * locations.
   *
   * @param envWithPass  The name of the environment variable that might
   *                     contain the password. Must not be null.
   * @param fileWithPass The name of a file that could contain the password.
   *                     Can be null.
   * @return The password as a char []; null if not found.
   * @throws IOException If fileWithPass is non-null and points to a
   * nonexistent file or a file that fails to open and be read properly.
   */
  public static char[] locatePassword(String envWithPass, String fileWithPass)
      throws IOException {
    char[] pass = null;
    if (System.getenv().containsKey(envWithPass)) {
      pass = System.getenv(envWithPass).toCharArray();
    }
    if (pass == null) {
      if (fileWithPass != null) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        URL pwdFile = cl.getResource(fileWithPass);
        if (pwdFile == null) {
          // Provided Password file does not exist
          throw new IOException("Password file does not exist");
        }
        try (InputStream is = pwdFile.openStream()) {
          pass = IOUtils.toString(is, StandardCharsets.UTF_8).trim().toCharArray();
        }
      }
    }
    return pass;
  }

  private static String noPasswordInstruction(String envKey, String fileKey) {
    return
        "    * In the environment variable " + envKey + "\n" +
        "    * In a file referred to by the configuration entry\n" +
        "      " + fileKey + ".\n" +
        NO_PASSWORD_INSTRUCTIONS_DOC;
  }

  public static String noPasswordWarning(String envKey, String fileKey) {
    return NO_PASSWORD_WARN + noPasswordInstruction(envKey, fileKey) +
        NO_PASSWORD_CONT;
  }

  public static String noPasswordError(String envKey, String fileKey) {
    return NO_PASSWORD_ERROR + noPasswordInstruction(envKey, fileKey);
  }
}

相关信息

hadoop 源码目录

相关文章

hadoop AccessControlException 源码

hadoop AnnotatedSecurityInfo 源码

hadoop AuthenticationFilterInitializer 源码

hadoop CompositeGroupsMapping 源码

hadoop Credentials 源码

hadoop FastSaslClientFactory 源码

hadoop FastSaslServerFactory 源码

hadoop GroupMappingServiceProvider 源码

hadoop Groups 源码

hadoop HadoopKerberosName 源码

0  赞