hadoop DelegationTokenAuthenticatedURL 源码

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

haddop DelegationTokenAuthenticatedURL 代码

文件路径:/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticatedURL.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.token.delegation.web;

import org.apache.hadoop.util.Preconditions;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.Credentials;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.ConnectionConfigurator;
import org.apache.hadoop.security.token.TokenIdentifier;
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * The <code>DelegationTokenAuthenticatedURL</code> is a
 * {@link AuthenticatedURL} sub-class with built-in Hadoop Delegation Token
 * functionality.
 * <p>
 * The authentication mechanisms supported by default are Hadoop Simple
 * authentication (also known as pseudo authentication) and Kerberos SPNEGO
 * authentication.
 * <p>
 * Additional authentication mechanisms can be supported via {@link
 * DelegationTokenAuthenticator} implementations.
 * <p>
 * The default {@link DelegationTokenAuthenticator} is the {@link
 * KerberosDelegationTokenAuthenticator} class which supports
 * automatic fallback from Kerberos SPNEGO to Hadoop Simple authentication via
 * the {@link PseudoDelegationTokenAuthenticator} class.
 * <p>
 * <code>AuthenticatedURL</code> instances are not thread-safe.
 */
@InterfaceAudience.Public
@InterfaceStability.Unstable
public class DelegationTokenAuthenticatedURL extends AuthenticatedURL {

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

  /**
   * Constant used in URL's query string to perform a proxy user request, the
   * value of the <code>DO_AS</code> parameter is the user the request will be
   * done on behalf of.
   */
  static final String DO_AS = "doAs";

  /**
   * Client side authentication token that handles Delegation Tokens.
   */
  @InterfaceAudience.Public
  @InterfaceStability.Unstable
  public static class Token extends AuthenticatedURL.Token {
    private
    org.apache.hadoop.security.token.Token<AbstractDelegationTokenIdentifier>
        delegationToken;

    public org.apache.hadoop.security.token.Token<AbstractDelegationTokenIdentifier>
    getDelegationToken() {
      return delegationToken;
    }
    public void setDelegationToken(
        org.apache.hadoop.security.token.Token<AbstractDelegationTokenIdentifier> delegationToken) {
      this.delegationToken = delegationToken;
    }

  }

  private static Class<? extends DelegationTokenAuthenticator>
      DEFAULT_AUTHENTICATOR = KerberosDelegationTokenAuthenticator.class;

  /**
   * Sets the default {@link DelegationTokenAuthenticator} class to use when an
   * {@link DelegationTokenAuthenticatedURL} instance is created without
   * specifying one.
   *
   * The default class is {@link KerberosDelegationTokenAuthenticator}
   *
   * @param authenticator the authenticator class to use as default.
   */
  public static void setDefaultDelegationTokenAuthenticator(
      Class<? extends DelegationTokenAuthenticator> authenticator) {
    DEFAULT_AUTHENTICATOR = authenticator;
  }

  /**
   * Returns the default {@link DelegationTokenAuthenticator} class to use when
   * an {@link DelegationTokenAuthenticatedURL} instance is created without
   * specifying one.
   * <p>
   * The default class is {@link KerberosDelegationTokenAuthenticator}
   *
   * @return the delegation token authenticator class to use as default.
   */
  public static Class<? extends DelegationTokenAuthenticator>
      getDefaultDelegationTokenAuthenticator() {
    return DEFAULT_AUTHENTICATOR;
  }

  private static DelegationTokenAuthenticator
      obtainDelegationTokenAuthenticator(DelegationTokenAuthenticator dta,
            ConnectionConfigurator connConfigurator) {
    try {
      if (dta == null) {
        dta = DEFAULT_AUTHENTICATOR.newInstance();
        dta.setConnectionConfigurator(connConfigurator);
      }
      return dta;
    } catch (Exception ex) {
      throw new IllegalArgumentException(ex);
    }
  }

  private boolean useQueryStringforDelegationToken = false;

  /**
   * Creates an <code>DelegationTokenAuthenticatedURL</code>.
   * <p>
   * An instance of the default {@link DelegationTokenAuthenticator} will be
   * used.
   */
  public DelegationTokenAuthenticatedURL() {
    this(null, null);
  }

  /**
   * Creates an <code>DelegationTokenAuthenticatedURL</code>.
   *
   * @param authenticator the {@link DelegationTokenAuthenticator} instance to
   * use, if <code>null</code> the default one will be used.
   */
  public DelegationTokenAuthenticatedURL(
      DelegationTokenAuthenticator authenticator) {
    this(authenticator, null);
  }

