Package org.apache.hadoop.hive.thrift

Source Code of org.apache.hadoop.hive.thrift.TestHadoop20SAuthBridge$MyHadoopThriftAuthBridge20S

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.hadoop.hive.thrift;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;

import junit.framework.TestCase;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hadoop.hive.metastore.HiveMetaStore;
import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
import org.apache.hadoop.hive.metastore.MetaStoreUtils;
import org.apache.hadoop.hive.metastore.api.Database;
import org.apache.hadoop.hive.metastore.api.MetaException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.SaslRpcServer;
import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
import org.apache.hadoop.security.authorize.AuthorizationException;
import org.apache.hadoop.security.authorize.ProxyUsers;
import org.apache.hadoop.security.token.SecretManager.InvalidToken;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager.DelegationTokenInformation;
import org.apache.hadoop.security.token.delegation.DelegationKey;
import org.apache.hadoop.util.StringUtils;
import org.apache.thrift.transport.TSaslServerTransport;
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.transport.TTransportFactory;

public class TestHadoop20SAuthBridge extends TestCase {

  private static class MyHadoopThriftAuthBridge20S extends HadoopThriftAuthBridge20S {
    @Override
    public Server createServer(String keytabFile, String principalConf)
    throws TTransportException {
      //Create a Server that doesn't interpret any Kerberos stuff
      return new Server();
    }

    static class Server extends HadoopThriftAuthBridge20S.Server {
      public Server() throws TTransportException {
        super();
      }
      @Override
      public TTransportFactory createTransportFactory()
      throws TTransportException {
        TSaslServerTransport.Factory transFactory =
          new TSaslServerTransport.Factory();
        transFactory.addServerDefinition(AuthMethod.DIGEST.getMechanismName(),
            null, SaslRpcServer.SASL_DEFAULT_REALM,
            SaslRpcServer.SASL_PROPS,
            new SaslDigestCallbackHandler(secretManager));

        return new TUGIAssumingTransportFactory(transFactory, realUgi);
      }
      static DelegationTokenStore TOKEN_STORE = new MemoryTokenStore();

      @Override
      protected DelegationTokenStore getTokenStore(Configuration conf) throws IOException {
        return TOKEN_STORE;
      }
    }
  }


  private HiveConf conf;

  private void configureSuperUserIPAddresses(Configuration conf,
      String superUserShortName) throws IOException {
    ArrayList<String> ipList = new ArrayList<String>();
    Enumeration<NetworkInterface> netInterfaceList = NetworkInterface
        .getNetworkInterfaces();
    while (netInterfaceList.hasMoreElements()) {
      NetworkInterface inf = netInterfaceList.nextElement();
      Enumeration<InetAddress> addrList = inf.getInetAddresses();
      while (addrList.hasMoreElements()) {
        InetAddress addr = addrList.nextElement();
        ipList.add(addr.getHostAddress());
      }
    }
    StringBuilder builder = new StringBuilder();
    for (String ip : ipList) {
      builder.append(ip);
      builder.append(',');
    }
    builder.append("127.0.1.1,");
    builder.append(InetAddress.getLocalHost().getCanonicalHostName());
    conf.setStrings(ProxyUsers.getProxySuperuserIpConfKey(superUserShortName),
        builder.toString());
  }

  public void setup(final int port) throws Exception {
    System.setProperty(HiveConf.ConfVars.METASTORE_USE_THRIFT_SASL.varname,
        "true");
    System.setProperty(HiveConf.ConfVars.METASTOREURIS.varname,
        "thrift://localhost:" + port);
    System.setProperty(HiveConf.ConfVars.METASTOREWAREHOUSE.varname, new Path(
        System.getProperty("test.build.data", "/tmp")).toString());
    conf = new HiveConf(TestHadoop20SAuthBridge.class);
    conf.setBoolVar(ConfVars.METASTORE_MODE, false);
    MetaStoreUtils.startMetaStore(port, new MyHadoopThriftAuthBridge20S());
  }

