View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.security.token;
19  
20  import static org.apache.hadoop.hdfs.protocol.HdfsConstants.HDFS_URI_SCHEME;
21  import static org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier.HDFS_DELEGATION_KIND;
22  import static org.apache.hadoop.hdfs.web.WebHdfsConstants.SWEBHDFS_SCHEME;
23  import static org.apache.hadoop.hdfs.web.WebHdfsConstants.SWEBHDFS_TOKEN_KIND;
24  import static org.apache.hadoop.hdfs.web.WebHdfsConstants.WEBHDFS_SCHEME;
25  import static org.apache.hadoop.hdfs.web.WebHdfsConstants.WEBHDFS_TOKEN_KIND;
26  
27  import java.io.IOException;
28  import java.util.Objects;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.fs.FileSystem;
33  import org.apache.hadoop.hbase.classification.InterfaceAudience;
34  import org.apache.hadoop.hbase.classification.InterfaceStability;
35  import org.apache.hadoop.hbase.security.UserProvider;
36  import org.apache.hadoop.security.token.Token;
37  
38  /**
39   * Helper class to obtain a filesystem delegation token.
40   * Mainly used by Map-Reduce jobs that requires to read/write data to 
41   * a remote file-system (e.g. BulkLoad, ExportSnapshot).
42   */
43  @InterfaceAudience.Private
44  @InterfaceStability.Evolving
45  public class FsDelegationToken {
46    private static final Log LOG = LogFactory.getLog(FsDelegationToken.class);
47  
48    private final UserProvider userProvider;
49    private final String renewer;
50  
51    private boolean hasForwardedToken = false;
52    private Token<?> userToken = null;
53    private FileSystem fs = null;
54  
55    /*
56     * @param renewer the account name that is allowed to renew the token.
57     */
58    public FsDelegationToken(final UserProvider userProvider, final String renewer) {
59      this.userProvider = userProvider;
60      this.renewer = renewer;
61    }
62  
63    /**
64     * Acquire the delegation token for the specified filesystem.
65     * Before requesting a new delegation token, tries to find one already available.
66     * Currently supports checking existing delegation tokens for swebhdfs, webhdfs and hdfs.
67     *
68     * @param fs the filesystem that requires the delegation token
69     * @throws IOException on fs.getDelegationToken() failure
70     */
71    public void acquireDelegationToken(final FileSystem fs)
72        throws IOException {
73      String tokenKind;
74      String scheme = fs.getUri().getScheme();
75      if (SWEBHDFS_SCHEME.equalsIgnoreCase(scheme)) {
76        tokenKind = SWEBHDFS_TOKEN_KIND.toString();
77      } else if (WEBHDFS_SCHEME.equalsIgnoreCase(scheme)) {
78        tokenKind = WEBHDFS_TOKEN_KIND.toString();
79      } else if (HDFS_URI_SCHEME.equalsIgnoreCase(scheme)) {
80        tokenKind = HDFS_DELEGATION_KIND.toString();
81      } else {
82        LOG.warn("Unknown FS URI scheme: " + scheme);
83        // Preserve default behavior
84        tokenKind = HDFS_DELEGATION_KIND.toString();
85      }
86  
87      acquireDelegationToken(tokenKind, fs);
88    }
89  
90    /**
91     * Acquire the delegation token for the specified filesystem and token kind.
92     * Before requesting a new delegation token, tries to find one already available.
93     *
94     * @param tokenKind non-null token kind to get delegation token from the {@link UserProvider}
95     * @param fs the filesystem that requires the delegation token
96     * @throws IOException on fs.getDelegationToken() failure
97     */
98    public void acquireDelegationToken(final String tokenKind, final FileSystem fs)
99        throws IOException {
100     Objects.requireNonNull(tokenKind, "tokenKind:null");
101     if (userProvider.isHadoopSecurityEnabled()) {
102       this.fs = fs;
103       userToken = userProvider.getCurrent().getToken(tokenKind, fs.getCanonicalServiceName());
104       if (userToken == null) {
105         hasForwardedToken = false;
106         try {
107           userToken = fs.getDelegationToken(renewer);
108         } catch (NullPointerException npe) {
109           // we need to handle NullPointerException in case HADOOP-10009 is missing
110           LOG.error("Failed to get token for " + renewer);
111         }
112       } else {
113         hasForwardedToken = true;
114         LOG.info("Use the existing token: " + userToken);
115       }
116     }
117   }
118 
119   /**
120    * Releases a previously acquired delegation token.
121    */
122   public void releaseDelegationToken() {
123     if (userProvider.isHadoopSecurityEnabled()) {
124       if (userToken != null && !hasForwardedToken) {
125         try {
126           userToken.cancel(this.fs.getConf());
127         } catch (Exception e) {
128           LOG.warn("Failed to cancel HDFS delegation token: " + userToken, e);
129         }
130       }
131       this.userToken = null;
132       this.fs = null;
133     }
134   }
135 
136   public UserProvider getUserProvider() {
137     return userProvider;
138   }
139 
140   /**
141    * @return the account name that is allowed to renew the token.
142    */
143   public String getRenewer() {
144     return renewer;
145   }
146 
147   /**
148    * @return the delegation token acquired, or null in case it was not acquired
149    */
150   public Token<?> getUserToken() {
151     return userToken;
152   }
153 
154   public FileSystem getFileSystem() {
155     return fs;
156   }
157 }