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

org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticatedURL Maven / Gradle / Ivy

There is a newer version: 3.4.0
Show newest version
/**
 * 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.thirdparty.com.google.common.base.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 DelegationTokenAuthenticatedURL is a
 * {@link AuthenticatedURL} sub-class with built-in Hadoop Delegation Token
 * functionality.
 * 

* The authentication mechanisms supported by default are Hadoop Simple * authentication (also known as pseudo authentication) and Kerberos SPNEGO * authentication. *

* Additional authentication mechanisms can be supported via {@link * DelegationTokenAuthenticator} implementations. *

* 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. *

* AuthenticatedURL 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 DO_AS 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 delegationToken; public org.apache.hadoop.security.token.Token getDelegationToken() { return delegationToken; } public void setDelegationToken( org.apache.hadoop.security.token.Token delegationToken) { this.delegationToken = delegationToken; } } private static Class 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 authenticator) { DEFAULT_AUTHENTICATOR = authenticator; } /** * Returns the default {@link DelegationTokenAuthenticator} class to use when * an {@link DelegationTokenAuthenticatedURL} instance is created without * specifying one. *

* The default class is {@link KerberosDelegationTokenAuthenticator} * * @return the delegation token authenticator class to use as default. */ public static Class 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 DelegationTokenAuthenticatedURL. *

* An instance of the default {@link DelegationTokenAuthenticator} will be * used. */ public DelegationTokenAuthenticatedURL() { this(null, null); } /** * Creates an DelegationTokenAuthenticatedURL. * * @param authenticator the {@link DelegationTokenAuthenticator} instance to * use, if null the default one will be used. */ public DelegationTokenAuthenticatedURL( DelegationTokenAuthenticator authenticator) { this(authenticator, null); } /** * Creates an DelegationTokenAuthenticatedURL using the default * {@link DelegationTokenAuthenticator} class. * * @param connConfigurator a connection configurator. */ public DelegationTokenAuthenticatedURL( ConnectionConfigurator connConfigurator) { this(null, connConfigurator); } /** * Creates an DelegationTokenAuthenticatedURL. * * @param authenticator the {@link DelegationTokenAuthenticator} instance to * use, if null 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. *

* This method is provided to enable WebHDFS backwards compatibility. * * @param useQueryString TRUE if the token is transmitted in the * URL query string, FALSE 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 TRUE if the token is transmitted in the URL query * string, FALSE 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 * Authenticator. * * @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 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 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 * Authenticator. If the doAs parameter is not NULL, * the request will be done on behalf of the specified doAs 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 extraParams = new HashMap(); org.apache.hadoop.security.token.Token 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 ) 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. */ @InterfaceAudience.Private public org.apache.hadoop.security.token.Token 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 dToken = creds.getToken(service); LOG.debug("Using delegation token {} from service:{}", dToken, service); return dToken; } /** * Requests a delegation token using the configured Authenticator * 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 getDelegationToken(URL url, Token token, String renewer) throws IOException, AuthenticationException { return getDelegationToken(url, token, renewer, null); } /** * Requests a delegation token using the configured Authenticator * 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 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 Authenticator 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. */ 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 Authenticator 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. */ 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 Authenticator. * * @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 Authenticator. * * @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; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy