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