  /**
   * Test delegation token store/load from shared store.
   * @throws Exception
   */
  public void testDelegationTokenSharedStore() throws Exception {
    UserGroupInformation clientUgi = UserGroupInformation.getCurrentUser();

    TokenStoreDelegationTokenSecretManager tokenManager =
        new TokenStoreDelegationTokenSecretManager(0, 60*60*1000, 60*60*1000, 0,
            MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE);
    // initializes current key
    tokenManager.startThreads();
    tokenManager.stopThreads();

    String tokenStrForm = tokenManager.getDelegationToken(clientUgi.getShortUserName());
    Token<DelegationTokenIdentifier> t= new Token<DelegationTokenIdentifier>();
    t.decodeFromUrlString(tokenStrForm);

    //check whether the username in the token is what we expect
    DelegationTokenIdentifier d = new DelegationTokenIdentifier();
    d.readFields(new DataInputStream(new ByteArrayInputStream(
        t.getIdentifier())));
    assertTrue("Usernames don't match",
        clientUgi.getShortUserName().equals(d.getUser().getShortUserName()));

    DelegationTokenInformation tokenInfo = MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE
        .getToken(d);
    assertNotNull("token not in store", tokenInfo);
    assertFalse("duplicate token add",
        MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE.addToken(d, tokenInfo));

    // check keys are copied from token store when token is loaded
    TokenStoreDelegationTokenSecretManager anotherManager =
        new TokenStoreDelegationTokenSecretManager(0, 0, 0, 0,
            MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE);
   assertEquals("master keys empty on init", 0,
        anotherManager.getAllKeys().length);
    assertNotNull("token loaded",
        anotherManager.retrievePassword(d));
    anotherManager.renewToken(t, clientUgi.getShortUserName());
    assertEquals("master keys not loaded from store",
        MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE.getMasterKeys().length,
        anotherManager.getAllKeys().length);

    // cancel the delegation token
    tokenManager.cancelDelegationToken(tokenStrForm);
    assertNull("token not removed from store after cancel",
        MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE.getToken(d));
    assertFalse("token removed (again)",
        MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE.removeToken(d));
    try {
      anotherManager.retrievePassword(d);
      fail("InvalidToken expected after cancel");
    } catch (InvalidToken ex) {
      // expected
    }

    // token expiration
    MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE.addToken(d,
        new DelegationTokenInformation(0, t.getPassword()));
    assertNotNull(MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE.getToken(d));
    anotherManager.removeExpiredTokens();
    assertNull("Expired token not removed",
        MyHadoopThriftAuthBridge20S.Server.TOKEN_STORE.getToken(d));

    // key expiration - create an already expired key
    anotherManager.startThreads(); // generates initial key
    anotherManager.stopThreads();
    DelegationKey expiredKey = new DelegationKey(-1, 0, anotherManager.getAllKeys()[0].getKey());
    anotherManager.logUpdateMasterKey(expiredKey); // updates key with sequence number
    assertTrue("expired key not in allKeys",
        anotherManager.reloadKeys().containsKey(expiredKey.getKeyId()));
    anotherManager.rollMasterKeyExt();
    assertFalse("Expired key not removed",
        anotherManager.reloadKeys().containsKey(expiredKey.getKeyId()));
  }

  public void testSaslWithHiveMetaStore() throws Exception {
    setup(10000);
    UserGroupInformation clientUgi = UserGroupInformation.getCurrentUser();
    obtainTokenAndAddIntoUGI(clientUgi, null);
    obtainTokenAndAddIntoUGI(clientUgi, "tokenForFooTablePartition");
  }

  public void testMetastoreProxyUser() throws Exception {
    setup(10010);

    final String proxyUserName = "proxyUser";
    //set the configuration up such that proxyUser can act on
    //behalf of all users belonging to the group foo_bar_group (
    //a dummy group)
    String[] groupNames =
      new String[] { "foo_bar_group" };
    setGroupsInConf(groupNames, proxyUserName);

    final UserGroupInformation delegationTokenUser =
      UserGroupInformation.getCurrentUser();

    final UserGroupInformation proxyUserUgi =
      UserGroupInformation.createRemoteUser(proxyUserName);
    String tokenStrForm = proxyUserUgi.doAs(new PrivilegedExceptionAction<String>() {
      public String run() throws Exception {
        try {
          //Since the user running the test won't belong to a non-existent group
          //foo_bar_group, the call to getDelegationTokenStr will fail
          return getDelegationTokenStr(delegationTokenUser, proxyUserUgi);
        } catch (AuthorizationException ae) {
          return null;
        }
      }
    });
    assertTrue("Expected the getDelegationToken call to fail",
        tokenStrForm == null);

    //set the configuration up such that proxyUser can act on
    //behalf of all users belonging to the real group(s) that the
    //user running the test belongs to
    setGroupsInConf(UserGroupInformation.getCurrentUser().getGroupNames(),
        proxyUserName);
    tokenStrForm = proxyUserUgi.doAs(new PrivilegedExceptionAction<String>() {
      public String run() throws Exception {
        try {
          //Since the user running the test belongs to the group
          //obtained above the call to getDelegationTokenStr will succeed
          return getDelegationTokenStr(delegationTokenUser, proxyUserUgi);
        } catch (AuthorizationException ae) {
          return null;
        }
      }
    });
    assertTrue("Expected the getDelegationToken call to not fail",
        tokenStrForm != null);
    Token<DelegationTokenIdentifier> t= new Token<DelegationTokenIdentifier>();
    t.decodeFromUrlString(tokenStrForm);
    //check whether the username in the token is what we expect
    DelegationTokenIdentifier d = new DelegationTokenIdentifier();
    d.readFields(new DataInputStream(new ByteArrayInputStream(
        t.getIdentifier())));
    assertTrue("Usernames don't match",
        delegationTokenUser.getShortUserName().equals(d.getUser().getShortUserName()));

  }

  private void setGroupsInConf(String[] groupNames, String proxyUserName)
  throws IOException {
   conf.set(
      ProxyUsers.getProxySuperuserGroupConfKey(proxyUserName),
      StringUtils.join(",", Arrays.asList(groupNames)));
    configureSuperUserIPAddresses(conf, proxyUserName);
    ProxyUsers.refreshSuperUserGroupsConfiguration(conf);
  }

  private String getDelegationTokenStr(UserGroupInformation ownerUgi,
      UserGroupInformation realUgi) throws Exception {
    //obtain a token by directly invoking the metastore operation(without going
    //through the thrift interface). Obtaining a token makes the secret manager
    //aware of the user and that it gave the token to the user
    //also set the authentication method explicitly to KERBEROS. Since the
    //metastore checks whether the authentication method is KERBEROS or not
    //for getDelegationToken, and the testcases don't use
    //kerberos, this needs to be done
    HadoopThriftAuthBridge20S.Server.authenticationMethod
                             .set(AuthenticationMethod.KERBEROS);
    HadoopThriftAuthBridge20S.Server.remoteAddress.set(InetAddress.getLocalHost());
    return
        HiveMetaStore.getDelegationToken(ownerUgi.getShortUserName(),
            realUgi.getShortUserName());
  }

  private void obtainTokenAndAddIntoUGI(UserGroupInformation clientUgi,
      String tokenSig) throws Exception {
    String tokenStrForm = getDelegationTokenStr(clientUgi, clientUgi);
    Token<DelegationTokenIdentifier> t= new Token<DelegationTokenIdentifier>();
    t.decodeFromUrlString(tokenStrForm);

    //check whether the username in the token is what we expect
    DelegationTokenIdentifier d = new DelegationTokenIdentifier();
    d.readFields(new DataInputStream(new ByteArrayInputStream(
        t.getIdentifier())));
    assertTrue("Usernames don't match",
        clientUgi.getShortUserName().equals(d.getUser().getShortUserName()));

    if (tokenSig != null) {
      conf.set("hive.metastore.token.signature", tokenSig);
      t.setService(new Text(tokenSig));
    }
    //add the token to the clientUgi for securely talking to the metastore
    clientUgi.addToken(t);
    //Create the metastore client as the clientUgi. Doing so this
    //way will give the client access to the token that was added earlier
    //in the clientUgi
    HiveMetaStoreClient hiveClient =
      clientUgi.doAs(new PrivilegedExceptionAction<HiveMetaStoreClient>() {
        public HiveMetaStoreClient run() throws Exception {
          HiveMetaStoreClient hiveClient =
            new HiveMetaStoreClient(conf);
          return hiveClient;
        }
      });

    assertTrue("Couldn't connect to metastore", hiveClient != null);

    //try out some metastore operations
    createDBAndVerifyExistence(hiveClient);

    //check that getDelegationToken fails since we are not authenticating
    //over kerberos
    boolean pass = false;
    try {
      hiveClient.getDelegationToken(clientUgi.getUserName());
    } catch (MetaException ex) {
      pass = true;
    }
    assertTrue("Expected the getDelegationToken call to fail", pass == true);
    hiveClient.close();

    //Now cancel the delegation token
    HiveMetaStore.cancelDelegationToken(tokenStrForm);

    //now metastore connection should fail
    hiveClient =
      clientUgi.doAs(new PrivilegedExceptionAction<HiveMetaStoreClient>() {
        public HiveMetaStoreClient run() {
          try {
            HiveMetaStoreClient hiveClient =
              new HiveMetaStoreClient(conf);
            return hiveClient;
          } catch (MetaException e) {
            return null;
          }
        }
      });
    assertTrue("Expected metastore operations to fail", hiveClient == null);
  }

  private void createDBAndVerifyExistence(HiveMetaStoreClient client)
  throws Exception {
    String dbName = "simpdb";
    Database db = new Database();
    db.setName(dbName);
    client.createDatabase(db);
    Database db1 = client.getDatabase(dbName);
    client.dropDatabase(dbName);
    assertTrue("Databases do not match", db1.getName().equals(db.getName()));
  }
}
TOP

Related Classes of org.apache.hadoop.hive.thrift.TestHadoop20SAuthBridge$MyHadoopThriftAuthBridge20S

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.