HBASE-9866. Support the mode where REST server authorizes proxy users
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1552385 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9f496164d6
commit
5ef080e8a7
|
@ -828,6 +828,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.</description>
|
||||
</property>
|
||||
<property>
|
||||
<name>hbase.rest.support.proxyuser</name>
|
||||
<value>false</value>
|
||||
<description>Enables running the REST server to support proxy-user mode.</description>
|
||||
</property>
|
||||
<property skipInDoc="true">
|
||||
<name>hbase.defaults.for.version</name>
|
||||
<value>@@@VERSION@@@</value>
|
||||
|
|
|
@ -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<String> effectiveUser = new ThreadLocal<String>() {
|
||||
protected String initialValue() {
|
||||
return NULL_USERNAME;
|
||||
private final ThreadLocal<UserGroupInformation> effectiveUser =
|
||||
new ThreadLocal<UserGroupInformation>() {
|
||||
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);
|
||||
|
|
|
@ -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 (doAsUserFromQuery != null && !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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue