1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.security;
22
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.hadoop.conf.Configuration;
25 import org.apache.hadoop.security.UserGroupInformation;
26
27 import java.io.IOException;
28 import java.lang.reflect.Constructor;
29 import java.lang.reflect.Method;
30 import java.lang.reflect.UndeclaredThrowableException;
31 import java.security.PrivilegedAction;
32 import java.security.PrivilegedExceptionAction;
33 import org.apache.commons.logging.Log;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public abstract class User {
54 private static boolean IS_SECURE_HADOOP = true;
55 static {
56 try {
57 UserGroupInformation.class.getMethod("isSecurityEnabled");
58 } catch (NoSuchMethodException nsme) {
59 IS_SECURE_HADOOP = false;
60 }
61 }
62 private static Log LOG = LogFactory.getLog(User.class);
63 protected UserGroupInformation ugi;
64
65
66
67
68
69
70 public String getName() {
71 return ugi.getUserName();
72 }
73
74
75
76
77
78
79 public abstract String getShortName();
80
81
82
83
84 public abstract <T> T runAs(PrivilegedAction<T> action);
85
86
87
88
89 public abstract <T> T runAs(PrivilegedExceptionAction<T> action)
90 throws IOException, InterruptedException;
91
92 public String toString() {
93 return ugi.toString();
94 }
95
96
97
98
99 public static User getCurrent() {
100 if (IS_SECURE_HADOOP) {
101 return new SecureHadoopUser();
102 } else {
103 return new HadoopUser();
104 }
105 }
106
107
108
109
110
111
112
113 public static User createUserForTesting(Configuration conf,
114 String name, String[] groups) {
115 if (IS_SECURE_HADOOP) {
116 return SecureHadoopUser.createUserForTesting(conf, name, groups);
117 }
118 return HadoopUser.createUserForTesting(conf, name, groups);
119 }
120
121
122
123
124
125
126
127
128
129 private static class HadoopUser extends User {
130
131 private HadoopUser() {
132 ugi = (UserGroupInformation) callStatic("getCurrentUGI");
133 }
134
135 private HadoopUser(UserGroupInformation ugi) {
136 this.ugi = ugi;
137 }
138
139 @Override
140 public String getShortName() {
141 return ugi.getUserName();
142 }
143
144 @Override
145 public <T> T runAs(PrivilegedAction<T> action) {
146 UserGroupInformation previous =
147 (UserGroupInformation) callStatic("getCurrentUGI");
148 if (ugi != null) {
149 callStatic("setCurrentUser", new Class[]{UserGroupInformation.class},
150 new Object[]{ugi});
151 }
152 T result = action.run();
153 callStatic("setCurrentUser", new Class[]{UserGroupInformation.class},
154 new Object[]{previous});
155 return result;
156 }
157
158 @Override
159 public <T> T runAs(PrivilegedExceptionAction<T> action)
160 throws IOException, InterruptedException {
161 UserGroupInformation previous =
162 (UserGroupInformation) callStatic("getCurrentUGI");
163 if (ugi != null) {
164 callStatic("setCurrentUGI", new Class[]{UserGroupInformation.class},
165 new Object[]{ugi});
166 }
167 T result = null;
168 try {
169 result = action.run();
170 } catch (Exception e) {
171 if (e instanceof IOException) {
172 throw (IOException)e;
173 } else if (e instanceof InterruptedException) {
174 throw (InterruptedException)e;
175 } else if (e instanceof RuntimeException) {
176 throw (RuntimeException)e;
177 } else {
178 throw new UndeclaredThrowableException(e, "Unknown exception in runAs()");
179 }
180 } finally {
181 callStatic("setCurrentUGI", new Class[]{UserGroupInformation.class},
182 new Object[]{previous});
183 }
184 return result;
185 }
186
187 public static User createUserForTesting(Configuration conf,
188 String name, String[] groups) {
189 try {
190 Class c = Class.forName("org.apache.hadoop.security.UnixUserGroupInformation");
191 Constructor constructor = c.getConstructor(String.class, String[].class);
192 if (constructor == null) {
193 throw new NullPointerException(
194 );
195 }
196 UserGroupInformation newUser =
197 (UserGroupInformation)constructor.newInstance(name, groups);
198
199 conf.set("hadoop.job.ugi", newUser.toString());
200 return new HadoopUser(newUser);
201 } catch (ClassNotFoundException cnfe) {
202 LOG.error("UnixUserGroupInformation not found, is this secure Hadoop?", cnfe);
203 } catch (NoSuchMethodException nsme) {
204 LOG.error("No valid constructor found for UnixUserGroupInformation!", nsme);
205 } catch (Exception e) {
206 LOG.error("Error instantiating new UnixUserGroupInformation", e);
207 }
208
209 return null;
210 }
211 }
212
213
214
215
216
217
218 private static class SecureHadoopUser extends User {
219 private SecureHadoopUser() {
220 ugi = (UserGroupInformation) callStatic("getCurrentUser");
221 }
222
223 private SecureHadoopUser(UserGroupInformation ugi) {
224 this.ugi = ugi;
225 }
226
227 @Override
228 public String getShortName() {
229 return (String)call(ugi, "getShortUserName", null, null);
230 }
231
232 @Override
233 public <T> T runAs(PrivilegedAction<T> action) {
234 return (T) call(ugi, "doAs", new Class[]{PrivilegedAction.class},
235 new Object[]{action});
236 }
237
238 @Override
239 public <T> T runAs(PrivilegedExceptionAction<T> action)
240 throws IOException, InterruptedException {
241 return (T) call(ugi, "doAs",
242 new Class[]{PrivilegedExceptionAction.class},
243 new Object[]{action});
244 }
245
246 public static User createUserForTesting(Configuration conf,
247 String name, String[] groups) {
248 return new SecureHadoopUser(
249 (UserGroupInformation)callStatic("createUserForTesting",
250 new Class[]{String.class, String[].class},
251 new Object[]{name, groups})
252 );
253 }
254 }
255
256
257 private static Object callStatic(String methodName) {
258 return call(null, methodName, null, null);
259 }
260
261 private static Object callStatic(String methodName, Class[] types,
262 Object[] args) {
263 return call(null, methodName, types, args);
264 }
265
266 private static Object call(UserGroupInformation instance, String methodName,
267 Class[] types, Object[] args) {
268 try {
269 Method m = UserGroupInformation.class.getMethod(methodName, types);
270 return m.invoke(instance, args);
271 } catch (NoSuchMethodException nsme) {
272 LOG.fatal("Can't find method "+methodName+" in UserGroupInformation!",
273 nsme);
274 } catch (Exception e) {
275 LOG.fatal("Error calling method "+methodName, e);
276 }
277 return null;
278 }
279 }