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 try {
260 shortName = ugi.getShortUserName();
261 return shortName;
262 } catch (Exception e) {
263 throw new RuntimeException("Unexpected error getting user short name",
264 e);
265 }
266 }
267
268 @Override
269 public <T> T runAs(PrivilegedAction<T> action) {
270 try {
271 return (T) call(ugi, "doAs", new Class[]{PrivilegedAction.class},
272 new Object[]{action});
273 } catch (RuntimeException re) {
274 throw re;
275 } catch (Exception e) {
276 throw new UndeclaredThrowableException(e,
277 "Unexpected exception in runAs()");
278 }
279 }
280
281 @Override
282 public <T> T runAs(PrivilegedExceptionAction<T> action)
283 throws IOException, InterruptedException {
284 try {
285 return (T) call(ugi, "doAs",
286 new Class[]{PrivilegedExceptionAction.class},
287 new Object[]{action});
288 } catch (IOException ioe) {
289 throw ioe;
290 } catch (InterruptedException ie) {
291 throw ie;
292 } catch (RuntimeException re) {
293 throw re;
294 } catch (Exception e) {
295 throw new UndeclaredThrowableException(e,
296 "Unexpected exception in runAs(PrivilegedExceptionAction)");
297 }
298 }
299
300 @Override
301 public void obtainAuthTokenForJob(Configuration conf, Job job)
302 throws IOException, InterruptedException {
303 try {
304 Class c = Class.forName(
305 "org.apache.hadoop.hbase.security.token.TokenUtil");
306 Methods.call(c, null, "obtainTokenForJob",
307 new Class[]{Configuration.class, UserGroupInformation.class,
308 Job.class},
309 new Object[]{conf, ugi, job});
310 } catch (ClassNotFoundException cnfe) {
311 throw new RuntimeException("Failure loading TokenUtil class, "
312 +"is secure RPC available?", cnfe);
313 } catch (IOException ioe) {
314 throw ioe;
315 } catch (InterruptedException ie) {
316 throw ie;
317 } catch (RuntimeException re) {
318 throw re;
319 } catch (Exception e) {
320 throw new UndeclaredThrowableException(e,
321 "Unexpected error calling TokenUtil.obtainAndCacheToken()");
322 }
323 }
324
325 @Override
326 public void obtainAuthTokenForJob(JobConf job)
327 throws IOException, InterruptedException {
328 try {
329 Class c = Class.forName(
330 "org.apache.hadoop.hbase.security.token.TokenUtil");
331 Methods.call(c, null, "obtainTokenForJob",
332 new Class[]{JobConf.class, UserGroupInformation.class},
333 new Object[]{job, ugi});
334 } catch (ClassNotFoundException cnfe) {
335 throw new RuntimeException("Failure loading TokenUtil class, "
336 +"is secure RPC available?", cnfe);
337 } catch (IOException ioe) {
338 throw ioe;
339 } catch (InterruptedException ie) {
340 throw ie;
341 } catch (RuntimeException re) {
342 throw re;
343 } catch (Exception e) {
344 throw new UndeclaredThrowableException(e,
345 "Unexpected error calling TokenUtil.obtainAndCacheToken()");
346 }
347 }
348
349
350 public static User createUserForTesting(Configuration conf,
351 String name, String[] groups) {
352 try {
353 return new SecureHadoopUser(
354 (UserGroupInformation)callStatic("createUserForTesting",
355 new Class[]{String.class, String[].class},
356 new Object[]{name, groups})
357 );
358 } catch (RuntimeException re) {
359 throw re;
360 } catch (Exception e) {
361 throw new UndeclaredThrowableException(e,
362 "Error creating secure test user");
363 }
364 }
365
366
367
368
369
370
371
372
373
374
375
376
377
378 public static void login(Configuration conf, String fileConfKey,
379 String principalConfKey, String localhost) throws IOException {
380 if (isSecurityEnabled()) {
381
382 try {
383 Class c = Class.forName("org.apache.hadoop.security.SecurityUtil");
384 Class[] types = new Class[]{
385 Configuration.class, String.class, String.class, String.class };
386 Object[] args = new Object[]{
387 conf, fileConfKey, principalConfKey, localhost };
388 Methods.call(c, null, "login", types, args);
389 } catch (ClassNotFoundException cnfe) {
390 throw new RuntimeException("Unable to login using " +
391 "org.apache.hadoop.security.SecurityUtil.login(). SecurityUtil class " +
392 "was not found! Is this a version of secure Hadoop?", cnfe);
393 } catch (IOException ioe) {
394 throw ioe;
395 } catch (RuntimeException re) {
396 throw re;
397 } catch (Exception e) {
398 throw new UndeclaredThrowableException(e,
399 "Unhandled exception in User.login()");
400 }
401 }
402 }
403
404
405
406
407 public static boolean isSecurityEnabled() {
408 try {
409 return (Boolean)callStatic("isSecurityEnabled");
410 } catch (RuntimeException re) {
411 throw re;
412 } catch (Exception e) {
413 throw new UndeclaredThrowableException(e,
414 "Unexpected exception calling UserGroupInformation.isSecurityEnabled()");
415 }
416 }
417 }
418
419
420 private static Object callStatic(String methodName) throws Exception {
421 return call(null, methodName, null, null);
422 }
423
424 private static Object callStatic(String methodName, Class[] types,
425 Object[] args) throws Exception {
426 return call(null, methodName, types, args);
427 }
428
429 private static Object call(UserGroupInformation instance, String methodName,
430 Class[] types, Object[] args) throws Exception {
431 return Methods.call(UserGroupInformation.class, instance, methodName, types,
432 args);
433 }
434 }