001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.hbase.security.token;
020
021import java.io.IOException;
022
023import org.apache.yetus.audience.InterfaceAudience;
024import org.apache.yetus.audience.InterfaceStability;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027import org.apache.hadoop.fs.FileSystem;
028import org.apache.hadoop.hbase.security.UserProvider;
029import org.apache.hadoop.security.token.Token;
030
031/**
032 * Helper class to obtain a filesystem delegation token.
033 * Mainly used by Map-Reduce jobs that requires to read/write data to 
034 * a remote file-system (e.g. BulkLoad, ExportSnapshot).
035 */
036@InterfaceAudience.Private
037@InterfaceStability.Evolving
038public class FsDelegationToken {
039  private static final Logger LOG = LoggerFactory.getLogger(FsDelegationToken.class);
040
041  private final UserProvider userProvider;
042  private final String renewer;
043
044  private boolean hasForwardedToken = false;
045  private Token<?> userToken = null;
046  private FileSystem fs = null;
047
048  /*
049   * @param renewer the account name that is allowed to renew the token.
050   */
051  public FsDelegationToken(final UserProvider userProvider, final String renewer) {
052    this.userProvider = userProvider;
053    this.renewer = renewer;
054  }
055
056  /**
057   * Acquire the delegation token for the specified filesytem.
058   * Before requesting a new delegation token, tries to find one already available.
059   *
060   * @param fs the filesystem that requires the delegation token
061   * @throws IOException on fs.getDelegationToken() failure
062   */
063  public void acquireDelegationToken(final FileSystem fs)
064      throws IOException {
065    if (userProvider.isHadoopSecurityEnabled()) {
066      this.fs = fs;
067      userToken = userProvider.getCurrent().getToken("HDFS_DELEGATION_TOKEN",
068                                                      fs.getCanonicalServiceName());
069      if (userToken == null) {
070        hasForwardedToken = false;
071        try {
072          userToken = fs.getDelegationToken(renewer);
073        } catch (NullPointerException npe) {
074          // we need to handle NullPointerException in case HADOOP-10009 is missing
075          LOG.error("Failed to get token for " + renewer);
076        }
077      } else {
078        hasForwardedToken = true;
079        LOG.info("Use the existing token: " + userToken);
080      }
081    }
082  }
083
084  /**
085   * Releases a previously acquired delegation token.
086   */
087  public void releaseDelegationToken() {
088    if (userProvider.isHadoopSecurityEnabled()) {
089      if (userToken != null && !hasForwardedToken) {
090        try {
091          userToken.cancel(this.fs.getConf());
092        } catch (Exception e) {
093          LOG.warn("Failed to cancel HDFS delegation token: " + userToken, e);
094        }
095      }
096      this.userToken = null;
097      this.fs = null;
098    }
099  }
100
101  public UserProvider getUserProvider() {
102    return userProvider;
103  }
104
105  /**
106   * @return the account name that is allowed to renew the token.
107   */
108  public String getRenewer() {
109    return renewer;
110  }
111
112  /**
113   * @return the delegation token acquired, or null in case it was not acquired
114   */
115  public Token<?> getUserToken() {
116    return userToken;
117  }
118
119  public FileSystem getFileSystem() {
120    return fs;
121  }
122}