You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2017/11/28 03:04:03 UTC

[02/15] directory-kerby git commit: Change the Maven groupId in HAS folder to org.apache.kerby.

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/hclient/HasClientLoginTool.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/hclient/HasClientLoginTool.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/hclient/HasClientLoginTool.java
new file mode 100644
index 0000000..f423a3b
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/hclient/HasClientLoginTool.java
@@ -0,0 +1,269 @@
+/**
+ *  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.kerby.has.tool.client.hclient;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.has.client.HasAuthAdminClient;
+import org.apache.kerby.has.client.HasClient;
+import org.apache.kerby.has.common.HasConfig;
+import org.apache.kerby.has.common.HasException;
+import org.apache.kerby.has.common.util.HasJaasLoginUtil;
+import org.apache.kerby.has.common.util.HasUtil;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.apache.kerby.util.OSUtil;
+
+import javax.security.auth.Subject;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class HasClientLoginTool {
+    private static List<String> principalList = new ArrayList<String>();
+    private static List<File>  keytabList = new ArrayList<File>();
+
+    private static final String KEYTAB_USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\k=login-test.cmd" : "Usage: sh bin/login-test.sh")
+        + " [add|run|delete] [conf_dir] [work_dir] [number]\n"
+        + "\n";
+
+    private static final String TGT_USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\k=login-test.cmd" : "Usage: sh bin/login-test.sh")
+        + " tgt [conf_dir]\n"
+        + "\n";
+
+    private static void printKeytabUsage(String error) {
+        System.err.println(error + "\n");
+        System.err.println(KEYTAB_USAGE);
+        System.exit(-1);
+    }
+
+    private static void printTgtUsage(String error) {
+        System.err.println(error + "\n");
+        System.err.println(TGT_USAGE);
+        System.exit(-1);
+    }
+
+    public static class Task implements Runnable {
+        private int index;
+
+        Task(int index) {
+            this.index = index;
+        }
+
+        @Override
+        public void run() {
+            Subject subject = null;
+            try {
+                subject = HasJaasLoginUtil.loginUsingKeytab(principalList.get(index),
+                    keytabList.get(index));
+            } catch (IOException e) {
+                System.err.println("Fail to login using keytab. " + e);
+            }
+            System.out.println("Login succeeded for user: "
+                + subject.getPrincipals().iterator().next());
+        }
+    }
+
+    public static void main(String[] args) {
+
+        String cmd = args[0];
+        File confDir;
+        File workDir;
+
+        if (cmd.equals("tgt")) {
+            if (args.length != 2) {
+                printTgtUsage("Need 2 args.");
+                return;
+            }
+
+            confDir = new File(args[1]);
+            if (!confDir.exists()) {
+                printTgtUsage("Need the valid conf dir.");
+                return;
+            }
+            File confFile = new File(confDir, "hadmin.conf");
+            HasConfig hasConfig;
+            try {
+                hasConfig = HasUtil.getHasConfig(confFile);
+            } catch (HasException e) {
+                System.err.println(e.getMessage());
+                return;
+            }
+            if (hasConfig == null) {
+                System.err.println("hadmin.conf not exist in " + confDir.getAbsolutePath());
+                return;
+            }
+            String host = hasConfig.getHttpsHost();
+            String port = hasConfig.getHttpsPort();
+
+            HasClient hasClient = new HasClient();
+            TgtTicket tgtTicket;
+            try {
+                tgtTicket = hasClient.requestTgt();
+            } catch (HasException e) {
+                System.err.println("Errors occurred when getting TGT. " + e.getMessage());
+                return;
+            }
+
+            System.out.println("Get the tgt ticket successfully!");
+            System.out.println("The client principal of tgt ticket: " + tgtTicket.getClientPrincipal());
+
+            Subject subject = null;
+            try {
+                subject = HasJaasLoginUtil.loginUserFromTgtTicket(
+                    "https://" + host + ":" + port + "/has/v1?auth_type=RAM");
+            } catch (IOException e) {
+                System.err.println("Errors occurred when login user with TGT. " + e.getMessage());
+                return;
+            }
+
+            System.out.println("Principal: " + subject.getPrincipals().iterator().next());
+        } else {
+            if (args.length != 4) {
+                printKeytabUsage("Need 4 args.");
+                return;
+            }
+
+            confDir = new File(args[1]);
+            workDir = new File(args[2]);
+
+            if (!confDir.exists()) {
+                printKeytabUsage("Need the valid conf dir.");
+                return;
+            }
+            if (!workDir.exists()) {
+                printKeytabUsage("Need the valid work dir.");
+                return;
+            }
+
+            int taskNum = Integer.parseInt(args[3]);
+
+            System.out.println("The task num is: " + taskNum);
+
+            if (taskNum <= 0) {
+                printKeytabUsage("The task num must be greater than zero");
+                System.exit(-1);
+            }
+
+            HasAdminClient hasAdminClient;
+            HasAuthAdminClient authHasAdminClient = null;
+            File confFile = new File(confDir, "hadmin.conf");
+            HasConfig hasConfig = null;
+            try {
+                hasConfig = HasUtil.getHasConfig(confFile);
+            } catch (HasException e) {
+                System.err.println(e.getMessage());
+                return;
+            }
+
+            if (hasConfig == null) {
+                System.err.println("hadmin.conf not exist in " + confDir.getAbsolutePath());
+                return;
+            }
+
+            if (hasConfig.getFilterAuthType().equals("kerberos")) {
+                authHasAdminClient = new HasAuthAdminClient(hasConfig);
+            }
+            if (authHasAdminClient != null) {
+                hasAdminClient = authHasAdminClient;
+            } else {
+                hasAdminClient = new HasAdminClient(hasConfig);
+            }
+            String realm = null;
+            try {
+                KdcConfig kdcConfig = KdcUtil.getKdcConfig(confDir);
+                realm = kdcConfig.getKdcRealm();
+            } catch (KrbException e) {
+                printKeytabUsage(e.getMessage());
+            }
+
+            if (cmd.equals("add")) {
+                for (int i = 0; i < taskNum; i++) {
+                    String principal = "test" + i + "@" + realm;
+                    try {
+                        hasAdminClient.addPrincipal(principal);
+                    } catch (HasException e) {
+                        System.err.println("Errors occurred when adding principal. "
+                            + e.getMessage());
+                        return;
+                    }
+                    File keytabFile = new File(workDir, i + ".keytab");
+                    try {
+                        hasAdminClient.exportKeytab(keytabFile, principal);
+                    } catch (HasException e) {
+                        System.err.println("Errors occurred when exporting the keytabs. "
+                            + e.getMessage());
+                        return;
+                    }
+                    System.out.println("Add principals and keytabs successfully.");
+                }
+            } else if (cmd.equals("run")) {
+                ExecutorService exec;
+                for (int i = 0; i < taskNum; i++) {
+                    String principal = "test" + i + "@" + realm;
+                    principalList.add(i, principal);
+                    File file = new File(workDir, i + ".keytab");
+                    keytabList.add(i, file);
+                }
+                System.out.println("Start the login test.");
+                Long startTime = System.currentTimeMillis();
+                exec = Executors.newFixedThreadPool(5);
+                for (int i = 0; i < taskNum; ++i) {
+                    exec.submit(new Task(i));
+                }
+                exec.shutdown();
+                try {
+                    exec.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+                } catch (InterruptedException e) {
+                    System.err.println(e.getMessage());
+                    return;
+                }
+                Long endTime = System.currentTimeMillis();
+                System.out.println("Finish the login test.");
+                System.out.println("Cost time: " + (endTime - startTime) + "ms");
+            } else if (cmd.equals("delete")) {
+                for (int i = 0; i < taskNum; i++) {
+                    String principal = "test" + i + "@" + realm;
+                    try {
+                        hasAdminClient.deletePrincipal(principal);
+                    } catch (HasException e) {
+                        System.err.println("Errors occurred when deleting the principal. "
+                            + e.getMessage());
+                        continue;
+                    }
+                    File file = new File(workDir, i + ".keytab");
+                    if (!file.delete()) {
+                        System.err.println("Failed to delete " + i + ".keytab.");
+                    }
+                }
+                System.out.println("Delete principals and keytabs successfully.");
+            } else {
+                printKeytabUsage("Need the cmd with add, run or delete.");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/HasInitTool.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/HasInitTool.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/HasInitTool.java
new file mode 100644
index 0000000..1171d02
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/HasInitTool.java
@@ -0,0 +1,132 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.has.common.HasConfig;
+import org.apache.kerby.has.common.HasException;
+import org.apache.kerby.has.common.util.HasUtil;
+import org.apache.kerby.has.tool.client.kdcinit.cmd.*;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.util.OSUtil;
+
+import java.io.File;
+import java.util.Scanner;
+
+public class HasInitTool {
+    private static final String PROMPT = HasInitTool.class.getSimpleName();
+    private static final String USAGE = (OSUtil.isWindows()
+            ? "Usage: bin\\hadmin.cmd" : "Usage: sh bin/kdcinit.sh")
+            + " <conf-file>\n"
+            + "\tExample:\n"
+            + "\t\t"
+            + (OSUtil.isWindows()
+            ? "bin\\kdcinit.cmd" : "sh bin/kdcinit.sh")
+            + " conf\n";
+
+    private static final String LEGAL_COMMANDS = "Available commands are: "
+            + "\n"
+            + "get_krb5conf, getkrb5\n"
+            + "                         Get krb5.conf\n"
+            + "get_hasConf, gethas\n"
+            + "                         Get has-client.conf\n"
+            + "set_plugin, setplugin\n"
+            + "                         Set plugin\n"
+            + "config_kdcBackend, confbackend\n"
+            + "                         Config kdc backend\n"
+            + "config_kdc, confkdc\n"
+            + "                         Config kdc\n"
+            + "start_kdc, start\n"
+            + "                         Start kdc\n"
+            + "init_kdc, init\n"
+            + "                         Init kdc\n";
+
+    public static void main(String[] args) {
+        if (args.length < 1) {
+            System.err.println(USAGE);
+            System.exit(1);
+        }
+        String confDirPath = args[0];
+        File confFile = new File(confDirPath, "hadmin.conf");
+        HasConfig hasConfig;
+        try {
+            hasConfig = HasUtil.getHasConfig(confFile);
+        } catch (HasException e) {
+            System.err.println(e.getMessage());
+            return;
+        }
+
+        System.out.println(LEGAL_COMMANDS);
+        System.out.println("enter \"<cmd> [?][-help]\" to get cmd help.");
+        Scanner scanner = new Scanner(System.in, "UTF-8");
+        System.out.print(PROMPT + ": ");
+        String input = scanner.nextLine();
+
+        HasAdminClient hadmin = new HasAdminClient(hasConfig, new File(confDirPath));
+        while (!(input.equals("quit") || input.equals("exit") || input.equals("q"))) {
+            try {
+                execute(hadmin, input);
+            } catch (KrbException e) {
+                System.err.println(e.getMessage());
+            }
+            System.out.print(PROMPT + ": ");
+            input = scanner.nextLine();
+        }
+    }
+
+    private static void execute(HasAdminClient hadmin, String input) throws KrbException {
+        input = input.trim();
+        if (input.startsWith("cmd")) {
+            System.out.println(LEGAL_COMMANDS);
+            return;
+        }
+        String[] items = input.split("\\s+");
+        String cmd = items[0];
+
+        KdcInitCmd executor;
+        if (cmd.equals("get_krb5conf")
+                || cmd.equals("getkrb5")) {
+            executor = new HasGetKrb5confCmd(hadmin);
+        } else if (cmd.equals("get_hasConf")
+                || cmd.equals("gethas")) {
+            executor = new HasGetHasconfCmd(hadmin);
+        } else if (cmd.equals("set_plugin")
+                || cmd.equals("setplugin")) {
+            executor = new HasSetPluginCmd(hadmin);
+        } else if (cmd.equals("config_kdcBackend")
+                || cmd.equals("confbackend")) {
+            executor = new HasConfKdcBackendCmd(hadmin);
+        } else if (cmd.equals("config_kdc")
+                || cmd.equals("confkdc")) {
+            executor = new HasConfKdcCmd(hadmin);
+        } else if (cmd.equals("start_kdc")
+                || cmd.equals("start")) {
+            executor = new HasStartKdcCmd(hadmin);
+        } else if (cmd.equals("init_kdc")
+                || cmd.equals("init")) {
+            executor = new HasInitKdcCmd(hadmin);
+        } else {
+            System.out.println(LEGAL_COMMANDS);
+            return;
+        }
+        executor.execute(items);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcBackendCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcBackendCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcBackendCmd.java
new file mode 100644
index 0000000..7423cbf
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcBackendCmd.java
@@ -0,0 +1,66 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Remote config kdc cmd
+ */
+public class HasConfKdcBackendCmd extends KdcInitCmd {
+
+    public static final String USAGE = "Usage: config_kdcBackend <backendType> [dir] [url] [user]"
+        + " [password]\n"
+        + "\tSupported backendType : json,mysql\n"
+        + "\tExample:\n"
+        + "\t\tconfig_kdcBackend json /tmp/has/jsonbackend \n"
+        + "\t\tconfig_kdcBackend mysql jdbc:mysql://127.0.0.1:3306/mysqlbackend root passwd\n";
+
+    public HasConfKdcBackendCmd(HasAdminClient hadmin) {
+        super(hadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length >= 2) {
+            if (items[1].startsWith("?") || items[1].startsWith("-help")) {
+                System.out.println(USAGE);
+                return;
+            }
+        }
+        if (items.length < 3) {
+            System.err.println(USAGE);
+            return;
+        }
+
+        HasAdminClient hasAdminClient = getHadmin();
+        if (items.length >= 3 && items[1].equals("json")) {
+            hasAdminClient.configKdcBackend(items[1], items[2],
+                    null, null, null);
+        } else if (items.length >= 5 && items[1].equals("mysql")) {
+            hasAdminClient.configKdcBackend(items[1], null,
+                    items[2], items[3], items[4]);
+        } else {
+            System.err.println(USAGE);
+            return;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcCmd.java
new file mode 100644
index 0000000..ce73dce
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasConfKdcCmd.java
@@ -0,0 +1,54 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Remote config kdc cmd
+ */
+public class HasConfKdcCmd extends KdcInitCmd {
+
+    public static final String USAGE = "Usage: config_kdc <host> <port> <realm>\n"
+        + "\tExample:\n"
+        + "\t\tconfig_kdc localhost 88 HADOOP.COM\n";
+
+    public HasConfKdcCmd(HasAdminClient hadmin) {
+        super(hadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length >= 2) {
+            if (items[1].startsWith("?") || items[1].startsWith("-help")) {
+                System.out.println(USAGE);
+                return;
+            }
+        }
+        if (items.length < 4) {
+            System.err.println(USAGE);
+            return;
+        }
+
+        HasAdminClient hasAdminClient = getHadmin();
+        hasAdminClient.configKdc(items[2], items[3], items[1]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetHasconfCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetHasconfCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetHasconfCmd.java
new file mode 100644
index 0000000..efa92f6
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetHasconfCmd.java
@@ -0,0 +1,77 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+/**
+ * Remote get has-client.conf cmd
+ */
+public class HasGetHasconfCmd extends KdcInitCmd {
+
+    public static final String USAGE = "Usage: get_hasConf [-p] [path]\n"
+        + "\tExample:\n"
+        + "\t\tget_hasConf\n";
+
+    public HasGetHasconfCmd(HasAdminClient hadmin) {
+        super(hadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length >= 2) {
+            if (items[1].startsWith("?") || items[1].startsWith("-help")) {
+                System.out.println(USAGE);
+                return;
+            }
+        }
+        File path = getHadmin().getConfDir();
+        if (items.length >= 3 && items[1].startsWith("-p")) {
+            path = new File(items[2]);
+            if (!path.exists()) {
+                if (!path.mkdirs()) {
+                    System.err.println("Cannot create file : " + items[2]);
+                    return;
+                }
+            }
+        }
+        File hasConf = new File(path, "has-client.conf");
+
+        HasAdminClient hasAdminClient = getHadmin();
+        String content = hasAdminClient.getHasconf();
+        if (content == null) {
+            System.err.println("Failed to get has.conf.");
+            return;
+        }
+        try {
+            PrintStream ps = new PrintStream(new FileOutputStream(hasConf));
+            ps.println(content);
+            System.out.println("has-client.conf has saved in : " + hasConf.getAbsolutePath());
+        } catch (FileNotFoundException e) {
+            System.err.println(e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetKrb5confCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetKrb5confCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetKrb5confCmd.java
new file mode 100644
index 0000000..bbe93cf
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasGetKrb5confCmd.java
@@ -0,0 +1,77 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+/**
+ * Remote get krb5.conf cmd
+ */
+public class HasGetKrb5confCmd extends KdcInitCmd {
+
+    public static final String USAGE = "Usage: get_krb5conf [-p] [path]\n"
+        + "\tExample:\n"
+        + "\t\tget_krb5conf -p /tmp/has\n";
+
+    public HasGetKrb5confCmd(HasAdminClient hadmin) {
+        super(hadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length >= 2) {
+            if (items[1].startsWith("?") || items[1].startsWith("-help")) {
+                System.out.println(USAGE);
+                return;
+            }
+        }
+        File path = getHadmin().getConfDir();
+        if (items.length >= 3 && items[1].startsWith("-p")) {
+            path = new File(items[2]);
+            if (!path.exists()) {
+                if (!path.mkdirs()) {
+                    System.err.println("Cannot create file : " + items[2]);
+                    return;
+                }
+            }
+        }
+        File krb5Conf = new File(path, "krb5.conf");
+
+        HasAdminClient hasAdminClient = getHadmin();
+        String content = hasAdminClient.getKrb5conf();
+        if (content == null) {
+            System.err.println("Failed to get krb5.conf.");
+            return;
+        }
+        try {
+            PrintStream ps = new PrintStream(new FileOutputStream(krb5Conf));
+            ps.println(content);
+            System.out.println("krb5.conf has saved in : " + krb5Conf.getAbsolutePath());
+        } catch (FileNotFoundException e) {
+            System.err.println(e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasInitKdcCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasInitKdcCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasInitKdcCmd.java
new file mode 100644
index 0000000..895b10a
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasInitKdcCmd.java
@@ -0,0 +1,94 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Remote init kdc cmd
+ */
+public class HasInitKdcCmd extends KdcInitCmd {
+
+    public static final String USAGE = "Usage: init_kdc [-p] [path]\n"
+        + "\tExample:\n"
+        + "\t\tinit_kdc\n";
+
+    public HasInitKdcCmd(HasAdminClient hadmin) {
+        super(hadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length >= 2) {
+            if (items[1].startsWith("?") || items[1].startsWith("-help")) {
+                System.out.println(USAGE);
+                return;
+            }
+        }
+        File path = getHadmin().getConfDir();
+        if (items.length >= 3 && items[1].startsWith("-p")) {
+            path = new File(items[2]);
+            if (!path.exists()) {
+                if (!path.mkdirs()) {
+                    System.err.println("Cannot create file : " + items[2]);
+                    return;
+                }
+            }
+        }
+        File hadminKeytab = new File(path, "admin.keytab");
+
+        HasAdminClient hasAdminClient = getHadmin();
+        InputStream content = hasAdminClient.initKdc();
+
+        if (content == null) {
+            System.err.println("Failed to init kdc.");
+            return;
+        }
+
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(hadminKeytab);
+        } catch (FileNotFoundException e) {
+            System.err.println("the admin keytab file not found. " + e.getMessage());
+        }
+        byte[] buffer = new byte[4 * 1024];
+        int read;
+        try {
+            while ((read = content.read(buffer)) > 0) {
+                fos.write(buffer, 0, read);
+            }
+            fos.close();
+            content.close();
+        } catch (IOException e) {
+            System.err.println("Errors occurred when getting the admin.keytab. " + e.getMessage());
+        }
+
+        System.out.println("admin.keytab has saved in : " + hadminKeytab.getAbsolutePath()
+            + ",\nplease safely save it to use hadmin.");
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasSetPluginCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasSetPluginCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasSetPluginCmd.java
new file mode 100644
index 0000000..a06230b
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasSetPluginCmd.java
@@ -0,0 +1,53 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Remote set plugin cmd
+ */
+public class HasSetPluginCmd extends KdcInitCmd {
+
+    public static final String USAGE = "Usage: set_plugin <plugin>\n"
+        + "\tExample:\n"
+        + "\t\tset_plugin RAM\n";
+
+    public HasSetPluginCmd(HasAdminClient hadmin) {
+        super(hadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length >= 2) {
+            if (items[1].startsWith("?") || items[1].startsWith("-help")) {
+                System.out.println(USAGE);
+                return;
+            }
+        } else {
+            System.err.println(USAGE);
+            return;
+        }
+
+        HasAdminClient hasAdminClient = getHadmin();
+        hasAdminClient.setPlugin(items[1]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasStartKdcCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasStartKdcCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasStartKdcCmd.java
new file mode 100644
index 0000000..466cee7
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/HasStartKdcCmd.java
@@ -0,0 +1,49 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Remote start kdc cmd
+ */
+public class HasStartKdcCmd extends KdcInitCmd {
+
+    public static final String USAGE = "Usage: start_kdc\n"
+        + "\tExample:\n"
+        + "\t\tstart\n";
+
+    public HasStartKdcCmd(HasAdminClient hadmin) {
+        super(hadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length >= 2) {
+            if (items[1].startsWith("?") || items[1].startsWith("-help")) {
+                System.out.println(USAGE);
+                return;
+            }
+        }
+        HasAdminClient hasAdminClient = getHadmin();
+        hasAdminClient.startKdc();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/KdcInitCmd.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/KdcInitCmd.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/KdcInitCmd.java
new file mode 100644
index 0000000..310cfa3
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kdcinit/cmd/KdcInitCmd.java
@@ -0,0 +1,42 @@
+/**
+ *  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.kerby.has.tool.client.kdcinit.cmd;
+
+import org.apache.kerby.has.client.HasAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+public abstract class KdcInitCmd {
+
+    private HasAdminClient hadmin;
+
+    public KdcInitCmd(HasAdminClient hadmin) {
+        this.hadmin = hadmin;
+    }
+
+    protected HasAdminClient getHadmin() {
+        return hadmin;
+    }
+
+    /**
+     * Execute the kdc init cmd.
+     * @param input Input cmd to execute
+     */
+    public abstract void execute(String[] input) throws KrbException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitOption.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitOption.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitOption.java
new file mode 100644
index 0000000..f96fa7c
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitOption.java
@@ -0,0 +1,88 @@
+/**
+ *  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.kerby.has.tool.client.kinit;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+import org.apache.kerby.kerberos.kerb.client.KrbOptionGroup;
+
+public enum KinitOption implements KOption {
+    NONE(null),
+
+    CLIENT_PRINCIPAL(new KOptionInfo("client-principal", "Client principal",
+        KrbOptionGroup.KRB, KOptionType.STR)),
+    LIFE_TIME(new KOptionInfo("-l", "lifetime",
+        KrbOptionGroup.KRB, KOptionType.DURATION)),
+    START_TIME(new KOptionInfo("-s", "start time",
+        KrbOptionGroup.KRB, KOptionType.DURATION)),
+    RENEWABLE_LIFE(new KOptionInfo("-r", "renewable lifetime",
+        KrbOptionGroup.KRB, KOptionType.DURATION)),
+    FORWARDABLE(new KOptionInfo("-f", "forwardable",
+        KrbOptionGroup.KDC_FLAGS)),
+    NOT_FORWARDABLE(new KOptionInfo("-F", "not forwardable",
+        KrbOptionGroup.KDC_FLAGS)),
+    PROXIABLE(new KOptionInfo("-p", "proxiable",
+        KrbOptionGroup.KDC_FLAGS)),
+    NOT_PROXIABLE(new KOptionInfo("-P", "not proxiable",
+        KrbOptionGroup.KDC_FLAGS)),
+    RENEW(new KOptionInfo("-R", "renew",
+        KrbOptionGroup.KDC_FLAGS)),
+    USE_PASSWD(new KOptionInfo("using-password", "using password",
+        KrbOptionGroup.KRB)),
+    USER_PASSWD(new KOptionInfo("user-passwd", "User plain password",
+        KrbOptionGroup.KRB)),
+    USE_KEYTAB(new KOptionInfo("-k", "use keytab",
+        KrbOptionGroup.KRB)),
+    USE_DFT_KEYTAB(new KOptionInfo("-i", "use default client keytab (with -k)",
+        KrbOptionGroup.KRB)),
+    KEYTAB_FILE(new KOptionInfo("-t", "filename of keytab to use",
+        KrbOptionGroup.KRB, KOptionType.FILE)),
+    KRB5_CACHE(new KOptionInfo("-c", "Kerberos 5 cache name",
+        KrbOptionGroup.KRB, KOptionType.STR)),
+    SERVICE(new KOptionInfo("-S", "service",
+        KrbOptionGroup.KRB, KOptionType.STR)),
+
+    CONF_DIR(new KOptionInfo("-conf", "conf dir", KrbOptionGroup.KRB, KOptionType.DIR));
+
+    private final KOptionInfo optionInfo;
+
+    KinitOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static KinitOption fromName(String name) {
+        if (name != null) {
+            for (KinitOption ko : values()) {
+                if (ko.optionInfo != null
+                        && ko.optionInfo.getName().equals(name)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitTool.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitTool.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitTool.java
new file mode 100644
index 0000000..f95fe91
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/kinit/KinitTool.java
@@ -0,0 +1,384 @@
+/**
+ *  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.kerby.has.tool.client.kinit;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.client.KrbKdcOption;
+import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.KrbOptionGroup;
+import org.apache.kerby.kerberos.kerb.client.PkinitOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
+import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.apache.kerby.util.OSUtil;
+import org.apache.kerby.util.SysUtil;
+
+import java.io.Console;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * kinit like tool
+ *
+ * Ref. MIT kinit command tool usage.
+ */
+public class KinitTool {
+
+    private static final String USAGE = (OSUtil.isWindows()
+            ? "Usage: bin\\kinit.cmd" : "Usage: sh bin/kinit.sh")
+            + " <-conf conf_dir> [-V] [-l lifetime] [-s start_time]\n"
+            + "\t\t[-r renewable_life] [-f | -F] [-p | -P] -n [-a | -A] [-C] [-E]\n"
+            + "\t\t[-v] [-R] [-k [-i|-t keytab_file]] [-c cachename]\n"
+            + "\t\t[-S service_name] [-T ticket_armor_cache]\n"
+            + "\t\t[-X <attribute>[=<value>]] <principal>\n\n"
+            + "\tDESCRIPTION:\n"
+            + "\t\tkinit obtains and caches an initial ticket-granting ticket for principal.\n\n"
+            + "\tOPTIONS:\n"
+            + "\t\t-V verbose\n"
+            + "\t\t-l lifetime\n"
+            + "\t\t-s start time\n"
+            + "\t\t-r renewable lifetime\n"
+            + "\t\t-f forwardable\n"
+            + "\t\t-F not forwardable\n"
+            + "\t\t-p proxiable\n"
+            + "\t\t-P not proxiable\n"
+            + "\t\t-n anonymous\n"
+            + "\t\t-a include addresses\n"
+            + "\t\t-A do not include addresses\n"
+            + "\t\t-v validate\n"
+            + "\t\t-R renew\n"
+            + "\t\t-C canonicalize\n"
+            + "\t\t-E client is enterprise principal name\n"
+            + "\t\t-k use keytab\n"
+            + "\t\t-i use default client keytab (with -k)\n"
+            + "\t\t-t filename of keytab to use\n"
+            + "\t\t-c Kerberos 5 cache name\n"
+            + "\t\t-S service\n"
+            + "\t\t-T armor credential cache\n"
+            + "\t\t-X <attribute>[=<value>]\n"
+            + "\n";
+
+    private static void printUsage(String error) {
+        System.err.println(error + "\n");
+        System.err.println(USAGE);
+        System.exit(-1);
+    }
+
+    private static final String KVNO_USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\kinit.cmd" : "Usage: sh bin/kinit.sh")
+        + " <-conf conf_dir> <-c cachename> <-S service_name>\n\n"
+        + "\tDESCRIPTION:\n"
+        + "\t\tkinit obtains a service ticket for the specified principal and prints out the key version number.\n"
+        + "\n";
+
+    private static void printKvnoUsage(String error) {
+        System.err.println(error + "\n");
+        System.err.println(KVNO_USAGE);
+        System.exit(-1);
+    }
+
+    /**
+     * Get password for the input principal from console
+     */
+    private static String getPassword(String principal) {
+        Console console = System.console();
+        if (console == null) {
+            System.out.println("Couldn't get Console instance, "
+                    + "maybe you're running this from within an IDE. "
+                    + "Use scanner to read password.");
+            System.out.println("Password for " + principal + ":");
+            try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
+                return scanner.nextLine().trim();
+            }
+        }
+        console.printf("Password for " + principal + ":");
+        char[] passwordChars = console.readPassword();
+        String password = new String(passwordChars).trim();
+        Arrays.fill(passwordChars, ' ');
+
+        return password;
+    }
+
+    private static void requestTicket(String principal, KOptions ktOptions) {
+        ktOptions.add(KinitOption.CLIENT_PRINCIPAL, principal);
+
+        File confDir = null;
+        if (ktOptions.contains(KinitOption.CONF_DIR)) {
+            confDir = ktOptions.getDirOption(KinitOption.CONF_DIR);
+        }
+
+        KrbClient krbClient = null;
+        try {
+            krbClient = getClient(confDir);
+        } catch (KrbException e) {
+            System.err.println("Create krbClient failed: " + e.getMessage());
+            System.exit(1);
+        }
+
+        if (ktOptions.contains(KinitOption.RENEW)) {
+            if (ktOptions.contains(KinitOption.KRB5_CACHE)) {
+                String ccName = ktOptions.getStringOption(KinitOption.KRB5_CACHE);
+                File ccFile = new File(ccName);
+
+                SgtTicket sgtTicket = null;
+                try {
+                    sgtTicket = krbClient.requestSgt(ccFile, null);
+                } catch (KrbException e) {
+                    System.err.println("kinit: " + e.getKrbErrorCode().getMessage());
+                }
+
+                try {
+                    krbClient.renewTicket(sgtTicket, ccFile);
+                } catch (KrbException e) {
+                    System.err.println("kinit: " + e.getKrbErrorCode().getMessage());
+                }
+
+                System.out.println("Successfully renewed.");
+            }
+            return;
+        }
+
+        if (ktOptions.contains(KinitOption.SERVICE) && ktOptions.contains(KinitOption.KRB5_CACHE)) {
+            String ccName = ktOptions.getStringOption(KinitOption.KRB5_CACHE);
+            File ccFile = new File(ccName);
+            if (ccFile.exists()) {
+                System.out.println("Use credential cache to request a service ticket.");
+                String servicePrincipal = ktOptions.getStringOption(KinitOption.SERVICE);
+                SgtTicket sgtTicket = null;
+                try {
+                    sgtTicket = krbClient.requestSgt(ccFile, servicePrincipal);
+                } catch (KrbException e) {
+                    System.err.println("Kinit: get service ticket failed: " + e.getMessage());
+                    System.exit(1);
+                }
+
+                try {
+                    krbClient.storeTicket(sgtTicket, ccFile);
+                } catch (KrbException e) {
+                    System.err.println("Kinit: store ticket failed: " + e.getMessage());
+                    System.exit(1);
+                }
+
+                System.out.println(sgtTicket.getEncKdcRepPart().getSname().getName() + ": knvo = "
+                    + sgtTicket.getTicket().getEncryptedEncPart().getKvno());
+                return;
+            }
+        }
+
+        if (!ktOptions.contains(KinitOption.USE_KEYTAB)) {
+            //If not request tickets by keytab than by password.
+            ktOptions.add(KinitOption.USE_PASSWD);
+            String password = getPassword(principal);
+            ktOptions.add(KinitOption.USER_PASSWD, password);
+        }
+
+        TgtTicket tgt = null;
+        try {
+            tgt = krbClient.requestTgt(convertOptions(ktOptions));
+        } catch (KrbException e) {
+            System.err.println("Authentication failed: " + e.getMessage());
+            System.exit(1);
+        }
+
+        File ccacheFile;
+        if (ktOptions.contains(KinitOption.KRB5_CACHE)) {
+            String ccacheName = ktOptions.getStringOption(KinitOption.KRB5_CACHE);
+            ccacheFile = new File(ccacheName);
+        } else {
+            String ccacheName = getCcacheName(krbClient);
+            ccacheFile = new File(ccacheName);
+        }
+
+        try {
+            krbClient.storeTicket(tgt, ccacheFile);
+        } catch (KrbException e) {
+            System.err.println("Store ticket failed: " + e.getMessage());
+            System.exit(1);
+        }
+
+        System.out.println("Successfully requested and stored ticket in "
+            + ccacheFile.getAbsolutePath());
+
+        if (ktOptions.contains(KinitOption.SERVICE)) {
+            System.out.println("Use tgt to request a service ticket.");
+            String servicePrincipal = ktOptions.getStringOption(KinitOption.SERVICE);
+            SgtTicket sgtTicket;
+            try {
+                sgtTicket = krbClient.requestSgt(tgt, servicePrincipal);
+            } catch (KrbException e) {
+                System.err.println("kinit: " + e.getKrbErrorCode().getMessage());
+                return;
+            }
+
+            System.out.println(sgtTicket.getEncKdcRepPart().getSname().getName() + ": knvo = "
+                + sgtTicket.getTicket().getEncryptedEncPart().getKvno());
+        }
+    }
+
+    /**
+     * Init the client.
+     */
+    private static KrbClient getClient(File confDir) throws KrbException {
+        KrbClient krbClient;
+
+        if (confDir != null) {
+            krbClient = new KrbClient(confDir);
+        } else {
+            krbClient = new KrbClient();
+        }
+
+        krbClient.init();
+        return krbClient;
+    }
+
+    /**
+     * Get credential cache file name if not specified.
+     */
+    private static String getCcacheName(KrbClient krbClient) {
+        final String ccacheNameEnv = System.getenv("KRB5CCNAME");
+        final String ccacheNameConf = krbClient.getSetting().getKrbConfig().getString("default_ccache_name");
+        String ccacheName;
+        if (ccacheNameEnv != null) {
+            ccacheName = ccacheNameEnv;
+        } else if (ccacheNameConf != null) {
+            ccacheName = ccacheNameConf;
+        } else {
+            StringBuilder uid = new StringBuilder();
+            try {
+                //Get UID through "id -u" command
+                String command = "id -u";
+                Process child = Runtime.getRuntime().exec(command);
+                InputStream in = child.getInputStream();
+                int c;
+                while ((c = in.read()) != -1) {
+                    uid.append((char) c);
+                }
+                in.close();
+            } catch (IOException e) {
+                System.err.println("Failed to get UID.");
+                System.exit(1);
+            }
+            ccacheName = "krb5cc_" + uid.toString().trim();
+            ccacheName = SysUtil.getTempDir().toString() + "/" + ccacheName;
+        }
+
+        return ccacheName;
+    }
+
+    public static void main(String[] args) {
+        KOptions ktOptions = new KOptions();
+        KinitOption kto;
+        String principal = null;
+
+        int i = 0;
+        String opt, param, error;
+        while (i < args.length) {
+            error = null;
+
+            opt = args[i++];
+            if (opt.startsWith("-")) {
+                kto = KinitOption.fromName(opt);
+                if (kto == KinitOption.NONE) {
+                    error = "Invalid option:" + opt;
+                    System.err.println(error);
+                    break;
+                }
+            } else {
+                principal = opt;
+                kto = KinitOption.NONE;
+            }
+
+            if (kto != KinitOption.NONE && kto.getOptionInfo().getType() != KOptionType.NOV) {
+                // require a parameter
+                param = null;
+                if (i < args.length) {
+                    param = args[i++];
+                }
+                if (param != null) {
+                    KOptions.parseSetValue(kto.getOptionInfo(), param);
+                } else {
+                    error = "Option " + opt + " require a parameter";
+                }
+            }
+
+            if (error != null) {
+                printUsage(error);
+            }
+            if (kto != KinitOption.NONE) {
+                ktOptions.add(kto);
+            }
+        }
+
+        if (!ktOptions.contains(KinitOption.CONF_DIR)) {
+            printUsage("No conf dir given.");
+        }
+
+        if (principal == null) {
+            if (!ktOptions.contains(KinitOption.SERVICE) && !ktOptions.contains(KinitOption.KRB5_CACHE)) {
+                printUsage("No principal is specified");
+            } else if (ktOptions.contains(KinitOption.SERVICE) && !ktOptions.contains(KinitOption.KRB5_CACHE)) {
+                printKvnoUsage("No credential cache file given.");
+            }
+        }
+
+        requestTicket(principal, ktOptions);
+        System.exit(0);
+    }
+
+    /**
+     * Convert kinit tool options to KOptions.
+     * @param toolOptions
+     * @return KOptions
+     */
+    static KOptions convertOptions(KOptions toolOptions) {
+        KOptions results = new KOptions();
+
+        for (KOption toolOpt : toolOptions.getOptions()) {
+            KOptionInfo kOptionInfo = toolOpt.getOptionInfo();
+            KOptionGroup group = kOptionInfo.getGroup();
+            KOption kOpt = null;
+
+            if (group == KrbOptionGroup.KRB) {
+                kOpt = KrbOption.fromOptionName(kOptionInfo.getName());
+            } else if (group == KrbOptionGroup.PKINIT) {
+                kOpt = PkinitOption.fromOptionName(kOptionInfo.getName());
+            } else if (group == KrbOptionGroup.TOKEN) {
+                kOpt = TokenOption.fromOptionName(kOptionInfo.getName());
+            } else if (group == KrbOptionGroup.KDC_FLAGS) {
+                kOpt = KrbKdcOption.fromOptionName(kOptionInfo.getName());
+            }
+            if (kOpt != null && kOpt.getOptionInfo() != KrbOption.NONE.getOptionInfo()) {
+                kOpt.getOptionInfo().setValue(toolOpt.getOptionInfo().getValue());
+                results.add(kOpt);
+            }
+        }
+
+        return results;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistOption.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistOption.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistOption.java
new file mode 100644
index 0000000..b43ddea
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistOption.java
@@ -0,0 +1,66 @@
+/**
+ *  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.kerby.has.tool.client.klist;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+public enum KlistOption implements KOption {
+    NONE(null),
+    CREDENTIALS_CACHE(new KOptionInfo("-c", "specifies path of credentials cache",
+        KOptionType.STR)),
+    KEYTAB(new KOptionInfo("-k", "specifies keytab")),
+    DEFAULT_CLIENT_KEYTAB(new KOptionInfo("-i", "uses default client keytab if no name given")),
+    LIST_CREDENTIAL_CACHES(new KOptionInfo("-l", "list credential caches in collection")),
+    ALL_CREDENTIAL_CACHES(new KOptionInfo("-A", "shows content of all credential caches")),
+    ENCRYPTION_TYPE(new KOptionInfo("-e", "shows encryption type")),
+    KERBEROS_VERSION(new KOptionInfo("-V", "shows Kerberos version")),
+    AUTHORIZATION_DATA_TYPE(new KOptionInfo("-d", "shows the submitted authorization data type")),
+    CREDENTIALS_FLAGS(new KOptionInfo("-f", "show credential flags")),
+    EXIT_TGT_EXISTENCE(new KOptionInfo("-s", "sets exit status based on valid tgt existence")),
+    DISPL_ADDRESS_LIST(new KOptionInfo("-a", "displays the address list")),
+    NO_REVERSE_RESOLVE(new KOptionInfo("-n", "do not reverse resolve")),
+    SHOW_KTAB_ENTRY_TS(new KOptionInfo("-t", "shows keytab entry timestamps")),
+    SHOW_KTAB_ENTRY_KEY(new KOptionInfo("-K", "show keytab entry keys"));
+
+    private final KOptionInfo optionInfo;
+
+    KlistOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static KlistOption fromName(String name) {
+        if (name != null) {
+            for (KlistOption ko : values()) {
+                if (ko.optionInfo != null
+                        && ko.optionInfo.getName().equals(name)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistTool.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistTool.java b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistTool.java
new file mode 100644
index 0000000..64f3315
--- /dev/null
+++ b/has/has-tool/has-client-tool/src/main/java/org/apache/kerby/has/tool/client/klist/KlistTool.java
@@ -0,0 +1,293 @@
+/**
+ *  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.kerby.has.tool.client.klist;
+
+import org.apache.kerby.KOptionType;
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.ccache.Credential;
+import org.apache.kerby.kerberos.kerb.ccache.CredentialCache;
+import org.apache.kerby.kerberos.kerb.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.keytab.KeytabEntry;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.apache.kerby.util.HexUtil;
+import org.apache.kerby.util.OSUtil;
+import org.apache.kerby.util.SysUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * klist like tool
+ *
+ * Ref. MIT klist command tool usage.
+ */
+public class KlistTool {
+    private static final Logger LOG = LoggerFactory.getLogger(KlistTool.class);
+
+    private static final String USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\klist.cmd" : "Usage: sh bin/klist.sh")
+            + " [-e] [-V] [[-c] [-l] [-A] [-d] [-f] [-s] "
+            + "[-a [-n]]] [-k [-t] [-K]] [name]\n"
+            + "\t-c specifies credentials cache\n"
+            + "\t-k specifies keytab\n"
+            + "\t   (Default is credentials cache)\n"
+            + "\t-i uses default client keytab if no name given\n"
+            + "\t-l lists credential caches in collection\n"
+            + "\t-A shows content of all credential caches\n"
+            + "\t-e shows the encryption type\n"
+            + "\t-V shows the Kerberos version and exits\n"
+            + "\toptions for credential caches:\n"
+            + "\t\t-d shows the submitted authorization data types\n"
+            + "\t\t-f shows credentials flags\n"
+            + "\t\t-s sets exit status based on valid tgt existence\n"
+            + "\t\t-a displays the address list\n"
+            + "\t\t\t-n do not reverse-resolve\n"
+            + "\toptions for keytabs:\n"
+            + "\t\t-t shows keytab entry timestamps\n"
+            + "\t\t-K shows keytab entry keys\n";
+
+    // option "-k" hava a optional parameter, "/etc/krb5.keytab" if not specified
+    private static String keytabFilePath = null;
+
+    private static void printUsage(String error) {
+        System.err.println(error + "\n");
+        System.err.println(USAGE);
+        System.exit(-1);
+    }
+
+    private static int printCredentialCacheInfo(KOptions klOptions) {
+        CredentialCache cc = new CredentialCache();
+        List<Credential> credentials;
+        InputStream cis = null;
+        String fileName;
+
+        if (!klOptions.contains(KlistOption.CREDENTIALS_CACHE)) {
+            fileName = getCcacheName();
+        } else {
+            fileName = klOptions.getStringOption(KlistOption.CREDENTIALS_CACHE);
+        }
+        try {
+            cis = Files.newInputStream(Paths.get(fileName));
+            cc.load(cis);
+        } catch (IOException e) {
+            LOG.error("Failed to open CredentialCache from file: " + fileName + ". " + e.toString());
+        } finally {
+            try {
+                if (cis != null) {
+                    cis.close();
+                }
+            } catch (IOException e) {
+                LOG.warn("Fail to close input stream. " + e);
+            }
+        }
+
+        if (cc != null) {
+            credentials = cc.getCredentials();
+
+            System.out.println("Ticket cache: " + fileName);
+            System.out.println("Default principal: " + cc.getPrimaryPrincipal().getName());
+
+            if (credentials.isEmpty()) {
+                System.out.println("No credential has been cached.");
+            } else {
+                DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+                System.out.println("Valid starting\t\tExpires\t\t\tService principal");
+
+                for (Credential crd : credentials) {
+                    System.out.println(df.format(crd.getStartTime().getTime()) + "\t"
+                        + df.format(crd.getEndTime().getTime()) + "\t"
+                        + crd.getServerName() + "\n"
+                        + "\t" + "renew until" + "\t" + df.format(crd.getRenewTill().getTime()));
+                }
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Get credential cache file name if not specified.
+     */
+    private static String getCcacheName() {
+        String ccacheName;
+        String ccacheNameEnv = System.getenv("KRB5CCNAME");
+        String ccacheNameConf = null;
+        File confDir = new File("/etc");
+        try {
+            KrbClient krbClient = new KrbClient(confDir);
+            ccacheNameConf = krbClient.getSetting().getKrbConfig().getString("default_ccache_name");
+        } catch (KrbException e) {
+            System.err.println("Create krbClient failed: " + e.getMessage());
+            System.exit(1);
+        }
+        if (ccacheNameEnv != null) {
+            ccacheName = ccacheNameEnv;
+        } else if (ccacheNameConf != null) {
+            ccacheName = ccacheNameConf;
+        } else {
+            StringBuilder uid = new StringBuilder();
+            try {
+                //Get UID through "id -u" command
+                String command = "id -u";
+                Process child = Runtime.getRuntime().exec(command);
+                InputStream in = child.getInputStream();
+                int c;
+                while ((c = in.read()) != -1) {
+                    uid.append((char) c);
+                }
+                in.close();
+            } catch (IOException e) {
+                System.err.println("Failed to get UID.");
+                System.exit(1);
+            }
+            ccacheName = "krb5cc_" + uid.toString().trim();
+            ccacheName = SysUtil.getTempDir().toString() + "/" + ccacheName;
+        }
+
+        return ccacheName;
+    }
+
+    private static int printKeytabInfo(KOptions klOptions) {
+        String[] header = new String[4];
+        header[0] = "KVNO Principal\n"
+                + "---- --------------------------------------------------------------------------";
+        header[1] = header[0];
+        header[2] = "KVNO Timestamp           Principal\n"
+                + "---- ------------------- ------------------------------------------------------";
+        header[3] = header[2];
+        int outputIndex = 0;
+        if (klOptions.contains(KlistOption.SHOW_KTAB_ENTRY_TS)) {
+            outputIndex |= 2;
+        }
+        if (klOptions.contains(KlistOption.SHOW_KTAB_ENTRY_KEY)) {
+            outputIndex |= 1;
+        }
+        System.out.println("Keytab name: FILE:" + keytabFilePath);
+        try {
+            File keytabFile = new File(keytabFilePath);
+            if (!keytabFile.exists()) {
+                System.out.println("klist: Key table file '" + keytabFilePath + "' not found. ");
+                return 0;
+            }
+            System.out.println(header[outputIndex]);
+            SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
+            Keytab keytab = Keytab.loadKeytab(keytabFile);
+            List<PrincipalName> principals = keytab.getPrincipals();
+            for (PrincipalName principal : principals) {
+                List<KeytabEntry> keytabEntries = keytab.getKeytabEntries(principal);
+                for (KeytabEntry entry : keytabEntries) {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append(String.format("%-4d ", entry.getKvno()));
+                    if ((outputIndex & 2) != 0) {
+                        Date date = new Date(entry.getTimestamp().getTime());
+                        sb.append(format.format(date));
+                        sb.append(' ');
+                    }
+                    sb.append(String.format("%s ", principal.getName()));
+                    if ((outputIndex & 1) != 0) {
+                        sb.append("(0x");
+                        sb.append(HexUtil.bytesToHex(entry.getKey().getKeyData()));
+                        sb.append(")");
+                    }
+                    System.out.println(sb);
+                }
+            }
+
+        } catch (IOException e) {
+            System.err.println("klist: Error while scan key table file '" + keytabFilePath + "'");
+        }
+        return 0;
+    }
+
+    private static int printInfo(KOptions klOptions) {
+        if (klOptions.contains(KlistOption.KEYTAB)) {
+            return printKeytabInfo(klOptions);
+        }
+        return printCredentialCacheInfo(klOptions);
+    }
+
+    public static void main(String[] args) throws Exception {
+        KOptions klOptions = new KOptions();
+        KlistOption klopt;
+        // String name = null;
+
+        int i = 0;
+        String opt, value, error;
+        while (i < args.length) {
+            error = null;
+            opt = args[i++];
+
+            if (opt.startsWith("-")) {
+                klopt = KlistOption.fromName(opt);
+                if (klopt == KlistOption.NONE) {
+                    error = "Invalid option:" + opt;
+                }
+            } else {
+                if (keytabFilePath == null && klOptions.contains(KlistOption.KEYTAB)) {
+                    keytabFilePath = opt;
+                }
+                break;
+            }
+
+            if (error == null && klopt.getOptionInfo().getType() != KOptionType.NOV) {
+                //needs value for this parameter
+                value = null;
+                if (i < args.length) {
+                    value = args[i++];
+                }
+                if (value != null) {
+                    KOptions.parseSetValue(klopt.getOptionInfo(), value);
+                } else {
+                    error = "Option" + klopt + "requires a following value";
+                }
+            }
+
+            if (error != null) {
+                printUsage(error);
+            }
+
+            klOptions.add(klopt);
+            if (klOptions.contains(KlistOption.KEYTAB)
+                && klOptions.contains(KlistOption.CREDENTIALS_CACHE)) {
+                error = "Can not use '-c' and '-k' at the same time ";
+                printUsage(error);
+            }
+        }
+
+        if (keytabFilePath == null) {
+            keytabFilePath = "/etc/krb5.keytab";
+        }
+
+        int errNo = KlistTool.printInfo(klOptions);
+        System.exit(errNo);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-server-tool/pom.xml
----------------------------------------------------------------------
diff --git a/has/has-tool/has-server-tool/pom.xml b/has/has-tool/has-server-tool/pom.xml
index 426eacf..0f634a6 100644
--- a/has/has-tool/has-server-tool/pom.xml
+++ b/has/has-tool/has-server-tool/pom.xml
@@ -4,7 +4,7 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
         <artifactId>has-tool</artifactId>
-        <groupId>org.apache.hadoop</groupId>
+        <groupId>org.apache.kerby</groupId>
         <version>1.0.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -13,12 +13,12 @@
 
     <dependencies>
       <dependency>
-        <groupId>org.apache.hadoop</groupId>
+        <groupId>org.apache.kerby</groupId>
         <artifactId>has-server</artifactId>
         <version>${project.version}</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.hadoop</groupId>
+        <groupId>org.apache.kerby</groupId>
         <artifactId>has-plugins</artifactId>
         <version>${project.version}</version>
       </dependency>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-tool/has-server-tool/src/main/java/org/apache/hadoop/has/tool/server/hadmin/local/HadminLocalTool.java
----------------------------------------------------------------------
diff --git a/has/has-tool/has-server-tool/src/main/java/org/apache/hadoop/has/tool/server/hadmin/local/HadminLocalTool.java b/has/has-tool/has-server-tool/src/main/java/org/apache/hadoop/has/tool/server/hadmin/local/HadminLocalTool.java
deleted file mode 100644
index 647ad4e..0000000
--- a/has/has-tool/has-server-tool/src/main/java/org/apache/hadoop/has/tool/server/hadmin/local/HadminLocalTool.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/**
- *  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.has.tool.server.hadmin.local;
-
-import org.apache.hadoop.has.common.HasException;
-import org.apache.hadoop.has.server.admin.LocalHasAdmin;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.AddPrincipalCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.AddPrincipalsCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.DeletePrincipalCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.DisableConfigureCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.EnableConfigureCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.ExportKeytabsCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.GetHostRolesCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.GetPrincipalCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.HadminCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.KeytabAddCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.ListPrincipalsCmd;
-import org.apache.hadoop.has.tool.server.hadmin.local.cmd.RenamePrincipalCmd;
-import org.apache.kerby.KOptions;
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
-import org.apache.kerby.kerberos.tool.kadmin.AuthUtil;
-import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
-import org.apache.kerby.util.OSUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.login.LoginException;
-import java.io.File;
-import java.security.Principal;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.Set;
-
-/**
- * Ref. MIT kadmin cmd tool usage.
- */
-public class HadminLocalTool {
-    private static final Logger LOG = LoggerFactory.getLogger(HadminLocalTool.class);
-    private static File confDir;
-
-    private static final String PROMPT = HadminLocalTool.class.getSimpleName() + ".local";
-    private static  final String USAGE = (OSUtil.isWindows()
-            ? "Usage: bin\\hadmin-local.cmd" : "Usage: sh bin/kadmin-local.sh")
-            + " <conf-dir> <-c cache_name>|<-k keytab>\n"
-            + "\tExample:\n"
-            + "\t\t"
-            + (OSUtil.isWindows()
-            ? "bin\\hadmin-local.cmd" : "sh bin/hadmin-local.sh")
-            + " conf -k admin.keytab\n";
-
-    private static void printUsage(String error) {
-        System.err.println(error + "\n");
-        System.err.println(USAGE);
-        System.exit(-1);
-    }
-
-    private static final String LEGAL_COMMANDS = "Available commands are: "
-        + "\n"
-        + "add_principal, addprinc\n"
-        + "                         Add principal\n"
-        + "delete_principal, delprinc\n"
-        + "                         Delete principal\n"
-        + "rename_principal, renprinc\n"
-        + "                         Rename principal\n"
-        + "get_principal, getprinc\n"
-        + "                         Get principal\n"
-        + "list_principals, listprincs\n"
-        + "                         List principals\n"
-        + "ktadd, xst\n"
-        + "                         Add entry(s) to a keytab\n"
-        + "get_hostroles, hostroles\n"
-        + "                         Get hostRoles\n"
-        + "export_keytabs, expkeytabs\n"
-        + "                         Export keytabs\n"
-        + "create_principals, creprincs\n"
-        + "                         Create principals\n"
-        + "enable_configure, enable\n"
-        + "                         Enable configure\n"
-        + "disable_configure, disable\n"
-        + "                         Disable configure\n";
-
-    private static void execute(LocalHasAdmin hadmin, String input) throws HasException {
-        // Omit the leading and trailing whitespace.
-        input = input.trim();
-        if (input.startsWith("cmd")) {
-            System.out.println(LEGAL_COMMANDS);
-            return;
-        }
-
-        String[] items = input.split("\\s+");
-        String cmd = items[0];
-        HadminCmd executor;
-        if (cmd.startsWith("add_principal")
-            || cmd.startsWith("addprinc")) {
-            executor = new AddPrincipalCmd(hadmin);
-        } else if (cmd.startsWith("delete_principal")
-            || cmd.startsWith("delprinc")) {
-            executor = new DeletePrincipalCmd(hadmin);
-        } else if (cmd.startsWith("rename_principal")
-            || cmd.startsWith("renprinc")) {
-            executor = new RenamePrincipalCmd(hadmin);
-        } else if (cmd.startsWith("list_principals")
-            || cmd.startsWith("listprincs")) {
-            executor = new ListPrincipalsCmd(hadmin);
-        } else if (cmd.startsWith("ktadd")
-            || cmd.startsWith("xst")) {
-            executor = new KeytabAddCmd(hadmin);
-        } else if (cmd.startsWith("get_hostroles")
-            || cmd.startsWith("hostroles")) {
-            executor = new GetHostRolesCmd(hadmin);
-        } else if (cmd.startsWith("create_principals")
-            || cmd.startsWith("creprincs")) {
-            executor = new AddPrincipalsCmd(hadmin);
-        } else if (cmd.startsWith("export_keytabs")
-            || cmd.startsWith("expkeytabs")) {
-            executor = new ExportKeytabsCmd(hadmin);
-        } else if (cmd.startsWith("enable_configure")
-            || cmd.startsWith("enable")) {
-            executor = new EnableConfigureCmd(hadmin);
-        } else if (cmd.startsWith("disable_configure")
-            || cmd.startsWith("disable")) {
-            executor = new DisableConfigureCmd(hadmin);
-        }  else if (cmd.startsWith("get_principal")
-            || cmd.startsWith("getprinc")) {
-            executor = new GetPrincipalCmd(hadmin);
-        } else {
-            System.out.println(LEGAL_COMMANDS);
-            return;
-        }
-        executor.execute(items);
-    }
-
-    private static File getConfDir(String[] args) {
-        String envDir;
-        confDir = new File(args[0]);
-        if (confDir == null || !confDir.exists()) {
-            try {
-                Map<String, String> mapEnv = System.getenv();
-                envDir = mapEnv.get("KRB5_KDC_DIR");
-            } catch (SecurityException e) {
-                envDir = null;
-            }
-            if (envDir != null) {
-                confDir = new File(envDir);
-            } else {
-                confDir = new File("/etc/kerby/"); // for Linux. TODO: fix for Win etc.
-            }
-
-            if (!confDir.exists()) {
-                throw new RuntimeException("Can not locate KDC backend directory "
-                        + confDir.getAbsolutePath());
-            }
-        }
-        LOG.info("Conf dir:" + confDir.getAbsolutePath());
-        return confDir;
-    }
-
-    public static void main(String[] args) {
-
-        if (args.length < 2) {
-            System.err.println(USAGE);
-            return;
-        }
-
-        LocalHasAdmin hadmin;
-        try {
-            hadmin = new LocalHasAdmin(getConfDir(args));
-        } catch (KrbException e) {
-            System.err.println("Failed to init HasAdmin due to " + e.getMessage());
-            return;
-        }
-
-        KOptions kOptions = ToolUtil.parseOptions(args, 1, args.length - 1);
-        if (kOptions == null) {
-            System.err.println(USAGE);
-            return;
-        }
-
-        String hadminPrincipal = hadmin.getHadminPrincipal();
-        Subject subject = null;
-        if (kOptions.contains(KadminOption.CCACHE)) {
-            File ccFile = kOptions.getFileOption(KadminOption.CCACHE);
-            if (ccFile == null || !ccFile.exists()) {
-                printUsage("Need the valid credentials cache file.");
-                return;
-            }
-            try {
-                subject = AuthUtil.loginUsingTicketCache(hadminPrincipal, ccFile);
-            } catch (LoginException e) {
-                System.err.println("Could not login with: " + hadminPrincipal
-                    + e.getMessage());
-                return;
-            }
-        } else if (kOptions.contains(KadminOption.K)) {
-            File keyTabFile = new File(kOptions.getStringOption(KadminOption.K));
-            if (keyTabFile == null || !keyTabFile.exists()) {
-                printUsage("Need the valid keytab file.");
-                return;
-            }
-            try {
-                subject = AuthUtil.loginUsingKeytab(hadminPrincipal, keyTabFile);
-            } catch (LoginException e) {
-                System.err.println("Could not login with: " + hadminPrincipal
-                    + e.getMessage());
-                return;
-            }
-        } else {
-            printUsage("No credentials cache file or keytab file for authentication.");
-        }
-        if (subject != null) {
-            Principal adminPrincipal = new KerberosPrincipal(hadminPrincipal);
-            Set<Principal> princSet = subject.getPrincipals();
-            if (princSet == null || princSet.isEmpty()) {
-                printUsage("The principals in subject is empty.");
-                return;
-            }
-            if (princSet.contains(adminPrincipal)) {
-                System.out.println("Login successful for user: " + hadminPrincipal);
-            } else {
-                printUsage("Login failure for " + hadminPrincipal);
-                return;
-            }
-        } else {
-            printUsage("The subject is null, login failure for " + hadminPrincipal);
-            return;
-        }
-        System.out.println("enter \"cmd\" to see legal commands.");
-        System.out.print(PROMPT + ": ");
-
-        try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
-            String input = scanner.nextLine();
-
-            while (!(input.equals("quit") || input.equals("exit")
-                    || input.equals("q"))) {
-                try {
-                    execute(hadmin, input);
-                } catch (HasException e) {
-                    System.err.println(e.getMessage());
-                }
-                System.out.print(PROMPT + ": ");
-                input = scanner.nextLine();
-            }
-        }
-    }
-}