1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.security;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.hadoop.classification.InterfaceAudience;
25 import org.apache.hadoop.classification.InterfaceStability;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.fs.CommonConfigurationKeys;
28 import org.apache.hadoop.hbase.util.Methods;
29 import org.apache.hadoop.mapred.JobConf;
30 import org.apache.hadoop.mapreduce.Job;
31 import org.apache.hadoop.security.UserGroupInformation;
32
33 import java.io.IOException;
34 import java.lang.reflect.UndeclaredThrowableException;
35 import java.security.PrivilegedAction;
36 import java.security.PrivilegedExceptionAction;
37
38
39
40
41
42
43
44
45
46
47
48
49 @InterfaceAudience.Public
50 @InterfaceStability.Evolving
51 public abstract class User {
52 public static final String HBASE_SECURITY_CONF_KEY =
53 "hbase.security.authentication";
54
55 private static Log LOG = LogFactory.getLog(User.class);
56
57 protected UserGroupInformation ugi;
58
59 public UserGroupInformation getUGI() {
60 return ugi;
61 }
62
63
64
65
66
67
68 public String getName() {
69 return ugi.getUserName();
70 }
71
72
73
74
75
76
77 public String[] getGroupNames() {
78 return ugi.getGroupNames();
79 }
80
81
82
83
84
85
86 public abstract String getShortName();
87
88
89
90
91 public abstract <T> T runAs(PrivilegedAction<T> action);
92
93
94
95
96 public abstract <T> T runAs(PrivilegedExceptionAction<T> action)
97 throws IOException, InterruptedException;
98
99
100
101
102
103
104
105 public abstract void obtainAuthTokenForJob(Configuration conf, Job job)
106 throws IOException, InterruptedException;
107
108
109
110
111
112
113
114 public abstract void obtainAuthTokenForJob(JobConf job)
115 throws IOException, InterruptedException;
116
117 @Override
118 public boolean equals(Object o) {
119 if (this == o) {
120 return true;
121 }
122 if (o == null || getClass() != o.getClass()) {
123 return false;
124 }
125 return ugi.equals(((User) o).ugi);
126 }
127
128 @Override
129 public int hashCode() {
130 return ugi.hashCode();
131 }
132
133 @Override
134 public String toString() {
135 return ugi.toString();
136 }
137
138
139
140
141 public static User getCurrent() throws IOException {
142 User user = new SecureHadoopUser();
143 if (user.getUGI() == null) {
144 return null;
145 }
146 return user;
147 }
148
149
150
151
152
153
154 public static User create(UserGroupInformation ugi) {
155 if (ugi == null) {
156 return null;
157 }
158 return new SecureHadoopUser(ugi);
159 }
160
161
162
163
164
165
166
167 public static User createUserForTesting(Configuration conf,
168 String name, String[] groups) {
169 return SecureHadoopUser.createUserForTesting(conf, name, groups);
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 public static void login(Configuration conf, String fileConfKey,
189 String principalConfKey, String localhost) throws IOException {
190 SecureHadoopUser.login(conf, fileConfKey, principalConfKey, localhost);
191 }
192
193
194
195
196
197
198
199 public static boolean isSecurityEnabled() {
200 return SecureHadoopUser.isSecurityEnabled();
201 }
202
203
204
205
206
207
208
209 public static boolean isHBaseSecurityEnabled(Configuration conf) {
210 return "kerberos".equalsIgnoreCase(conf.get(HBASE_SECURITY_CONF_KEY)) &&
211 "kerberos".equalsIgnoreCase(
212 conf.get(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION));
213 }
214
215
216
217
218
219
220
221
222 private static class SecureHadoopUser extends User {
223 private String shortName;
224
225 private SecureHadoopUser() throws IOException {
226 try {
227 ugi = (UserGroupInformation) callStatic("getCurrentUser");
228 } catch (IOException ioe) {
229 throw ioe;
230 } catch (RuntimeException re) {
231 throw re;
232 } catch (Exception e) {
233 throw new UndeclaredThrowableException(e,
234 "Unexpected exception getting current secure user");
235 }
236 }
237
238 private SecureHadoopUser(UserGroupInformation ugi) {
239 this.ugi = ugi;
240 }
241
242 @Override
243 public String getShortName() {
244 if (shortName != null) return shortName;
245
246 try {
247 shortName = (String)call(ugi, "getShortUserName", null, null);
248 return shortName;
249 } catch (RuntimeException re) {
250 throw re;
251 } catch (Exception e) {
252 throw new UndeclaredThrowableException(e,
253 "Unexpected error getting user short name");
254 }
255 }
256
257 @Override
258 public <T> T runAs(PrivilegedAction<T> action) {
259 try {
260 return (T) call(ugi, "doAs", new Class[]{PrivilegedAction.class},
261 new Object[]{action});
262 } catch (RuntimeException re) {
263 throw re;
264 } catch (Exception e) {
265 throw new UndeclaredThrowableException(e,
266 "Unexpected exception in runAs()");
267 }
268 }
269
270 @Override
271 public <T> T runAs(PrivilegedExceptionAction<T> action)
272 throws IOException, InterruptedException {
273 try {
274 return (T) call(ugi, "doAs",
275 new Class[]{PrivilegedExceptionAction.class},
276 new Object[]{action});
277 } catch (IOException ioe) {
278 throw ioe;
279 } catch (InterruptedException ie) {
280 throw ie;
281 } catch (RuntimeException re) {
282 throw re;
283 } catch (Exception e) {
284 throw new UndeclaredThrowableException(e,
285 "Unexpected exception in runAs(PrivilegedExceptionAction)");
286 }
287 }
288
289 @Override
290 public void obtainAuthTokenForJob(Configuration conf, Job job)
291 throws IOException, InterruptedException {
292 try {
293 Class c = Class.forName(
294 "org.apache.hadoop.hbase.security.token.TokenUtil");
295 Methods.call(c, null, "obtainTokenForJob",
296 new Class[]{Configuration.class, UserGroupInformation.class,
297 Job.class},
298 new Object[]{conf, ugi, job});
299 } catch (ClassNotFoundException cnfe) {
300 throw new RuntimeException("Failure loading TokenUtil class, "
301 +"is secure RPC available?", cnfe);
302 } catch (IOException ioe) {
303 throw ioe;
304 } catch (InterruptedException ie) {
305 throw ie;
306 } catch (RuntimeException re) {
307 throw re;
308 } catch (Exception e) {
309 throw new UndeclaredThrowableException(e,
310 "Unexpected error calling TokenUtil.obtainAndCacheToken()");
311 }
312 }
313
314 @Override
315 public void obtainAuthTokenForJob(JobConf job)
316 throws IOException, InterruptedException {
317 try {
318 Class c = Class.forName(
319 "org.apache.hadoop.hbase.security.token.TokenUtil");
320 Methods.call(c, null, "obtainTokenForJob",
321 new Class[]{JobConf.class, UserGroupInformation.class},
322 new Object[]{job, ugi});
323 } catch (ClassNotFoundException cnfe) {
324 throw new RuntimeException("Failure loading TokenUtil class, "
325 +"is secure RPC available?", cnfe);
326 } catch (IOException ioe) {
327 throw ioe;
328 } catch (InterruptedException ie) {
329 throw ie;
330 } catch (RuntimeException re) {
331 throw re;
332 } catch (Exception e) {
333 throw new UndeclaredThrowableException(e,
334 "Unexpected error calling TokenUtil.obtainAndCacheToken()");
335 }
336 }
337
338
339 public static User createUserForTesting(Configuration conf,
340 String name, String[] groups) {
341 try {
342 return new SecureHadoopUser(
343 (UserGroupInformation)callStatic("createUserForTesting",
344 new Class[]{String.class, String[].class},
345 new Object[]{name, groups})
346 );
347 } catch (RuntimeException re) {
348 throw re;
349 } catch (Exception e) {
350 throw new UndeclaredThrowableException(e,
351 "Error creating secure test user");
352 }
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367 public static void login(Configuration conf, String fileConfKey,
368 String principalConfKey, String localhost) throws IOException {
369 if (isSecurityEnabled()) {
370
371 try {
372 Class c = Class.forName("org.apache.hadoop.security.SecurityUtil");
373 Class[] types = new Class[]{
374 Configuration.class, String.class, String.class, String.class };
375 Object[] args = new Object[]{
376 conf, fileConfKey, principalConfKey, localhost };
377 Methods.call(c, null, "login", types, args);
378 } catch (ClassNotFoundException cnfe) {
379 throw new RuntimeException("Unable to login using " +
380 "org.apache.hadoop.security.SecurityUtil.login(). SecurityUtil class " +
381 "was not found! Is this a version of secure Hadoop?", cnfe);
382 } catch (IOException ioe) {
383 throw ioe;
384 } catch (RuntimeException re) {
385 throw re;
386 } catch (Exception e) {
387 throw new UndeclaredThrowableException(e,
388 "Unhandled exception in User.login()");
389 }
390 }
391 }
392
393
394
395
396 public static boolean isSecurityEnabled() {
397 try {
398 return (Boolean)callStatic("isSecurityEnabled");
399 } catch (RuntimeException re) {
400 throw re;
401 } catch (Exception e) {
402 throw new UndeclaredThrowableException(e,
403 "Unexpected exception calling UserGroupInformation.isSecurityEnabled()");
404 }
405 }
406 }
407
408
409 private static Object callStatic(String methodName) throws Exception {
410 return call(null, methodName, null, null);
411 }
412
413 private static Object callStatic(String methodName, Class[] types,
414 Object[] args) throws Exception {
415 return call(null, methodName, types, args);
416 }
417
418 private static Object call(UserGroupInformation instance, String methodName,
419 Class[] types, Object[] args) throws Exception {
420 return Methods.call(UserGroupInformation.class, instance, methodName, types,
421 args);
422 }
423 }