You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by jx...@apache.org on 2014/12/18 01:14:07 UTC
[2/2] hbase git commit: HBASE-12704 Add demo client which uses doAs
functionality on Thrift-over-HTTPS
HBASE-12704 Add demo client which uses doAs functionality on Thrift-over-HTTPS
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/ba86c18f
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/ba86c18f
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/ba86c18f
Branch: refs/heads/master
Commit: ba86c18f20962f31a90bfecc89d4fdba93dc39d9
Parents: 072b2d6
Author: Srikanth Srungarapu <ss...@cloudera.com>
Authored: Thu Dec 11 19:13:53 2014 -0800
Committer: Jimmy Xiang <jx...@cloudera.com>
Committed: Wed Dec 17 16:13:24 2014 -0800
----------------------------------------------------------------------
.../hadoop/hbase/thrift/HttpDoAsClient.java | 290 +++++++++++++++++++
1 file changed, 290 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/ba86c18f/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
new file mode 100644
index 0000000..9da79ac
--- /dev/null
+++ b/hbase-examples/src/main/java/org/apache/hadoop/hbase/thrift/HttpDoAsClient.java
@@ -0,0 +1,290 @@
+/**
+ *
+ * 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.hbase.thrift;
+
+import sun.misc.BASE64Encoder;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+
+import org.apache.hadoop.hbase.thrift.generated.AlreadyExists;
+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.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.THttpClient;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+
+/**
+ * See the instructions under hbase-examples/README.txt
+ */
+public class HttpDoAsClient {
+
+ static protected int port;
+ static protected String host;
+ CharsetDecoder decoder = null;
+ private static boolean secure = false;
+
+ public static void main(String[] args) throws Exception {
+
+ if (args.length < 2 || args.length > 3) {
+
+ System.out.println("Invalid arguments!");
+ System.out.println("Usage: DemoClient host port [secure=false]");
+
+ System.exit(-1);
+ }
+
+ port = Integer.parseInt(args[1]);
+ host = args[0];
+ if (args.length > 2) {
+ secure = Boolean.parseBoolean(args[2]);
+ }
+
+ final HttpDoAsClient client = new HttpDoAsClient();
+ Subject.doAs(getSubject(),
+ new PrivilegedExceptionAction<Void>() {
+ @Override
+ public Void run() throws Exception {
+ client.run();
+ return null;
+ }
+ });
+ }
+
+ HttpDoAsClient() {
+ decoder = Charset.forName("UTF-8").newDecoder();
+ }
+
+ // Helper to translate byte[]'s to UTF8 strings
+ private String utf8(byte[] buf) {
+ try {
+ return decoder.decode(ByteBuffer.wrap(buf)).toString();
+ } catch (CharacterCodingException e) {
+ return "[INVALID UTF-8]";
+ }
+ }
+
+ // Helper to translate strings to UTF8 bytes
+ private byte[] bytes(String s) {
+ try {
+ return s.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private void run() throws Exception {
+ TTransport transport = new TSocket(host, port);
+
+ transport.open();
+ String url = "http://" + host + ":" + port;
+ THttpClient httpClient = new THttpClient(url);
+ httpClient.open();
+ TProtocol protocol = new TBinaryProtocol(httpClient);
+ Hbase.Client client = new Hbase.Client(protocol);
+
+ byte[] t = bytes("demo_table");
+
+ //
+ // Scan all tables, look for the demo table and delete it.
+ //
+ System.out.println("scanning tables...");
+ 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)) {
+ System.out.println(" disabling table: " + utf8(name.array()));
+ refresh(client, httpClient).disableTable(name);
+ }
+ System.out.println(" deleting table: " + utf8(name.array()));
+ refresh(client, httpClient).deleteTable(name);
+ }
+ }
+
+
+
+ //
+ // Create the demo table with two column families, entry: and unused:
+ //
+ ArrayList<ColumnDescriptor> columns = new ArrayList<ColumnDescriptor>();
+ ColumnDescriptor col;
+ col = new ColumnDescriptor();
+ col.name = ByteBuffer.wrap(bytes("entry:"));
+ col.timeToLive = Integer.MAX_VALUE;
+ col.maxVersions = 10;
+ columns.add(col);
+ col = new ColumnDescriptor();
+ col.name = ByteBuffer.wrap(bytes("unused:"));
+ col.timeToLive = Integer.MAX_VALUE;
+ columns.add(col);
+
+ System.out.println("creating table: " + utf8(t));
+ try {
+
+ refresh(client, httpClient).createTable(ByteBuffer.wrap(t), columns);
+ } catch (AlreadyExists ae) {
+ System.out.println("WARN: " + ae.message);
+ }
+
+ System.out.println("column families in " + utf8(t) + ": ");
+ Map<ByteBuffer, ColumnDescriptor> columnMap = refresh(client, httpClient)
+ .getColumnDescriptors(ByteBuffer.wrap(t));
+ for (ColumnDescriptor col2 : columnMap.values()) {
+ System.out.println(" column: " + utf8(col2.name.array()) + ", maxVer: " + Integer.toString(col2.maxVersions));
+ }
+
+ transport.close();
+ httpClient.close();
+ }
+
+ private Hbase.Client refresh(Hbase.Client client, THttpClient httpClient) {
+ if(secure) {
+ httpClient.setCustomHeader("doAs", "hbase");
+ try {
+ httpClient.setCustomHeader("Authorization", generateTicket());
+ } catch (GSSException e) {
+ e.printStackTrace();
+ }
+ }
+ return client;
+ }
+
+ private String generateTicket() throws GSSException {
+ final GSSManager manager = GSSManager.getInstance();
+ // 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",
+ 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 GSSContext context = manager.createContext(serverName,
+ KERB_V5_OID,
+ clientCred,
+ GSSContext.DEFAULT_LIFETIME);
+ context.requestMutualAuth(true);
+ context.requestConf(false);
+ context.requestInteg(true);
+
+ 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", ""));
+ System.out.print("Ticket is: " + outputBuffer);
+ return outputBuffer.toString();
+ }
+
+ private void printVersions(ByteBuffer row, List<TCell> versions) {
+ StringBuilder rowStr = new StringBuilder();
+ for (TCell cell : versions) {
+ rowStr.append(utf8(cell.value.array()));
+ rowStr.append("; ");
+ }
+ System.out.println("row: " + utf8(row.array()) + ", values: " + rowStr);
+ }
+
+ private void printRow(TRowResult rowResult) {
+ // copy values into a TreeMap to get them in sorted order
+
+ TreeMap<String, TCell> sorted = new TreeMap<String, TCell>();
+ for (Map.Entry<ByteBuffer, TCell> column : rowResult.columns.entrySet()) {
+ sorted.put(utf8(column.getKey().array()), column.getValue());
+ }
+
+ StringBuilder rowStr = new StringBuilder();
+ for (SortedMap.Entry<String, TCell> entry : sorted.entrySet()) {
+ rowStr.append(entry.getKey());
+ rowStr.append(" => ");
+ rowStr.append(utf8(entry.getValue().value.array()));
+ rowStr.append("; ");
+ }
+ System.out.println("row: " + utf8(rowResult.row.array()) + ", cols: " + rowStr);
+ }
+
+ private void printRow(List<TRowResult> rows) {
+ for (TRowResult rowResult : rows) {
+ printRow(rowResult);
+ }
+ }
+
+ static Subject getSubject() throws Exception {
+ if (!secure) return new Subject();
+ /*
+ * To authenticate the DemoClient, kinit should be invoked ahead.
+ * Here we try to get the Kerberos credential from the ticket cache.
+ */
+ LoginContext context = new LoginContext("", new Subject(), null,
+ new Configuration() {
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, String> options = new HashMap<String, String>();
+ options.put("useKeyTab", "false");
+ options.put("storeKey", "false");
+ options.put("doNotPrompt", "true");
+ options.put("useTicketCache", "true");
+ options.put("renewTGT", "true");
+ options.put("refreshKrb5Config", "true");
+ options.put("isInitiator", "true");
+ String ticketCache = System.getenv("KRB5CCNAME");
+ if (ticketCache != null) {
+ options.put("ticketCache", ticketCache);
+ }
+ options.put("debug", "true");
+
+ return new AppConfigurationEntry[]{
+ new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ options)};
+ }
+ });
+ context.login();
+ return context.getSubject();
+ }
+}