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