  /**
   * Creates an <code>DelegationTokenAuthenticatedURL</code> using the default
   * {@link DelegationTokenAuthenticator} class.
   *
   * @param connConfigurator a connection configurator.
   */
  public DelegationTokenAuthenticatedURL(
      ConnectionConfigurator connConfigurator) {
    this(null, connConfigurator);
  }

  /**
   * Creates an <code>DelegationTokenAuthenticatedURL</code>.
   *
   * @param authenticator the {@link DelegationTokenAuthenticator} instance to
   * use, if <code>null</code> the default one will be used.
   * @param connConfigurator a connection configurator.
   */
  public DelegationTokenAuthenticatedURL(
      DelegationTokenAuthenticator authenticator,
      ConnectionConfigurator connConfigurator) {
    super(obtainDelegationTokenAuthenticator(authenticator, connConfigurator),
            connConfigurator);
  }

  /**
   * Sets if delegation token should be transmitted in the URL query string.
   * By default it is transmitted using the
   * {@link DelegationTokenAuthenticator#DELEGATION_TOKEN_HEADER} HTTP header.
   * <p>
   * This method is provided to enable WebHDFS backwards compatibility.
   *
   * @param useQueryString  <code>TRUE</code> if the token is transmitted in the
   * URL query string, <code>FALSE</code> if the delegation token is transmitted
   * using the {@link DelegationTokenAuthenticator#DELEGATION_TOKEN_HEADER} HTTP
   * header.
   */
  @Deprecated
  protected void setUseQueryStringForDelegationToken(boolean useQueryString) {
    useQueryStringforDelegationToken = useQueryString;
  }

  /**
   * Returns if delegation token is transmitted as a HTTP header.
   *
   * @return <code>TRUE</code> if the token is transmitted in the URL query
   * string, <code>FALSE</code> if the delegation token is transmitted using the
   * {@link DelegationTokenAuthenticator#DELEGATION_TOKEN_HEADER} HTTP header.
   */
  public boolean useQueryStringForDelegationToken() {
    return useQueryStringforDelegationToken;
  }

  /**
   * Returns an authenticated {@link HttpURLConnection}, it uses a Delegation
   * Token only if the given auth token is an instance of {@link Token} and
   * it contains a Delegation Token, otherwise use the configured
   * {@link DelegationTokenAuthenticator} to authenticate the connection.
   *
   * @param url the URL to connect to. Only HTTP/S URLs are supported.
   * @param token the authentication token being used for the user.
   * @return an authenticated {@link HttpURLConnection}.
   * @throws IOException if an IO error occurred.
   * @throws AuthenticationException if an authentication exception occurred.
   */
  @Override
  public HttpURLConnection openConnection(URL url, AuthenticatedURL.Token token)
      throws IOException, AuthenticationException {
    return (token instanceof Token) ? openConnection(url, (Token) token)
                                    : super.openConnection(url ,token);
  }

  /**
   * Returns an authenticated {@link HttpURLConnection}. If the Delegation
   * Token is present, it will be used taking precedence over the configured
   * <code>Authenticator</code>.
   *
   * @param url the URL to connect to. Only HTTP/S URLs are supported.
   * @param token the authentication token being used for the user.
   * @return an authenticated {@link HttpURLConnection}.
   * @throws IOException if an IO error occurred.
   * @throws AuthenticationException if an authentication exception occurred.
   */
  public HttpURLConnection openConnection(URL url, Token token)
      throws IOException, AuthenticationException {
    return openConnection(url, token, null);
  }

  private URL augmentURL(URL url, Map<String, String> params)
      throws IOException {
    if (params != null && params.size() > 0) {
      String urlStr = url.toExternalForm();
      StringBuilder sb = new StringBuilder(urlStr);
      String separator = (urlStr.contains("?")) ? "&" : "?";
      for (Map.Entry<String, String> param : params.entrySet()) {
        sb.append(separator).append(param.getKey()).append("=").append(
            param.getValue());
        separator = "&";
      }
      url = new URL(sb.toString());
    }
    return url;
  }

