hbase-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From te...@apache.org
Subject hbase git commit: HBASE-13115 Fix the usage of remote user in thrift doAs implementation (Srikanth Srungarapu)
Date Tue, 03 Mar 2015 14:48:59 GMT
Repository: hbase
Updated Branches:
  refs/heads/master daed00fc9 -> 5dfcee087


HBASE-13115 Fix the usage of remote user in thrift doAs implementation (Srikanth Srungarapu)


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/5dfcee08
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/5dfcee08
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/5dfcee08

Branch: refs/heads/master
Commit: 5dfcee0871f13b2657e815aca08416b4bd9d7881
Parents: daed00f
Author: tedyu <yuzhihong@gmail.com>
Authored: Tue Mar 3 06:48:56 2015 -0800
Committer: tedyu <yuzhihong@gmail.com>
Committed: Tue Mar 3 06:48:56 2015 -0800

----------------------------------------------------------------------
 .../hadoop/hbase/thrift/HttpDoAsClient.java     | 27 ++++++-----
 .../hadoop/hbase/thrift/ThriftHttpServlet.java  | 49 ++++++++++++++------
 2 files changed, 51 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/5dfcee08/hbase-examples/src/main/java/org/apache/hadoop/hbase/thrift/HttpDoAsClient.java
----------------------------------------------------------------------
diff --git a/hbase-examples/src/main/java/org/apache/hadoop/hbase/thrift/HttpDoAsClient.java
b/hbase-examples/src/main/java/org/apache/hadoop/hbase/thrift/HttpDoAsClient.java
index 9ef1bd2..df18fed 100644
--- a/hbase-examples/src/main/java/org/apache/hadoop/hbase/thrift/HttpDoAsClient.java
+++ b/hbase-examples/src/main/java/org/apache/hadoop/hbase/thrift/HttpDoAsClient.java
@@ -18,7 +18,6 @@
  */
 package org.apache.hadoop.hbase.thrift;
 
-import sun.misc.BASE64Encoder;
 
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
@@ -43,6 +42,7 @@ import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
 import org.apache.hadoop.hbase.thrift.generated.Hbase;
 import org.apache.hadoop.hbase.thrift.generated.TCell;
 import org.apache.hadoop.hbase.thrift.generated.TRowResult;
+import org.apache.hadoop.hbase.util.Base64;
 import org.apache.thrift.protocol.TBinaryProtocol;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.transport.THttpClient;
