1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.ipc;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.hadoop.conf.Configuration;
24 import org.apache.hadoop.hbase.io.HbaseObjectWritable;
25 import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
26 import org.apache.hadoop.hbase.security.HBasePolicyProvider;
27 import org.apache.hadoop.hbase.security.HBaseSaslRpcServer;
28 import org.apache.hadoop.hbase.security.User;
29 import org.apache.hadoop.hbase.security.token.AuthenticationTokenSecretManager;
30 import org.apache.hadoop.hbase.util.Objects;
31 import org.apache.hadoop.io.Writable;
32 import org.apache.hadoop.security.authorize.ServiceAuthorizationManager;
33
34 import java.io.IOException;
35 import java.lang.reflect.*;
36 import java.net.InetSocketAddress;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class SecureRpcEngine implements RpcEngine {
53
54
55
56 protected static final Log LOG =
57 LogFactory.getLog("org.apache.hadoop.ipc.SecureRpcEngine");
58
59 private Configuration conf;
60 private SecureClient client;
61
62 @Override
63 public void setConf(Configuration config) {
64 this.conf = config;
65 if (User.isHBaseSecurityEnabled(conf)) {
66 HBaseSaslRpcServer.init(conf);
67 }
68
69 if (this.client != null) {
70 this.client.stop();
71 }
72 this.client = new SecureClient(HbaseObjectWritable.class, conf);
73 }
74
75 @Override
76 public Configuration getConf() {
77 return this.conf;
78 }
79
80 private static class Invoker implements InvocationHandler {
81 private Class<? extends VersionedProtocol> protocol;
82 private InetSocketAddress address;
83 private User ticket;
84 private SecureClient client;
85 final private int rpcTimeout;
86
87 public Invoker(SecureClient client,
88 Class<? extends VersionedProtocol> protocol,
89 InetSocketAddress address, User ticket, int rpcTimeout) {
90 this.protocol = protocol;
91 this.address = address;
92 this.ticket = ticket;
93 this.client = client;
94 this.rpcTimeout = rpcTimeout;
95 }
96
97 public Object invoke(Object proxy, Method method, Object[] args)
98 throws Throwable {
99 final boolean logDebug = LOG.isDebugEnabled();
100 long startTime = 0;
101 if (logDebug) {
102 startTime = System.currentTimeMillis();
103 }
104 HbaseObjectWritable value = (HbaseObjectWritable)
105 client.call(new Invocation(method, protocol, args), address,
106 protocol, ticket, rpcTimeout);
107 if (logDebug) {
108 long callTime = System.currentTimeMillis() - startTime;
109 LOG.debug("Call: " + method.getName() + " " + callTime);
110 }
111 return value.get();
112 }
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126 @Override
127 public <T extends VersionedProtocol> T getProxy(
128 Class<T> protocol, long clientVersion,
129 InetSocketAddress addr,
130 Configuration conf, int rpcTimeout)
131 throws IOException {
132 if (this.client == null) {
133 throw new IOException("Client must be initialized by calling setConf(Configuration)");
134 }
135
136 T proxy =
137 (T) Proxy.newProxyInstance(
138 protocol.getClassLoader(), new Class[] { protocol },
139 new Invoker(this.client, protocol, addr, User.getCurrent(),
140 HBaseRPC.getRpcTimeout(rpcTimeout)));
141
142
143
144
145
146 long serverVersion = proxy.getProtocolVersion(protocol.getName(),
147 clientVersion);
148 if (serverVersion != clientVersion) {
149 throw new HBaseRPC.VersionMismatch(protocol.getName(), clientVersion,
150 serverVersion);
151 }
152 return proxy;
153 }
154
155
156 @Override
157 public Object[] call(Method method, Object[][] params,
158 InetSocketAddress[] addrs,
159 Class<? extends VersionedProtocol> protocol,
160 User ticket, Configuration conf)
161 throws IOException, InterruptedException {
162 if (this.client == null) {
163 throw new IOException("Client must be initialized by calling setConf(Configuration)");
164 }
165
166 Invocation[] invocations = new Invocation[params.length];
167 for (int i = 0; i < params.length; i++) {
168 invocations[i] = new Invocation(method, protocol, params[i]);
169 }
170
171 Writable[] wrappedValues =
172 client.call(invocations, addrs, protocol, ticket);
173
174 if (method.getReturnType() == Void.TYPE) {
175 return null;
176 }
177
178 Object[] values =
179 (Object[])Array.newInstance(method.getReturnType(), wrappedValues.length);
180 for (int i = 0; i < values.length; i++)
181 if (wrappedValues[i] != null)
182 values[i] = ((HbaseObjectWritable)wrappedValues[i]).get();
183
184 return values;
185 }
186
187 @Override
188 public void close() {
189 if (this.client != null) {
190 this.client.stop();
191 }
192 }
193
194
195
196 @Override
197 public Server getServer(Class<? extends VersionedProtocol> protocol,
198 final Object instance,
199 Class<?>[] ifaces,
200 final String bindAddress, final int port,
201 final int numHandlers,
202 int metaHandlerCount, final boolean verbose, Configuration conf,
203 int highPriorityLevel)
204 throws IOException {
205 Server server = new Server(instance, ifaces, conf, bindAddress, port,
206 numHandlers, metaHandlerCount, verbose,
207 highPriorityLevel);
208 return server;
209 }
210
211
212 public static class Server extends SecureServer {
213 private Object instance;
214 private Class<?> implementation;
215 private Class<?>[] ifaces;
216 private boolean verbose;
217
218 private static String classNameBase(String className) {
219 String[] names = className.split("\\.", -1);
220 if (names == null || names.length == 0) {
221 return className;
222 }
223 return names[names.length-1];
224 }
225
226
227
228
229
230
231
232
233
234
235 public Server(Object instance, final Class<?>[] ifaces,
236 Configuration conf, String bindAddress, int port,
237 int numHandlers, int metaHandlerCount, boolean verbose,
238 int highPriorityLevel)
239 throws IOException {
240 super(bindAddress, port, Invocation.class, numHandlers, metaHandlerCount, conf,
241 classNameBase(instance.getClass().getName()), highPriorityLevel);
242 this.instance = instance;
243 this.implementation = instance.getClass();
244 this.verbose = verbose;
245
246 this.ifaces = ifaces;
247
248
249 this.rpcMetrics.createMetrics(this.ifaces);
250 }
251
252 public AuthenticationTokenSecretManager createSecretManager(){
253 if (instance instanceof org.apache.hadoop.hbase.Server) {
254 org.apache.hadoop.hbase.Server server =
255 (org.apache.hadoop.hbase.Server)instance;
256 Configuration conf = server.getConfiguration();
257 long keyUpdateInterval =
258 conf.getLong("hbase.auth.key.update.interval", 24*60*60*1000);
259 long maxAge =
260 conf.getLong("hbase.auth.token.max.lifetime", 7*24*60*60*1000);
261 return new AuthenticationTokenSecretManager(conf, server.getZooKeeper(),
262 server.getServerName().toString(), keyUpdateInterval, maxAge);
263 }
264 return null;
265 }
266
267 @Override
268 public void startThreads() {
269 AuthenticationTokenSecretManager mgr = createSecretManager();
270 if (mgr != null) {
271 setSecretManager(mgr);
272 mgr.start();
273 }
274 this.authManager = new ServiceAuthorizationManager();
275 HBasePolicyProvider.init(conf, authManager);
276
277
278 super.startThreads();
279 }
280
281 @Override
282 public Writable call(Class<? extends VersionedProtocol> protocol,
283 Writable param, long receivedTime, MonitoredRPCHandler status)
284 throws IOException {
285 try {
286 Invocation call = (Invocation)param;
287 if(call.getMethodName() == null) {
288 throw new IOException("Could not find requested method, the usual " +
289 "cause is a version mismatch between client and server.");
290 }
291 if (verbose) log("Call: " + call);
292
293 Method method =
294 protocol.getMethod(call.getMethodName(),
295 call.getParameterClasses());
296 method.setAccessible(true);
297
298 Object impl = null;
299 if (protocol.isAssignableFrom(this.implementation)) {
300 impl = this.instance;
301 }
302 else {
303 throw new HBaseRPC.UnknownProtocolException(protocol);
304 }
305
306 long startTime = System.currentTimeMillis();
307 Object[] params = call.getParameters();
308 Object value = method.invoke(impl, params);
309 int processingTime = (int) (System.currentTimeMillis() - startTime);
310 int qTime = (int) (startTime-receivedTime);
311 if (TRACELOG.isDebugEnabled()) {
312 TRACELOG.debug("Call #" + CurCall.get().id +
313 "; Served: " + protocol.getSimpleName()+"#"+call.getMethodName() +
314 " queueTime=" + qTime +
315 " processingTime=" + processingTime +
316 " contents=" + Objects.describeQuantity(params));
317 }
318 rpcMetrics.rpcQueueTime.inc(qTime);
319 rpcMetrics.rpcProcessingTime.inc(processingTime);
320 rpcMetrics.inc(call.getMethodName(), processingTime);
321 if (verbose) log("Return: "+value);
322
323 return new HbaseObjectWritable(method.getReturnType(), value);
324 } catch (InvocationTargetException e) {
325 Throwable target = e.getTargetException();
326 if (target instanceof IOException) {
327 throw (IOException)target;
328 }
329 IOException ioe = new IOException(target.toString());
330 ioe.setStackTrace(target.getStackTrace());
331 throw ioe;
332 } catch (Throwable e) {
333 if (!(e instanceof IOException)) {
334 LOG.error("Unexpected throwable object ", e);
335 }
336 IOException ioe = new IOException(e.toString());
337 ioe.setStackTrace(e.getStackTrace());
338 throw ioe;
339 }
340 }
341 }
342
343 protected static void log(String value) {
344 String v = value;
345 if (v != null && v.length() > 55)
346 v = v.substring(0, 55)+"...";
347 LOG.info(v);
348 }
349 }