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  
19  package org.apache.hadoop.hbase.security.token;
20  
21  import java.io.IOException;
22  import java.lang.reflect.UndeclaredThrowableException;
23  import java.security.PrivilegedExceptionAction;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.HConstants;
29  import org.apache.hadoop.hbase.client.HTable;
30  import org.apache.hadoop.io.Text;
31  import org.apache.hadoop.mapred.JobConf;
32  import org.apache.hadoop.mapreduce.Job;
33  import org.apache.hadoop.security.UserGroupInformation;
34  import org.apache.hadoop.security.token.Token;
35  
36  /**
37   * Utility methods for obtaining authentication tokens.
38   */
39  public class TokenUtil {
40    private static Log LOG = LogFactory.getLog(TokenUtil.class);
41  
42    /**
43     * Obtain and return an authentication token for the current user.
44     * @param conf The configuration for connecting to the cluster
45     * @return the authentication token instance
46     */
47    public static Token<AuthenticationTokenIdentifier> obtainToken(
48        Configuration conf) throws IOException {
49      HTable meta = null;
50      try {
51        meta = new HTable(conf, ".META.");
52        AuthenticationProtocol prot = meta.coprocessorProxy(
53            AuthenticationProtocol.class, HConstants.EMPTY_START_ROW);
54        return prot.getAuthenticationToken();
55      } finally {
56        if (meta != null) {
57          meta.close();
58        }
59      }
60    }
61  
62    private static Text getClusterId(Token<AuthenticationTokenIdentifier> token)
63        throws IOException {
64      return token.getService() != null
65          ? token.getService() : new Text("default");
66    }
67  
68    /**
69     * Obtain an authentication token for the given user and add it to the
70     * user's credentials.
71     * @param conf The configuration for connecting to the cluster
72     * @param user The user for whom to obtain the token
73     * @throws IOException If making a remote call to the {@link TokenProvider} fails
74     * @throws InterruptedException If executing as the given user is interrupted
75     */
76    public static void obtainAndCacheToken(final Configuration conf,
77        UserGroupInformation user)
78        throws IOException, InterruptedException {
79      try {
80        Token<AuthenticationTokenIdentifier> token =
81            user.doAs(new PrivilegedExceptionAction<Token<AuthenticationTokenIdentifier>>() {
82              public Token<AuthenticationTokenIdentifier> run() throws Exception {
83                return obtainToken(conf);
84              }
85            });
86  
87        if (token == null) {
88          throw new IOException("No token returned for user "+user.getUserName());
89        }
90        if (LOG.isDebugEnabled()) {
91          LOG.debug("Obtained token "+token.getKind().toString()+" for user "+
92              user.getUserName());
93        }
94        user.addToken(token);
95      } catch (IOException ioe) {
96        throw ioe;
97      } catch (InterruptedException ie) {
98        throw ie;
99      } catch (RuntimeException re) {
100       throw re;
101     } catch (Exception e) {
102       throw new UndeclaredThrowableException(e,
103           "Unexpected exception obtaining token for user "+user.getUserName());
104     }
105   }
106 
107   /**
108    * Obtain an authentication token on behalf of the given user and add it to
109    * the credentials for the given map reduce job.
110    * @param conf The configuration for connecting to the cluster
111    * @param user The user for whom to obtain the token
112    * @param job The job instance in which the token should be stored
113    * @throws IOException If making a remote call to the {@link TokenProvider} fails
114    * @throws InterruptedException If executing as the given user is interrupted
115    */
116   public static void obtainTokenForJob(final Configuration conf,
117       UserGroupInformation user, Job job)
118       throws IOException, InterruptedException {
119     try {
120       Token<AuthenticationTokenIdentifier> token =
121           user.doAs(new PrivilegedExceptionAction<Token<AuthenticationTokenIdentifier>>() {
122             public Token<AuthenticationTokenIdentifier> run() throws Exception {
123               return obtainToken(conf);
124             }
125           });
126 
127       if (token == null) {
128         throw new IOException("No token returned for user "+user.getUserName());
129       }
130       Text clusterId = getClusterId(token);
131       LOG.info("Obtained token "+token.getKind().toString()+" for user "+
132           user.getUserName() + " on cluster "+clusterId.toString());
133       job.getCredentials().addToken(clusterId, token);
134     } catch (IOException ioe) {
135       throw ioe;
136     } catch (InterruptedException ie) {
137       throw ie;
138     } catch (RuntimeException re) {
139       throw re;
140     } catch (Exception e) {
141       throw new UndeclaredThrowableException(e,
142           "Unexpected exception obtaining token for user "+user.getUserName());
143     }
144   }
145 
146   /**
147    * Obtain an authentication token on behalf of the given user and add it to
148    * the credentials for the given map reduce job.
149    * @param user The user for whom to obtain the token
150    * @param job The job configuration in which the token should be stored
151    * @throws IOException If making a remote call to the {@link TokenProvider} fails
152    * @throws InterruptedException If executing as the given user is interrupted
153    */
154   public static void obtainTokenForJob(final JobConf job,
155       UserGroupInformation user)
156       throws IOException, InterruptedException {
157     try {
158       Token<AuthenticationTokenIdentifier> token =
159           user.doAs(new PrivilegedExceptionAction<Token<AuthenticationTokenIdentifier>>() {
160             public Token<AuthenticationTokenIdentifier> run() throws Exception {
161               return obtainToken(job);
162             }
163           });
164 
165       if (token == null) {
166         throw new IOException("No token returned for user "+user.getUserName());
167       }
168       Text clusterId = getClusterId(token);
169       LOG.info("Obtained token "+token.getKind().toString()+" for user "+
170           user.getUserName()+" on cluster "+clusterId.toString());
171       job.getCredentials().addToken(clusterId, token);
172     } catch (IOException ioe) {
173       throw ioe;
174     } catch (InterruptedException ie) {
175       throw ie;
176     } catch (RuntimeException re) {
177       throw re;
178     } catch (Exception e) {
179       throw new UndeclaredThrowableException(e,
180           "Unexpected exception obtaining token for user "+user.getUserName());
181     }
182   }
183 }