  /**
   * Returns an authenticated {@link HttpURLConnection}. If the Delegation
   * Token is present, it will be used taking precedence over the configured
   * <code>Authenticator</code>. If the <code>doAs</code> parameter is not NULL,
   * the request will be done on behalf of the specified <code>doAs</code> user.
   *
   * @param url the URL to connect to. Only HTTP/S URLs are supported.
   * @param token the authentication token being used for the user.
   * @param doAs user to do the the request on behalf of, if NULL the request is
   * as self.
   * @return an authenticated {@link HttpURLConnection}.
   * @throws IOException if an IO error occurred.
   * @throws AuthenticationException if an authentication exception occurred.
   */
  @SuppressWarnings("unchecked")
  public HttpURLConnection openConnection(URL url, Token token, String doAs)
      throws IOException, AuthenticationException {
    Preconditions.checkNotNull(url, "url");
    Preconditions.checkNotNull(token, "token");
    Map<String, String> extraParams = new HashMap<String, String>();
    org.apache.hadoop.security.token.Token<? extends TokenIdentifier> dToken
        = null;
    LOG.debug("Connecting to url {} with token {} as {}", url, token, doAs);
    // if we have valid auth token, it takes precedence over a delegation token
    // and we don't even look for one.
    if (!token.isSet()) {
      // delegation token
      Credentials creds = UserGroupInformation.getCurrentUser().
          getCredentials();
      LOG.debug("Token not set, looking for delegation token. Creds:{},"
          + " size:{}", creds.getAllTokens(), creds.numberOfTokens());
      if (!creds.getAllTokens().isEmpty()) {
        dToken = selectDelegationToken(url, creds);
        if (dToken != null) {
          if (useQueryStringForDelegationToken()) {
            // delegation token will go in the query string, injecting it
            extraParams.put(
                KerberosDelegationTokenAuthenticator.DELEGATION_PARAM,
                dToken.encodeToUrlString());
          } else {
            // delegation token will go as request header, setting it in the
            // auth-token to ensure no authentication handshake is triggered
            // (if we have a delegation token, we are authenticated)
            // the delegation token header is injected in the connection request
            // at the end of this method.
            token.delegationToken = (org.apache.hadoop.security.token.Token
                <AbstractDelegationTokenIdentifier>) dToken;
          }
        }
      }
    }

    // proxyuser
    if (doAs != null) {
      extraParams.put(DO_AS, URLEncoder.encode(doAs, "UTF-8"));
    }

    url = augmentURL(url, extraParams);
    HttpURLConnection conn = super.openConnection(url, token);
    if (!token.isSet() && !useQueryStringForDelegationToken() && dToken != null) {
      // injecting the delegation token header in the connection request
      conn.setRequestProperty(
          DelegationTokenAuthenticator.DELEGATION_TOKEN_HEADER,
          dToken.encodeToUrlString());
    }
    return conn;
  }

  /**
   * Select a delegation token from all tokens in credentials, based on url.
   *
   * @param url url.
   * @param creds credentials.
   * @return token.
   */
  @InterfaceAudience.Private
  public org.apache.hadoop.security.token.Token<? extends TokenIdentifier>
      selectDelegationToken(URL url, Credentials creds) {
    final InetSocketAddress serviceAddr = new InetSocketAddress(url.getHost(),
        url.getPort());
    final Text service = SecurityUtil.buildTokenService(serviceAddr);
    org.apache.hadoop.security.token.Token<? extends TokenIdentifier> dToken =
        creds.getToken(service);
    LOG.debug("Using delegation token {} from service:{}", dToken, service);
    return dToken;
  }

  /**
   * Requests a delegation token using the configured <code>Authenticator</code>
   * for authentication.
   *
   * @param url the URL to get the delegation token from. Only HTTP/S URLs are
   * supported.
   * @param token the authentication token being used for the user where the
   * Delegation token will be stored.
   * @param renewer the renewer user.
   * @return a delegation token.
   * @throws IOException if an IO error occurred.
   * @throws AuthenticationException if an authentication exception occurred.
   */
  public org.apache.hadoop.security.token.Token<AbstractDelegationTokenIdentifier>
      getDelegationToken(URL url, Token token, String renewer)
          throws IOException, AuthenticationException {
    return getDelegationToken(url, token, renewer, null);
  }

