diff --git a/hbase-common/src/main/resources/hbase-default.xml b/hbase-common/src/main/resources/hbase-default.xml
index a0be62f..3983fcf 100644
--- a/hbase-common/src/main/resources/hbase-default.xml
+++ b/hbase-common/src/main/resources/hbase-default.xml
@@ -835,6 +835,11 @@ possible configurations would overwhelm and obscure the important.
The thread pool always has at least these number of threads so
the REST server is ready to serve incoming requests.
+
+ hbase.rest.support.proxyuser
+ false
+ Enables running the REST server to support proxy-user mode.
+
hbase.defaults.for.version
@@@VERSION@@@
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServlet.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServlet.java
index 6df1dea..c265e40 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServlet.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServlet.java
@@ -56,14 +56,17 @@ public class RESTServlet implements Constants {
static final String CLEANUP_INTERVAL = "hbase.rest.connection.cleanup-interval";
static final String MAX_IDLETIME = "hbase.rest.connection.max-idletime";
- static final String NULL_USERNAME = "--NULL--";
-
- private final ThreadLocal effectiveUser = new ThreadLocal() {
- protected String initialValue() {
- return NULL_USERNAME;
+ private final ThreadLocal effectiveUser =
+ new ThreadLocal() {
+ protected UserGroupInformation initialValue() {
+ return realUser;
}
};
+ UserGroupInformation getRealUser() {
+ return realUser;
+ }
+
// A chore to clean up idle connections.
private final Chore connectionCleaner;
private final Stoppable stoppable;
@@ -192,7 +195,7 @@ public class RESTServlet implements Constants {
HBaseAdmin getAdmin() throws IOException {
ConnectionInfo connInfo = getCurrentConnection();
if (connInfo.admin == null) {
- Lock lock = locker.acquireLock(effectiveUser.get());
+ Lock lock = locker.acquireLock(effectiveUser.get().getUserName());
try {
if (connInfo.admin == null) {
connInfo.admin = new HBaseAdmin(connInfo.connection);
@@ -229,23 +232,19 @@ public class RESTServlet implements Constants {
return getConfiguration().getBoolean("hbase.rest.readonly", false);
}
- void setEffectiveUser(String effectiveUser) {
+ void setEffectiveUser(UserGroupInformation effectiveUser) {
this.effectiveUser.set(effectiveUser);
}
private ConnectionInfo getCurrentConnection() throws IOException {
- String userName = effectiveUser.get();
+ String userName = effectiveUser.get().getUserName();
ConnectionInfo connInfo = connections.get(userName);
if (connInfo == null || !connInfo.updateAccessTime()) {
Lock lock = locker.acquireLock(userName);
try {
connInfo = connections.get(userName);
if (connInfo == null) {
- UserGroupInformation ugi = realUser;
- if (!userName.equals(NULL_USERNAME)) {
- ugi = UserGroupInformation.createProxyUser(userName, realUser);
- }
- User user = userProvider.create(ugi);
+ User user = userProvider.create(effectiveUser.get());
HConnection conn = HConnectionManager.createConnection(conf, user);
connInfo = new ConnectionInfo(conn, userName);
connections.put(userName, connInfo);
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServletContainer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServletContainer.java
index 976132e..a6b9b51 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServletContainer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServletContainer.java
@@ -28,6 +28,11 @@ import org.apache.hadoop.classification.InterfaceAudience;
import com.sun.jersey.spi.container.servlet.ServletContainer;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.apache.hadoop.security.authorize.ProxyUsers;
+import org.apache.hadoop.conf.Configuration;
+
/**
* REST servlet container. It is used to get the remote request user
* without going through @HttpContext, so that we can minimize code changes.
@@ -44,7 +49,29 @@ public class RESTServletContainer extends ServletContainer {
@Override
public void service(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {
- RESTServlet.getInstance().setEffectiveUser(request.getRemoteUser());
+ final String doAsUserFromQuery = request.getParameter("doAs");
+ Configuration conf = RESTServlet.getInstance().getConfiguration();
+ final boolean proxyConfigured = conf.getBoolean("hbase.rest.support.proxyuser", false);
+ if (!proxyConfigured) {
+ throw new ServletException("Support for proxyuser is not configured");
+ }
+ UserGroupInformation ugi = RESTServlet.getInstance().getRealUser();
+ if (doAsUserFromQuery != null) {
+ // create and attempt to authorize a proxy user (the client is attempting
+ // to do proxy user)
+ ugi = UserGroupInformation.createProxyUser(doAsUserFromQuery, ugi);
+ // validate the proxy user authorization
+ try {
+ ProxyUsers.authorize(ugi, request.getRemoteAddr(), conf);
+ } catch(AuthorizationException e) {
+ throw new ServletException(e.getMessage());
+ }
+ } else {
+ // the REST server would send the request without validating the proxy
+ // user authorization
+ ugi = UserGroupInformation.createProxyUser(request.getRemoteUser(), ugi);
+ }
+ RESTServlet.getInstance().setEffectiveUser(ugi);
super.service(request, response);
}
}