@@ -64,21 +64,24 @@ public class HttpDoAsClient {
   static protected String host;
   CharsetDecoder decoder = null;
   private static boolean secure = false;
+  static protected String doAsUser = null;
+  static protected String principal = null;
 
   public static void main(String[] args) throws Exception {
 
-    if (args.length < 2 || args.length > 3) {
+    if (args.length < 3 || args.length > 4) {
 
       System.out.println("Invalid arguments!");
-      System.out.println("Usage: DemoClient host port [secure=false]");
-
+      System.out.println("Usage: HttpDoAsClient host port doAsUserName [security=true]");
       System.exit(-1);
     }
 
-    port = Integer.parseInt(args[1]);
     host = args[0];
-    if (args.length > 2) {
-      secure = Boolean.parseBoolean(args[2]);
+    port = Integer.parseInt(args[1]);
+    doAsUser = args[2];
+    if (args.length > 3) {
+      secure = Boolean.parseBoolean(args[3]);
+      principal = getSubject().getPrincipals().iterator().next().getName();
     }
 
     final HttpDoAsClient client = new HttpDoAsClient();
@@ -134,7 +137,7 @@ public class HttpDoAsClient {
     for (ByteBuffer name : refresh(client, httpClient).getTableNames()) {
       System.out.println("  found: " + utf8(name.array()));
       if (utf8(name.array()).equals(utf8(t))) {
-        if (client.isTableEnabled(name)) {
+        if (refresh(client, httpClient).isTableEnabled(name)) {
           System.out.println("    disabling table: " + utf8(name.array()));
           refresh(client, httpClient).disableTable(name);
         }
@@ -180,8 +183,8 @@ public class HttpDoAsClient {
   }
 
   private Hbase.Client refresh(Hbase.Client client, THttpClient httpClient) {
+    httpClient.setCustomHeader("doAs", doAsUser);
     if(secure) {
-      httpClient.setCustomHeader("doAs", "hbase");
       try {
         httpClient.setCustomHeader("Authorization", generateTicket());
       } catch (GSSException e) {
@@ -196,14 +199,14 @@ public class HttpDoAsClient {
     // Oid for kerberos principal name
     Oid krb5PrincipalOid = new Oid("1.2.840.113554.1.2.2.1");
     Oid KERB_V5_OID = new Oid("1.2.840.113554.1.2.2");
-    final GSSName clientName = manager.createName("hbase/node-1.internal@INTERNAL",
+    final GSSName clientName = manager.createName(principal,
         krb5PrincipalOid);
     final GSSCredential clientCred = manager.createCredential(clientName,
         8 * 3600,
         KERB_V5_OID,
         GSSCredential.INITIATE_ONLY);
 
-    final GSSName serverName = manager.createName("hbase/node-1.internal@INTERNAL", krb5PrincipalOid);
+    final GSSName serverName = manager.createName(principal, krb5PrincipalOid);
 
     final GSSContext context = manager.createContext(serverName,
         KERB_V5_OID,
@@ -216,7 +219,7 @@ public class HttpDoAsClient {
     final byte[] outToken = context.initSecContext(new byte[0], 0, 0);
     StringBuffer outputBuffer = new StringBuffer();
     outputBuffer.append("Negotiate ");
-    outputBuffer.append(new BASE64Encoder().encode(outToken).replace("\n", ""));
+    outputBuffer.append(Base64.encodeBytes(outToken).replace("\n", ""));
     System.out.print("Ticket is: " + outputBuffer);
     return outputBuffer.toString();
   }

http://git-wip-us.apache.org/repos/asf/hbase/blob/5dfcee08/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java
----------------------------------------------------------------------
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java
b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java
index f3bed0a..c7ea46f 100644
--- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java
@@ -27,10 +27,10 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.commons.net.util.Base64;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.security.SecurityUtil;
+import org.apache.hadoop.hbase.util.Base64;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.authorize.AuthorizationException;
 import org.apache.hadoop.security.authorize.ProxyUsers;
@@ -57,6 +57,12 @@ public class ThriftHttpServlet extends TServlet {
   private final boolean securityEnabled;
   private final boolean doAsEnabled;
   private transient ThriftServerRunner.HBaseHandler hbaseHandler;
+  private String outToken;
+
+  // HTTP Header related constants.
+  public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+  public static final String AUTHORIZATION = "Authorization";
+  public static final String NEGOTIATE = "Negotiate";
 
   public ThriftHttpServlet(TProcessor processor, TProtocolFactory protocolFactory,
       UserGroupInformation realUser, Configuration conf, ThriftServerRunner.HBaseHandler
@@ -72,28 +78,38 @@ public class ThriftHttpServlet extends TServlet {
   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException {
-    String effectiveUser = realUser.getShortUserName();
+    String effectiveUser = request.getRemoteUser();
     if (securityEnabled) {
       try {
         // As Thrift HTTP transport doesn't support SPNEGO yet (THRIFT-889),
         // Kerberos authentication is being done at servlet level.
         effectiveUser = doKerberosAuth(request);
+        // It is standard for client applications expect this header.
+        // Please see http://tools.ietf.org/html/rfc4559 for more details.
+        response.addHeader(WWW_AUTHENTICATE,  NEGOTIATE + " " + outToken);
       } catch (HttpAuthenticationException e) {
         LOG.error("Kerberos Authentication failed", e);
         // Send a 401 to the client
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        response.addHeader(WWW_AUTHENTICATE, NEGOTIATE);
         response.getWriter().println("Authentication Error: " + e.getMessage());
         return;
       }
     }
     String doAsUserFromQuery = request.getHeader("doAs");
+    if(effectiveUser == null) {
+      effectiveUser = realUser.getShortUserName();
+    }
     if (doAsUserFromQuery != null) {
       if (!doAsEnabled) {
         throw new ServletException("Support for proxyuser is not configured");
       }
+      // The authenticated remote user is attempting to perform 'doAs' proxy user.
+      UserGroupInformation remoteUser = UserGroupInformation.createRemoteUser(effectiveUser);
       // create and attempt to authorize a proxy user (the client is attempting
       // to do proxy user)
-      UserGroupInformation ugi = UserGroupInformation.createProxyUser(doAsUserFromQuery,
realUser);
+      UserGroupInformation ugi = UserGroupInformation.createProxyUser(doAsUserFromQuery,
+          remoteUser);
       // validate the proxy user authorization
       try {
         ProxyUsers.authorize(ugi, request.getRemoteAddr(), conf);
@@ -113,8 +129,11 @@ public class ThriftHttpServlet extends TServlet {
    */
   private String doKerberosAuth(HttpServletRequest request)
       throws HttpAuthenticationException {
+    HttpKerberosServerAction action = new HttpKerberosServerAction(request, realUser);
     try {
-      return realUser.doAs(new HttpKerberosServerAction(request, realUser));
+      String principal = realUser.doAs(action);
+      outToken = action.outToken;
+      return principal;
     } catch (Exception e) {
       LOG.error("Failed to perform authentication");
       throw new HttpAuthenticationException(e);
@@ -125,6 +144,7 @@ public class ThriftHttpServlet extends TServlet {
   private static class HttpKerberosServerAction implements PrivilegedExceptionAction<String>
{
     HttpServletRequest request;
     UserGroupInformation serviceUGI;
+    String outToken = null;
     HttpKerberosServerAction(HttpServletRequest request, UserGroupInformation serviceUGI)
{
       this.request = request;
       this.serviceUGI = serviceUGI;
@@ -153,16 +173,19 @@ public class ThriftHttpServlet extends TServlet {
         // Create a GSS context
         gssContext = manager.createContext(serverCreds);
         // Get service ticket from the authorization header
-         String serviceTicketBase64 = getAuthHeader(request);
-         byte[] inToken = Base64.decodeBase64(serviceTicketBase64.getBytes());
-         gssContext.acceptSecContext(inToken, 0, inToken.length);
-         // Authenticate or deny based on its context completion
-         if (!gssContext.isEstablished()) {
+        String serviceTicketBase64 = getAuthHeader(request);
+        byte[] inToken = Base64.decode(serviceTicketBase64);
+        byte[] res = gssContext.acceptSecContext(inToken, 0, inToken.length);
+        if(res != null) {
+          outToken = Base64.encodeBytes(res).replace("\n", "");
+        }
+        // Authenticate or deny based on its context completion
+        if (!gssContext.isEstablished()) {
           throw new HttpAuthenticationException("Kerberos authentication failed: " +
               "unable to establish context with the service ticket " +
               "provided by the client.");
-         }
-         return SecurityUtil.getUserFromPrincipal(gssContext.getSrcName().toString());
+        }
+        return SecurityUtil.getUserFromPrincipal(gssContext.getSrcName().toString());
       } catch (GSSException e) {
         throw new HttpAuthenticationException("Kerberos authentication failed: ", e);
       } finally {
@@ -183,14 +206,14 @@ public class ThriftHttpServlet extends TServlet {
      */
     private String getAuthHeader(HttpServletRequest request)
         throws HttpAuthenticationException {
-      String authHeader = request.getHeader("Authorization");
+      String authHeader = request.getHeader(AUTHORIZATION);
       // Each http request must have an Authorization header
       if (authHeader == null || authHeader.isEmpty()) {
         throw new HttpAuthenticationException("Authorization header received " +
             "from the client is empty.");
       }
       String authHeaderBase64String;
-      int beginIndex = ("Negotiate ").length();
+      int beginIndex = (NEGOTIATE + " ").length();
       authHeaderBase64String = authHeader.substring(beginIndex);
       // Authorization header must have a payload
       if (authHeaderBase64String == null || authHeaderBase64String.isEmpty()) {


Mime
View raw message