  /**
   * Requests a delegation token using the configured <code>Authenticator</code>
   * for authentication.
   *
   * @param url the URL to get the delegation token from. Only HTTP/S URLs are
   * supported.
   * @param token the authentication token being used for the user where the
   * Delegation token will be stored.
   * @param renewer the renewer user.
   * @param doAsUser the user to do as, which will be the token owner.
   * @return a delegation token.
   * @throws IOException if an IO error occurred.
   * @throws AuthenticationException if an authentication exception occurred.
   */
  public org.apache.hadoop.security.token.Token<AbstractDelegationTokenIdentifier>
      getDelegationToken(URL url, Token token, String renewer, String doAsUser)
          throws IOException, AuthenticationException {
    Preconditions.checkNotNull(url, "url");
    Preconditions.checkNotNull(token, "token");
    try {
      token.delegationToken =
          ((KerberosDelegationTokenAuthenticator) getAuthenticator()).
              getDelegationToken(url, token, renewer, doAsUser);
      return token.delegationToken;
    } catch (IOException ex) {
      token.delegationToken = null;
      throw ex;
    }
  }

  /**
   * Renews a delegation token from the server end-point using the
   * configured <code>Authenticator</code> for authentication.
   *
   * @param url the URL to renew the delegation token from. Only HTTP/S URLs are
   * supported.
   * @param token the authentication token with the Delegation Token to renew.
   * @throws IOException if an IO error occurred.
   * @throws AuthenticationException if an authentication exception occurred.
   * @return delegation token long value.
   */
  public long renewDelegationToken(URL url, Token token)
      throws IOException, AuthenticationException {
    return renewDelegationToken(url, token, null);
  }

  /**
   * Renews a delegation token from the server end-point using the
   * configured <code>Authenticator</code> for authentication.
   *
   * @param url the URL to renew the delegation token from. Only HTTP/S URLs are
   * supported.
   * @param token the authentication token with the Delegation Token to renew.
   * @param doAsUser the user to do as, which will be the token owner.
   * @throws IOException if an IO error occurred.
   * @throws AuthenticationException if an authentication exception occurred.
   * @return delegation token long value.
   */
  public long renewDelegationToken(URL url, Token token, String doAsUser)
      throws IOException, AuthenticationException {
    Preconditions.checkNotNull(url, "url");
    Preconditions.checkNotNull(token, "token");
    Preconditions.checkNotNull(token.delegationToken,
        "No delegation token available");
    try {
      return ((KerberosDelegationTokenAuthenticator) getAuthenticator()).
          renewDelegationToken(url, token, token.delegationToken, doAsUser);
    } catch (IOException ex) {
      token.delegationToken = null;
      throw ex;
    }
  }

  /**
   * Cancels a delegation token from the server end-point. It does not require
   * being authenticated by the configured <code>Authenticator</code>.
   *
   * @param url the URL to cancel the delegation token from. Only HTTP/S URLs
   * are supported.
   * @param token the authentication token with the Delegation Token to cancel.
   * @throws IOException if an IO error occurred.
   */
  public void cancelDelegationToken(URL url, Token token)
      throws IOException {
    cancelDelegationToken(url, token, null);
  }

  /**
   * Cancels a delegation token from the server end-point. It does not require
   * being authenticated by the configured <code>Authenticator</code>.
   *
   * @param url the URL to cancel the delegation token from. Only HTTP/S URLs
   * are supported.
   * @param token the authentication token with the Delegation Token to cancel.
   * @param doAsUser the user to do as, which will be the token owner.
   * @throws IOException if an IO error occurred.
   */
  public void cancelDelegationToken(URL url, Token token, String doAsUser)
      throws IOException {
    Preconditions.checkNotNull(url, "url");
    Preconditions.checkNotNull(token, "token");
    Preconditions.checkNotNull(token.delegationToken,
        "No delegation token available");
    try {
      ((KerberosDelegationTokenAuthenticator) getAuthenticator()).
          cancelDelegationToken(url, token, token.delegationToken, doAsUser);
    } finally {
      token.delegationToken = null;
    }
  }

}

相关信息

hadoop 源码目录

相关文章

hadoop DelegationTokenAuthenticationFilter 源码

hadoop DelegationTokenAuthenticationHandler 源码

hadoop DelegationTokenAuthenticator 源码

hadoop DelegationTokenIdentifier 源码

hadoop DelegationTokenManager 源码

hadoop HttpUserGroupInformation 源码

hadoop KerberosDelegationTokenAuthenticationHandler 源码

hadoop KerberosDelegationTokenAuthenticator 源码

hadoop MultiSchemeDelegationTokenAuthenticationHandler 源码

hadoop PseudoDelegationTokenAuthenticationHandler 源码

0  赞