Skip to content

Commit 9cf54ee

Browse files
author
Jimmy Xiang
committed
HBASE-11474 [Thrift2] support authentication/impersonation
1 parent f2d16e0 commit 9cf54ee

File tree

6 files changed

+229
-27
lines changed

6 files changed

+229
-27
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/util/ConnectionCache.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ public void setEffectiveUser(String user) {
107107
effectiveUserNames.set(user);
108108
}
109109

110+
/**
111+
* Get the current thread local effective user
112+
*/
113+
public String getEffectiveUser() {
114+
return effectiveUserNames.get();
115+
}
116+
110117
/**
111118
* Caller doesn't close the admin afterwards.
112119
* We need to manage it and close it properly.
@@ -115,7 +122,7 @@ public void setEffectiveUser(String user) {
115122
public HBaseAdmin getAdmin() throws IOException {
116123
ConnectionInfo connInfo = getCurrentConnection();
117124
if (connInfo.admin == null) {
118-
Lock lock = locker.acquireLock(effectiveUserNames.get());
125+
Lock lock = locker.acquireLock(getEffectiveUser());
119126
try {
120127
if (connInfo.admin == null) {
121128
connInfo.admin = new HBaseAdmin(connInfo.connection);
@@ -140,7 +147,7 @@ public HTableInterface getTable(String tableName) throws IOException {
140147
* If none or timed out, create a new one.
141148
*/
142149
ConnectionInfo getCurrentConnection() throws IOException {
143-
String userName = effectiveUserNames.get();
150+
String userName = getEffectiveUser();
144151
ConnectionInfo connInfo = connections.get(userName);
145152
if (connInfo == null || !connInfo.updateAccessTime()) {
146153
Lock lock = locker.acquireLock(userName);

hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ public ThriftServerRunner(Configuration conf) throws IOException {
285285
if (qop != null) {
286286
if (!qop.equals("auth") && !qop.equals("auth-int")
287287
&& !qop.equals("auth-conf")) {
288-
throw new IOException("Invalid hbase.thrift.security.qop: " + qop
288+
throw new IOException("Invalid " + THRIFT_QOP_KEY + ": " + qop
289289
+ ", it must be 'auth', 'auth-int', or 'auth-conf'");
290290
}
291291
if (!securityEnabled) {

hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/ThriftHBaseServiceHandler.java

+58-8
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,41 @@
3030
import java.util.Collections;
3131
import java.util.List;
3232
import java.util.Map;
33+
import java.util.concurrent.Callable;
3334
import java.util.concurrent.ConcurrentHashMap;
35+
import java.util.concurrent.ExecutionException;
36+
import java.util.concurrent.TimeUnit;
3437
import java.util.concurrent.atomic.AtomicInteger;
3538

3639
import org.apache.commons.logging.Log;
3740
import org.apache.commons.logging.LogFactory;
3841
import org.apache.hadoop.classification.InterfaceAudience;
3942
import org.apache.hadoop.conf.Configuration;
43+
import org.apache.hadoop.hbase.client.HTableFactory;
4044
import org.apache.hadoop.hbase.client.HTableInterface;
4145
import org.apache.hadoop.hbase.client.HTablePool;
4246
import org.apache.hadoop.hbase.client.ResultScanner;
43-
import org.apache.hadoop.hbase.client.RowMutations;
47+
import org.apache.hadoop.hbase.security.UserProvider;
4448
import org.apache.hadoop.hbase.thrift.ThriftMetrics;
4549
import org.apache.hadoop.hbase.thrift2.generated.*;
50+
import org.apache.hadoop.hbase.util.Bytes;
51+
import org.apache.hadoop.hbase.util.ConnectionCache;
4652
import org.apache.thrift.TException;
4753

54+
import com.google.common.cache.Cache;
55+
import com.google.common.cache.CacheBuilder;
56+
4857
/**
4958
* This class is a glue object that connects Thrift RPC calls to the HBase client API primarily
5059
* defined in the HTableInterface.
5160
*/
5261
@InterfaceAudience.Private
62+
@SuppressWarnings("deprecation")
5363
public class ThriftHBaseServiceHandler implements THBaseService.Iface {
5464

5565
// TODO: Size of pool configuraple
56-
private final HTablePool htablePool;
66+
private final Cache<String, HTablePool> htablePools;
67+
private final Callable<? extends HTablePool> htablePoolCreater;
5768
private static final Log LOG = LogFactory.getLog(ThriftHBaseServiceHandler.class);
5869

5970
// nextScannerId and scannerMap are used to manage scanner state
@@ -62,8 +73,15 @@ public class ThriftHBaseServiceHandler implements THBaseService.Iface {
6273
private final Map<Integer, ResultScanner> scannerMap =
6374
new ConcurrentHashMap<Integer, ResultScanner>();
6475

65-
public static THBaseService.Iface newInstance(Configuration conf, ThriftMetrics metrics) {
66-
THBaseService.Iface handler = new ThriftHBaseServiceHandler(conf);
76+
private final ConnectionCache connectionCache;
77+
private final HTableFactory tableFactory;
78+
private final int maxPoolSize;
79+
80+
static final String CLEANUP_INTERVAL = "hbase.thrift.connection.cleanup-interval";
81+
static final String MAX_IDLETIME = "hbase.thrift.connection.max-idletime";
82+
83+
public static THBaseService.Iface newInstance(
84+
THBaseService.Iface handler, ThriftMetrics metrics) {
6785
return (THBaseService.Iface) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
6886
new Class[] { THBaseService.Iface.class }, new THBaseServiceMetricsProxy(handler, metrics));
6987
}
@@ -98,13 +116,41 @@ private static long now() {
98116
return System.nanoTime();
99117
}
100118

101-
ThriftHBaseServiceHandler(Configuration conf) {
102-
int maxPoolSize = conf.getInt("hbase.thrift.htablepool.size.max", 1000);
103-
htablePool = new HTablePool(conf, maxPoolSize);
119+
ThriftHBaseServiceHandler(final Configuration conf,
120+
final UserProvider userProvider) throws IOException {
121+
int cleanInterval = conf.getInt(CLEANUP_INTERVAL, 10 * 1000);
122+
int maxIdleTime = conf.getInt(MAX_IDLETIME, 10 * 60 * 1000);
123+
connectionCache = new ConnectionCache(
124+
conf, userProvider, cleanInterval, maxIdleTime);
125+
tableFactory = new HTableFactory() {
126+
@Override
127+
public HTableInterface createHTableInterface(Configuration config,
128+
byte[] tableName) {
129+
try {
130+
return connectionCache.getTable(Bytes.toString(tableName));
131+
} catch (IOException ioe) {
132+
throw new RuntimeException(ioe);
133+
}
134+
}
135+
};
136+
htablePools = CacheBuilder.newBuilder().expireAfterAccess(
137+
maxIdleTime, TimeUnit.MILLISECONDS).softValues().concurrencyLevel(4).build();
138+
maxPoolSize = conf.getInt("hbase.thrift.htablepool.size.max", 1000);
139+
htablePoolCreater = new Callable<HTablePool>() {
140+
public HTablePool call() {
141+
return new HTablePool(conf, maxPoolSize, tableFactory);
142+
}
143+
};
104144
}
105145

106146
private HTableInterface getTable(ByteBuffer tableName) {
107-
return htablePool.getTable(byteBufferToByteArray(tableName));
147+
String currentUser = connectionCache.getEffectiveUser();
148+
try {
149+
HTablePool htablePool = htablePools.get(currentUser, htablePoolCreater);
150+
return htablePool.getTable(byteBufferToByteArray(tableName));
151+
} catch (ExecutionException ee) {
152+
throw new RuntimeException(ee);
153+
}
108154
}
109155

110156
private void closeTable(HTableInterface table) throws TIOError {
@@ -141,6 +187,10 @@ private ResultScanner getScanner(int id) {
141187
return scannerMap.get(id);
142188
}
143189

190+
void setEffectiveUser(String effectiveUser) {
191+
connectionCache.setEffectiveUser(effectiveUser);
192+
}
193+
144194
/**
145195
* Removes the scanner associated with the specified ID from the internal HashMap.
146196
* @param id of the Scanner to remove

0 commit comments

Comments
 (0)