1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.thrift;
20
21 import sun.misc.BASE64Encoder;
22
23 import java.io.UnsupportedEncodingException;
24 import java.nio.ByteBuffer;
25 import java.nio.charset.CharacterCodingException;
26 import java.nio.charset.Charset;
27 import java.nio.charset.CharsetDecoder;
28 import java.security.PrivilegedExceptionAction;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.SortedMap;
34 import java.util.TreeMap;
35
36 import javax.security.auth.Subject;
37 import javax.security.auth.login.AppConfigurationEntry;
38 import javax.security.auth.login.Configuration;
39 import javax.security.auth.login.LoginContext;
40
41 import org.apache.hadoop.hbase.thrift.generated.AlreadyExists;
42 import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
43 import org.apache.hadoop.hbase.thrift.generated.Hbase;
44 import org.apache.hadoop.hbase.thrift.generated.TCell;
45 import org.apache.hadoop.hbase.thrift.generated.TRowResult;
46 import org.apache.thrift.protocol.TBinaryProtocol;
47 import org.apache.thrift.protocol.TProtocol;
48 import org.apache.thrift.transport.THttpClient;
49 import org.apache.thrift.transport.TSocket;
50 import org.apache.thrift.transport.TTransport;
51 import org.ietf.jgss.GSSContext;
52 import org.ietf.jgss.GSSCredential;
53 import org.ietf.jgss.GSSException;
54 import org.ietf.jgss.GSSManager;
55 import org.ietf.jgss.GSSName;
56 import org.ietf.jgss.Oid;
57
58
59
60
61 public class HttpDoAsClient {
62
63 static protected int port;
64 static protected String host;
65 CharsetDecoder decoder = null;
66 private static boolean secure = false;
67
68 public static void main(String[] args) throws Exception {
69
70 if (args.length < 2 || args.length > 3) {
71
72 System.out.println("Invalid arguments!");
73 System.out.println("Usage: DemoClient host port [secure=false]");
74
75 System.exit(-1);
76 }
77
78 port = Integer.parseInt(args[1]);
79 host = args[0];
80 if (args.length > 2) {
81 secure = Boolean.parseBoolean(args[2]);
82 }
83
84 final HttpDoAsClient client = new HttpDoAsClient();
85 Subject.doAs(getSubject(),
86 new PrivilegedExceptionAction<Void>() {
87 @Override
88 public Void run() throws Exception {
89 client.run();
90 return null;
91 }
92 });
93 }
94
95 HttpDoAsClient() {
96 decoder = Charset.forName("UTF-8").newDecoder();
97 }
98
99
100 private String utf8(byte[] buf) {
101 try {
102 return decoder.decode(ByteBuffer.wrap(buf)).toString();
103 } catch (CharacterCodingException e) {
104 return "[INVALID UTF-8]";
105 }
106 }
107
108
109 private byte[] bytes(String s) {
110 try {
111 return s.getBytes("UTF-8");
112 } catch (UnsupportedEncodingException e) {
113 e.printStackTrace();
114 return null;
115 }
116 }
117
118 private void run() throws Exception {
119 TTransport transport = new TSocket(host, port);
120
121 transport.open();
122 String url = "http://" + host + ":" + port;
123 THttpClient httpClient = new THttpClient(url);
124 httpClient.open();
125 TProtocol protocol = new TBinaryProtocol(httpClient);
126 Hbase.Client client = new Hbase.Client(protocol);
127
128 byte[] t = bytes("demo_table");
129
130
131
132
133 System.out.println("scanning tables...");
134 for (ByteBuffer name : refresh(client, httpClient).getTableNames()) {
135 System.out.println(" found: " + utf8(name.array()));
136 if (utf8(name.array()).equals(utf8(t))) {
137 if (client.isTableEnabled(name)) {
138 System.out.println(" disabling table: " + utf8(name.array()));
139 refresh(client, httpClient).disableTable(name);
140 }
141 System.out.println(" deleting table: " + utf8(name.array()));
142 refresh(client, httpClient).deleteTable(name);
143 }
144 }
145
146
147
148
149
150
151 ArrayList<ColumnDescriptor> columns = new ArrayList<ColumnDescriptor>();
152 ColumnDescriptor col;
153 col = new ColumnDescriptor();
154 col.name = ByteBuffer.wrap(bytes("entry:"));
155 col.timeToLive = Integer.MAX_VALUE;
156 col.maxVersions = 10;
157 columns.add(col);
158 col = new ColumnDescriptor();
159 col.name = ByteBuffer.wrap(bytes("unused:"));
160 col.timeToLive = Integer.MAX_VALUE;
161 columns.add(col);
162
163 System.out.println("creating table: " + utf8(t));
164 try {
165
166 refresh(client, httpClient).createTable(ByteBuffer.wrap(t), columns);
167 } catch (AlreadyExists ae) {
168 System.out.println("WARN: " + ae.message);
169 }
170
171 System.out.println("column families in " + utf8(t) + ": ");
172 Map<ByteBuffer, ColumnDescriptor> columnMap = refresh(client, httpClient)
173 .getColumnDescriptors(ByteBuffer.wrap(t));
174 for (ColumnDescriptor col2 : columnMap.values()) {
175 System.out.println(" column: " + utf8(col2.name.array()) + ", maxVer: " + Integer.toString(col2.maxVersions));
176 }
177
178 transport.close();
179 httpClient.close();
180 }
181
182 private Hbase.Client refresh(Hbase.Client client, THttpClient httpClient) {
183 if(secure) {
184 httpClient.setCustomHeader("doAs", "hbase");
185 try {
186 httpClient.setCustomHeader("Authorization", generateTicket());
187 } catch (GSSException e) {
188 e.printStackTrace();
189 }
190 }
191 return client;
192 }
193
194 private String generateTicket() throws GSSException {
195 final GSSManager manager = GSSManager.getInstance();
196
197 Oid krb5PrincipalOid = new Oid("1.2.840.113554.1.2.2.1");
198 Oid KERB_V5_OID = new Oid("1.2.840.113554.1.2.2");
199 final GSSName clientName = manager.createName("hbase/node-1.internal@INTERNAL",
200 krb5PrincipalOid);
201 final GSSCredential clientCred = manager.createCredential(clientName,
202 8 * 3600,
203 KERB_V5_OID,
204 GSSCredential.INITIATE_ONLY);
205
206 final GSSName serverName = manager.createName("hbase/node-1.internal@INTERNAL", krb5PrincipalOid);
207
208 final GSSContext context = manager.createContext(serverName,
209 KERB_V5_OID,
210 clientCred,
211 GSSContext.DEFAULT_LIFETIME);
212 context.requestMutualAuth(true);
213 context.requestConf(false);
214 context.requestInteg(true);
215
216 final byte[] outToken = context.initSecContext(new byte[0], 0, 0);
217 StringBuffer outputBuffer = new StringBuffer();
218 outputBuffer.append("Negotiate ");
219 outputBuffer.append(new BASE64Encoder().encode(outToken).replace("\n", ""));
220 System.out.print("Ticket is: " + outputBuffer);
221 return outputBuffer.toString();
222 }
223
224 private void printVersions(ByteBuffer row, List<TCell> versions) {
225 StringBuilder rowStr = new StringBuilder();
226 for (TCell cell : versions) {
227 rowStr.append(utf8(cell.value.array()));
228 rowStr.append("; ");
229 }
230 System.out.println("row: " + utf8(row.array()) + ", values: " + rowStr);
231 }
232
233 private void printRow(TRowResult rowResult) {
234
235
236 TreeMap<String, TCell> sorted = new TreeMap<String, TCell>();
237 for (Map.Entry<ByteBuffer, TCell> column : rowResult.columns.entrySet()) {
238 sorted.put(utf8(column.getKey().array()), column.getValue());
239 }
240
241 StringBuilder rowStr = new StringBuilder();
242 for (SortedMap.Entry<String, TCell> entry : sorted.entrySet()) {
243 rowStr.append(entry.getKey());
244 rowStr.append(" => ");
245 rowStr.append(utf8(entry.getValue().value.array()));
246 rowStr.append("; ");
247 }
248 System.out.println("row: " + utf8(rowResult.row.array()) + ", cols: " + rowStr);
249 }
250
251 static Subject getSubject() throws Exception {
252 if (!secure) return new Subject();
253
254
255
256
257 LoginContext context = new LoginContext("", new Subject(), null,
258 new Configuration() {
259 @Override
260 public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
261 Map<String, String> options = new HashMap<String, String>();
262 options.put("useKeyTab", "false");
263 options.put("storeKey", "false");
264 options.put("doNotPrompt", "true");
265 options.put("useTicketCache", "true");
266 options.put("renewTGT", "true");
267 options.put("refreshKrb5Config", "true");
268 options.put("isInitiator", "true");
269 String ticketCache = System.getenv("KRB5CCNAME");
270 if (ticketCache != null) {
271 options.put("ticketCache", ticketCache);
272 }
273 options.put("debug", "true");
274
275 return new AppConfigurationEntry[]{
276 new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
277 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
278 options)};
279 }
280 });
281 context.login();
282 return context.getSubject();
283 }
284 }