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