View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.thrift2;
20  
21  import java.nio.ByteBuffer;
22  import java.security.PrivilegedExceptionAction;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.security.auth.Subject;
29  import javax.security.auth.login.AppConfigurationEntry;
30  import javax.security.auth.login.Configuration;
31  import javax.security.auth.login.LoginContext;
32  import javax.security.sasl.Sasl;
33  
34  import org.apache.hadoop.hbase.HBaseConfiguration;
35  
36  import org.apache.hadoop.hbase.thrift2.generated.TColumnValue;
37  import org.apache.hadoop.hbase.thrift2.generated.TGet;
38  import org.apache.hadoop.hbase.thrift2.generated.THBaseService;
39  import org.apache.hadoop.hbase.thrift2.generated.TPut;
40  import org.apache.hadoop.hbase.thrift2.generated.TResult;
41  import org.apache.thrift.protocol.TBinaryProtocol;
42  import org.apache.thrift.protocol.TProtocol;
43  import org.apache.thrift.transport.TFramedTransport;
44  import org.apache.thrift.transport.TSaslClientTransport;
45  import org.apache.thrift.transport.TSocket;
46  import org.apache.thrift.transport.TTransport;
47  
48  public class DemoClient {
49  
50    private static String host = "localhost";
51    private static int port = 9090;
52    private static boolean secure = false;
53    private static String user = null;
54  
55    public static void main(String[] args) throws Exception {
56      System.out.println("Thrift2 Demo");
57      System.out.println("Usage: DemoClient [host=localhost] [port=9090] [secure=false]");
58      System.out.println("This demo assumes you have a table called \"example\" with a column family called \"family1\"");
59  
60      // use passed in arguments instead of defaults
61      if (args.length >= 1) {
62        host = args[0];
63      }
64      if (args.length >= 2) {
65        port = Integer.parseInt(args[1]);
66      }
67      org.apache.hadoop.conf.Configuration conf = HBaseConfiguration.create();
68      String principal = conf.get("hbase.thrift.kerberos.principal");
69      if (principal != null) {
70        secure = true;
71        int slashIdx = principal.indexOf("/");
72        int atIdx = principal.indexOf("@");
73        int idx = slashIdx != -1 ? slashIdx : atIdx != -1 ? atIdx : principal.length();
74        user = principal.substring(0, idx);
75      }
76      if (args.length >= 3) {
77        secure = Boolean.parseBoolean(args[2]);
78      }
79  
80      final DemoClient client = new DemoClient();
81      Subject.doAs(getSubject(),
82        new PrivilegedExceptionAction<Void>() {
83          @Override
84          public Void run() throws Exception {
85            client.run();
86            return null;
87          }
88        });
89    }
90  
91    public void run() throws Exception {
92      int timeout = 10000;
93      boolean framed = false;
94  
95      TTransport transport = new TSocket(host, port, timeout);
96      if (framed) {
97        transport = new TFramedTransport(transport);
98      } else if (secure) {
99        /**
100        * The Thrift server the DemoClient is trying to connect to
101        * must have a matching principal, and support authentication.
102        *
103        * The HBase cluster must be secure, allow proxy user.
104        */
105       Map<String, String> saslProperties = new HashMap<String, String>();
106       saslProperties.put(Sasl.QOP, "auth-conf,auth-int,auth");
107       transport = new TSaslClientTransport("GSSAPI", null,
108         user != null ? user : "hbase",// Thrift server user name, should be an authorized proxy user
109         host, // Thrift server domain
110         saslProperties, null, transport);
111     }
112 
113     TProtocol protocol = new TBinaryProtocol(transport);
114     // This is our thrift client.
115     THBaseService.Iface client = new THBaseService.Client(protocol);
116 
117     // open the transport
118     transport.open();
119 
120     ByteBuffer table = ByteBuffer.wrap("example".getBytes());
121 
122     TPut put = new TPut();
123     put.setRow("row1".getBytes());
124 
125     TColumnValue columnValue = new TColumnValue();
126     columnValue.setFamily("family1".getBytes());
127     columnValue.setQualifier("qualifier1".getBytes());
128     columnValue.setValue("value1".getBytes());
129     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
130     columnValues.add(columnValue);
131     put.setColumnValues(columnValues);
132 
133     client.put(table, put);
134 
135     TGet get = new TGet();
136     get.setRow("row1".getBytes());
137 
138     TResult result = client.get(table, get);
139 
140     System.out.print("row = " + new String(result.getRow()));
141     for (TColumnValue resultColumnValue : result.getColumnValues()) {
142       System.out.print("family = " + new String(resultColumnValue.getFamily()));
143       System.out.print("qualifier = " + new String(resultColumnValue.getFamily()));
144       System.out.print("value = " + new String(resultColumnValue.getValue()));
145       System.out.print("timestamp = " + resultColumnValue.getTimestamp());
146     }
147 
148     transport.close();
149   }
150 
151   static Subject getSubject() throws Exception {
152     if (!secure) return new Subject();
153 
154     /*
155      * To authenticate the DemoClient, kinit should be invoked ahead.
156      * Here we try to get the Kerberos credential from the ticket cache.
157      */
158     LoginContext context = new LoginContext("", new Subject(), null,
159       new Configuration() {
160         @Override
161         public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
162           Map<String, String> options = new HashMap<String, String>();
163           options.put("useKeyTab", "false");
164           options.put("storeKey", "false");
165           options.put("doNotPrompt", "true");
166           options.put("useTicketCache", "true");
167           options.put("renewTGT", "true");
168           options.put("refreshKrb5Config", "true");
169           options.put("isInitiator", "true");
170           String ticketCache = System.getenv("KRB5CCNAME");
171           if (ticketCache != null) {
172             options.put("ticketCache", ticketCache);
173           }
174           options.put("debug", "true");
175 
176           return new AppConfigurationEntry[]{
177               new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
178                   AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
179                   options)};
180         }
181       });
182     context.login();
183     return context.getSubject();
184   }
185 }