Java tutorial
/** * 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.io.crypto.tool; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.net.URL; import java.util.Random; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.apache.commons.codec.binary.Base64; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.Text; import org.apache.hadoop.io.crypto.bee.BeeConstants; import org.apache.hadoop.io.crypto.bee.RestResult; import org.apache.hadoop.io.crypto.bee.key.sasl.common.SaslUtil; import org.apache.hadoop.io.crypto.tool.kerberos.SpnegoRestCli; import org.apache.hadoop.security.Credentials; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; public class BeeCli { static final Logger logger = LoggerFactory.getLogger(BeeCli.class); public enum CmdType { NONE(0), TOKEN(1), CRYPTO(2); public final int type; private CmdType(int type) { this.type = type; } } public enum CmdAction { NONE(0), TOKEN_CREATE(1), TOKEN_REMOVE(2), CRYPTO_ENCRYPT(3), CRYPTO_DECRYPT(4); public final int action; private CmdAction(int action) { this.action = action; } } private String strManagerUrl = ""; private CmdType cmdType = CmdType.NONE; private CmdAction cmdAction = CmdAction.NONE; private String strFileInputPath = ""; private String strFileOutputPath = ""; private String strKeyName = ""; private String strHexKey = ""; private URL buildRequestUrl(String method) throws Exception { return buildRequestUrl(method, null); } private URL buildRequestUrl(String method, String parameter) throws Exception { // String strUrl = "http://" + this.strManagerUrl + BeeConstants.API_ROOT + // method; String strUrl = "https://" + this.strManagerUrl + BeeConstants.API_ROOT + method; if (parameter != null && !parameter.isEmpty()) { strUrl = strUrl + "/" + Base64.encodeBase64URLSafeString(parameter.getBytes()); } return new URL(strUrl); } private void createToken() throws Exception { if (new File(this.strFileOutputPath).exists()) throw new Exception("Output file already exists: " + this.strFileOutputPath); StringBuffer sb = new SpnegoRestCli(buildRequestUrl("createToken")).getResult(); // logger.debug("Get response:" + sb.toString()); JsonElement jelement = new JsonParser().parse(sb.toString()); JsonObject jobject = jelement.getAsJsonObject(); JsonObject jobjectMsg = jobject.getAsJsonObject("msg"); String msg = jobjectMsg.toString(); String result = jobject.get("result").toString(); if (0 == result.replaceAll("\"", "").compareTo(BeeConstants.ResponseStatus.SUCCESS.toString())) { Credentials credentials = new Credentials(); credentials.addSecretKey(new Text(SaslUtil.KEY_TOKEN_ALIAS), msg.getBytes()); credentailsFileWriter(credentials, this.strFileOutputPath); } else { throw new Exception("Create token from Key Manager Server fail: " + msg); } } private void credentailsFileWriter(Credentials credentials, String path) throws Exception { DataOutputStream dos = new DataOutputStream(new FileOutputStream(path)); credentials.writeTokenStorageToStream(dos); File f = new File(path); f.setExecutable(false, false); f.setReadable(true, true); f.setWritable(true, true); } private File rename2TmpFile(String srcPath) throws Exception { File file = new File(srcPath).getAbsoluteFile(); File parentFile = file.getParentFile(); String tmpName = "." + file.getName() + new Random().nextInt(10000); File tmpFile = new File(parentFile, tmpName); // In current Java version on linux, we should add more checking, // otherwise, File.renameTo always return true even file not movable if (file.exists()) { if (file.getParentFile().canWrite()) { if (file.renameTo(tmpFile)) { return tmpFile; } else { throw new Exception("Fail to delete file: " + this.strFileInputPath); } } else { throw new Exception("Permission denied to remove the file: " + file.getPath()); } } else { throw new Exception("Input file not exist"); } } private void removeToken() throws Exception { if (!new File(this.strFileInputPath).getParentFile().canExecute()) { throw new Exception("Permission Denied to access " + this.strFileInputPath); } Credentials credentials = Credentials.readTokenStorageFile(new Path("file://" + this.strFileInputPath), new Configuration()); byte[] buffer = credentials.getSecretKey(new Text(SaslUtil.KEY_TOKEN_ALIAS)); if (buffer.length == 0) throw new Exception("Fail! Bad Token file, fail to get token value"); File tmpFile = rename2TmpFile(this.strFileInputPath); try { StringBuffer sb = new SpnegoRestCli(this.buildRequestUrl("removeToken", new String(buffer))) .getResult(); RestResult restResult = new Gson().fromJson(sb.toString(), RestResult.class); if (restResult.getResult().equals(BeeConstants.ResponseStatus.SUCCESS.toString())) { tmpFile.delete(); } else { // Rollback: Move back the credential file // In general, no exception will be raise by File.renameTo // because it has write permission here (file.renameTo() is passed) tmpFile.renameTo(new File(this.strFileInputPath)); throw new Exception("Fail to remove token from Key Manager server:" + restResult.getMsg()); } } catch (Exception e) { // Rollback: Write back the credential file // In general, no exception will be raise by File.renameTo // because it has write permission here (file.delete() is passed) tmpFile.renameTo(new File(this.strFileInputPath)); throw new Exception(e); } } private void fileCrypto() throws Exception { String strFileIn = "file://" + this.strFileInputPath; String strFileOut = "file://" + this.strFileOutputPath; String hexKey; if (this.strHexKey.isEmpty()) { StringBuffer sb = new SpnegoRestCli(buildRequestUrl("getHexkey/" + this.strKeyName)).getResult(); RestResult restResult = new Gson().fromJson(sb.toString(), RestResult.class); if (restResult.getResult().equals(BeeConstants.ResponseStatus.SUCCESS.toString())) { hexKey = restResult.getMsg(); } else { throw new Exception("Error! Get key from Key Manager fail. Message: " + restResult.getMsg()); } } else { hexKey = this.strHexKey; } CryptoApiTool cryptoApiTool = new CryptoApiTool(hexKey, strFileIn, strFileOut); if (this.cmdAction.equals(CmdAction.CRYPTO_ENCRYPT)) { cryptoApiTool.apiEncryption(); } else { cryptoApiTool.apiDecryption(); } } public void requestHandler() throws Exception { if (this.cmdType == CmdType.TOKEN) { if (this.cmdAction == CmdAction.TOKEN_CREATE) { createToken(); } else if (this.cmdAction == CmdAction.TOKEN_REMOVE) { removeToken(); } else { throw new Exception("Not supported commnad action(" + cmdAction + ") for type (" + cmdType + ")"); } } else if (this.cmdType == CmdType.CRYPTO) { fileCrypto(); } else { throw new Exception("Not Supported command type"); } } private void errorExitOnSetup(String msg) throws ParseException { System.out.println(); System.out.println("Error! " + msg); System.out.println(); System.exit(1); } public void setupOptions(String[] args) throws ParseException { String strUsage = "Usage: Support Actions\n" + " Token Create: bee-cli.sh -type token -action create -km <BeeKeyManager:port> -fileout <FILEOUT>\n" + " Token Remove: bee-cli.sh -type token -action remove -km <BeeKeyManager:port> -filein <FILEIN>\n" + " Crypto Encrypt: bee-cli.sh -type crypto -action encrypt -km <BeeKeyManager:port> -keyname <keyname> -filein <FILEIN> -fileout <FILEOUT>\n" + " Crypto Encrypt: bee-cli.sh -type crypto -action encrypt -hexkey <HexKeyString> -filein <FILEIN> -fileout <FILEOUT>\n" + " Crypto Decrypt: bee-cli.sh -type crypto -action decrypt -km <BeeKeyManager:port> -keyname <keyname> -filein <FILEIN> -fileout <FILEOUT>\n" + " Crypto Decrypt: bee-cli.sh -type crypto -action decrypt -hexkey <HexKeyString> -filein <FILEIN> -fileout <FILEOUT>\n"; Options options = new Options(); options.addOption("km", true, "The Url of Key Manager, E.g. 10.1.1.2:8080"); options.addOption("type", true, "token/crypto"); options.addOption("action", true, "<token>: create/remove, <crypto>:encrypt/decrypt"); options.addOption("filein", true, "Full file path for input file"); options.addOption("fileout", true, "Full file path for output file"); options.addOption("keyname", true, "<crypto> The key name for file encryption/decryption"); options.addOption("hexkey", true, "<crypto> The Hex secret key string for file encryption/decryption"); CommandLineParser parser = new PosixParser(); CommandLine cmd = parser.parse(options, args); HelpFormatter formatter = new HelpFormatter(); System.out.println(); if (cmd.hasOption("km")) { this.strManagerUrl = cmd.getOptionValue("km"); } if (cmd.hasOption("type")) { if (0 == cmd.getOptionValue("type").compareTo("token")) cmdType = CmdType.TOKEN; else if (0 == cmd.getOptionValue("type").compareTo("crypto")) cmdType = CmdType.CRYPTO; } if (cmd.hasOption("action")) { if (0 == cmd.getOptionValue("action").compareTo("create")) cmdAction = CmdAction.TOKEN_CREATE; else if (0 == cmd.getOptionValue("action").compareTo("remove")) cmdAction = CmdAction.TOKEN_REMOVE; else if (0 == cmd.getOptionValue("action").compareTo("encrypt")) cmdAction = CmdAction.CRYPTO_ENCRYPT; else if (0 == cmd.getOptionValue("action").compareTo("decrypt")) cmdAction = CmdAction.CRYPTO_DECRYPT; } if (cmd.hasOption("filein")) { this.strFileInputPath = new File(cmd.getOptionValue("filein")).getAbsolutePath(); if (!new File(this.strFileInputPath).getParentFile().canExecute()) { this.errorExitOnSetup("Permission Denied to access " + this.strFileInputPath); } } if (cmd.hasOption("fileout")) { this.strFileOutputPath = new File(cmd.getOptionValue("fileout")).getAbsolutePath(); if (!new File(this.strFileOutputPath).getParentFile().canWrite()) { this.errorExitOnSetup("Permission Denied to write " + this.strFileOutputPath); } } if (cmd.hasOption("keyname")) strKeyName = cmd.getOptionValue("keyname"); if (cmd.hasOption("hexkey")) this.strHexKey = cmd.getOptionValue("hexkey"); if (cmdType == CmdType.NONE || cmdAction == CmdAction.NONE) { System.out.println("Error! Argument type/action must be specified"); System.out.println(strUsage); formatter.printHelp("Arguments Detail", options); System.exit(1); } if (cmdType == CmdType.TOKEN) { if (this.strManagerUrl.isEmpty()) { this.errorExitOnSetup("Please specified key manager url by argument -km"); } if (cmdAction == CmdAction.NONE) { this.errorExitOnSetup("Type <token> need arguments -action(create/remove)"); } else { if (cmdAction == CmdAction.TOKEN_CREATE) { if (this.strFileOutputPath.isEmpty()) { this.errorExitOnSetup("Token create: need arguments -fileout"); } else { System.out.println("token will be created to file " + this.strFileOutputPath); } } else { if (this.strFileInputPath.isEmpty()) { this.errorExitOnSetup("Token remove: need arguments -filein"); } else { System.out.println("token read from " + this.strFileInputPath); } } } } if (cmdType == CmdType.CRYPTO) { if (cmdAction != CmdAction.CRYPTO_ENCRYPT && cmdAction != CmdAction.CRYPTO_DECRYPT) { this.errorExitOnSetup("Type <crypto> only support Action encrypt/decrypt"); } else { if (this.strHexKey.isEmpty()) { if (this.strKeyName.isEmpty()) { this.errorExitOnSetup("Argument -keyname must be specified if you don't specify " + "the argument -hexkey"); } else { if (this.strManagerUrl.isEmpty()) { this.errorExitOnSetup("Please specified key manager url by argument -km"); } else { System.out.println( "Key Manager: " + this.strManagerUrl + ", Key Name: " + this.strKeyName); } } } else { System.out.println("Hex Key String: " + this.strHexKey); } if (this.strFileInputPath.isEmpty() || this.strFileOutputPath.isEmpty()) { this.errorExitOnSetup("crypto: Arguments -filein and -fileout must be specified"); } } } System.out.println(); } /** * @param args * @throws Exception */ public static void main(String[] args) { // -type token -action create -km web.bdp:8080 -fileout /tmp/bee/tt.jobtoken // -type token -action remove -km web.bdp:8080 -filein /tmp/bee/tt.jobtoken // -type crypto -action encrypt -km web.bdp:8443 -keyname test1 -filein // /tmp/bee/install.log -fileout /tmp/bee/install.log.intel_aes // -type crypto -action encrypt -hexkey // 4c7e62f001ae63fd7567f9c9bd5ca1e161396726bea70fe843fec0f771546da7 -filein // /tmp/bee/install.log -fileout /tmp/bee/install.log.intel_aes // -type crypto -action decrypt -km web.bdp -keyname test1 -filein // /tmp/bee/install.log.intel_aes -fileout /tmp/bee/install.log.decrypt // -type crypto -action decrypt -hexkey // 4c7e62f001ae63fd7567f9c9bd5ca1e161396726bea70fe843fec0f771546da7 -filein // /tmp/bee/install.log.intel_aes -fileout /tmp/bee/install.log.decrypt BeeCli beeCli = null; try { beeCli = new BeeCli(); beeCli.setupOptions(args); beeCli.requestHandler(); System.out.println(); System.out.println("Success."); if (beeCli.cmdType == CmdType.TOKEN) { if (beeCli.cmdAction == CmdAction.TOKEN_CREATE) { System.out.println("Token File is created: " + beeCli.strFileOutputPath); } else { System.out.println("Token File is removed from server and local: " + beeCli.strFileInputPath); } } System.out.println(); } catch (Exception e) { e.printStackTrace(); System.out.println(""); System.out.println(""); System.out.println( "Fail to process(" + e.getMessage() + "), please refer to above exception for detail!"); System.out.println(); } } }