You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ze...@apache.org on 2018/07/06 06:03:01 UTC

directory-kerby git commit: DIRKRB-721 Add some commands into HAS remote admin tool. Contributed by Peiyuan Qi.

Repository: directory-kerby
Updated Branches:
  refs/heads/trunk 6b3a0de39 -> 5ec8b2053


DIRKRB-721 Add some commands into HAS remote admin tool. Contributed by Peiyuan Qi.


Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/5ec8b205
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/5ec8b205
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/5ec8b205

Branch: refs/heads/trunk
Commit: 5ec8b2053d281dde0a26d28ab4deba3e7182f169
Parents: 6b3a0de
Author: zenglinx <fr...@intel.com>
Authored: Fri Jul 6 14:02:26 2018 +0800
Committer: zenglinx <fr...@intel.com>
Committed: Fri Jul 6 14:02:26 2018 +0800

----------------------------------------------------------------------
 .../kerby/has/client/HasAuthAdminClient.java    | 110 ++++++++++++++--
 .../kerby/has/server/web/rest/KadminApi.java    | 129 +++++++++++++++++--
 kerby-tool/has-tool/pom.xml                     |   5 +
 .../tool/admin/remote/AdminRemoteTool.java      |  31 +++--
 .../remote/cmd/AddPrincipalsRemoteCmd.java      |  82 ------------
 .../remote/cmd/CreatePrincipalsRemoteCmd.java   |  82 ++++++++++++
 .../remote/cmd/GetPrincipalRemoteCommand.java   |  75 +++++++++++
 .../admin/remote/cmd/KeytabAddRemoteCmd.java    |  94 ++++++++++++++
 .../remote/cmd/ListPrincipalsRemoteCmd.java     |   3 +-
 .../tool/kadmin/command/KeytabAddCommand.java   |   2 +-
 10 files changed, 498 insertions(+), 115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasAuthAdminClient.java
----------------------------------------------------------------------
diff --git a/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasAuthAdminClient.java b/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasAuthAdminClient.java
index 04da650..73eeb5a 100644
--- a/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasAuthAdminClient.java
+++ b/has-project/has-client/src/main/java/org/apache/kerby/has/client/HasAuthAdminClient.java
@@ -207,7 +207,7 @@ public class HasAuthAdminClient implements Kadmin {
             LOG.error("IO error occurred." + e.getMessage());
             throw new KrbException("IO error occurred.", e);
         }
-        return stringtoList(response);
+        return convertJsonStringToList(response);
     }
 
     @Override
@@ -216,7 +216,7 @@ public class HasAuthAdminClient implements Kadmin {
 
         URL url;
         try {
-            url = new URL(getKadminBaseURL() + "getprincipals?exp=" + exp);
+            url = new URL(getKadminBaseURL() + "listprincipals?exp=" + exp);
         } catch (MalformedURLException e) {
             throw new KrbException("Failed to create a URL object. ", e);
         }
@@ -238,17 +238,17 @@ public class HasAuthAdminClient implements Kadmin {
         if (response == null) {
             throw new KrbException("Please initial KDC first.");
         }
-        return stringtoList(response);
+        return convertJsonStringToList(response);
     }
 
     /**
-     * Change JSON string to a List.
+     * Convert JSON string to a List.
      *
      * @param result principals JSON string which like
      *               "["HTTP\/host1@HADOOP.COM","HTTP\/host2@HADOOP.COM"]"
-     * @return principalLists.
+     * @return principal lists.
      */
-    private List<String> stringtoList(String result) throws KrbException {
+    private List<String> convertJsonStringToList(String result) throws KrbException {
         List<String> principalLists = new ArrayList<>();
         try {
             JSONArray jsonArray = new JSONArray(result);
@@ -262,7 +262,7 @@ public class HasAuthAdminClient implements Kadmin {
     }
 
     @Override
-    public void exportKeytab(File keytab, String principal) throws KrbException {
+    public void exportKeytab(File keytabFile, String principal) throws KrbException {
         URL url;
         try {
             url = new URL(getKadminBaseURL() + "exportkeytab?principal=" + principal);
@@ -278,7 +278,18 @@ public class HasAuthAdminClient implements Kadmin {
             if (httpConn.getResponseCode() != 200) {
                 throw new KrbException(HasClientUtil.getResponse(httpConn));
             }
-            FileOutputStream fos = new FileOutputStream(keytab);
+
+            try {
+                if (!keytabFile.exists() && !keytabFile.createNewFile()) {
+                    throw new KrbException("Failed to create keytab file "
+                            + keytabFile.getAbsolutePath());
+                }
+            } catch (IOException e) {
+                throw new KrbException("Failed to load or create keytab "
+                        + keytabFile.getAbsolutePath(), e);
+            }
+
+            FileOutputStream fos = new FileOutputStream(keytabFile);
             InputStream in = httpConn.getInputStream();
             byte[] buffer = new byte[3 * 1024];
             int read;
@@ -290,7 +301,49 @@ public class HasAuthAdminClient implements Kadmin {
         } catch (IOException e) {
             throw new KrbException("IO error occurred.", e);
         }
-        LOG.info("Receive keytab file \"" + keytab.getName() + "\" from server successfully.");
+        LOG.info("Receive keytab file \"" + keytabFile.getName() + "\" from server successfully.");
+    }
+
+    public void exportKeytabWithGlob(File keytabFile, String principal) throws KrbException {
+        URL url;
+        try {
+            url = new URL(getKadminBaseURL() + "exportkeytab?principal=" + principal + "&global=true");
+        } catch (MalformedURLException e) {
+            LOG.error("Failed to create a URL object.", e);
+            throw new KrbException("Failed to create a URL object.", e);
+        }
+
+        HttpURLConnection httpConn = HasClientUtil.createConnection(hasConfig, url, "GET", true);
+        try {
+            httpConn.connect();
+            if (httpConn.getResponseCode() != 200) {
+                throw new KrbException(HasClientUtil.getResponse(httpConn));
+            }
+
+            try {
+                if (!keytabFile.exists() && !keytabFile.createNewFile()) {
+                    throw new KrbException("Failed to create keytab file "
+                            + keytabFile.getAbsolutePath());
+                }
+            } catch (IOException e) {
+                throw new KrbException("Failed to load or create keytab "
+                        + keytabFile.getAbsolutePath(), e);
+            }
+
+            FileOutputStream fos = new FileOutputStream(keytabFile);
+            InputStream in = httpConn.getInputStream();
+            byte[] buffer = new byte[3 * 1024];
+            int read;
+            while ((read = in.read(buffer)) > 0) {
+                fos.write(buffer, 0, read);
+            }
+            fos.close();
+            in.close();
+        } catch (IOException e) {
+            LOG.error("IO error occurred.", e);
+            throw new KrbException("IO error occurred.", e);
+        }
+        LOG.info("Receive keytab file " + keytabFile.getName() + " from server successfully.");
     }
 
     @Override
@@ -422,7 +475,7 @@ public class HasAuthAdminClient implements Kadmin {
         } catch (Exception e) {
             throw new KrbException(e.getMessage());
         }
-        return stringtoList(response);
+        return convertJsonStringToList(response);
     }
 
     public void setEnableOfConf(String isEnable) throws KrbException {
@@ -528,4 +581,41 @@ public class HasAuthAdminClient implements Kadmin {
         }
         return response;
     }
+
+    public String getPrincipal(String principalName) throws KrbException {
+        HttpURLConnection httpConn;
+
+        URL url;
+        try {
+            url = new URL(getKadminBaseURL() + "getprincipal?principal=" + principalName);
+        } catch (MalformedURLException e) {
+            throw new KrbException("Failed to create a URL object.", e);
+        }
+
+        httpConn = HasClientUtil.createConnection(hasConfig, url, "POST", true);
+
+        String response;
+        try {
+            httpConn.setDoInput(true);
+            httpConn.connect();
+
+            OutputStream out = httpConn.getOutputStream();
+            out.write(principalName.getBytes());
+            out.flush();
+            out.close();
+
+            if (httpConn.getResponseCode() == 200) {
+                response = HasClientUtil.getResponse(httpConn);
+                LOG.info(response);
+            } else {
+                LOG.info(HasClientUtil.getResponse(httpConn));
+                throw new KrbException(HasClientUtil.getResponse(httpConn));
+            }
+        } catch (IOException e) {
+            LOG.error("IO error occurred.", e);
+            throw new KrbException("IO error occurred.", e);
+        }
+
+        return response;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/has-project/has-server/src/main/java/org/apache/kerby/has/server/web/rest/KadminApi.java
----------------------------------------------------------------------
diff --git a/has-project/has-server/src/main/java/org/apache/kerby/has/server/web/rest/KadminApi.java b/has-project/has-server/src/main/java/org/apache/kerby/has/server/web/rest/KadminApi.java
index 6a967ed..24ba8b2 100644
--- a/has-project/has-server/src/main/java/org/apache/kerby/has/server/web/rest/KadminApi.java
+++ b/has-project/has-server/src/main/java/org/apache/kerby/has/server/web/rest/KadminApi.java
@@ -23,8 +23,12 @@ import org.apache.kerby.has.server.web.rest.param.PasswordParam;
 import org.apache.kerby.has.server.web.rest.param.PrincipalParam;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadminImpl;
+import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
 import org.apache.kerby.kerberos.kerb.server.KdcSetting;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
 import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONObject;
 
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
@@ -34,12 +38,14 @@ import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.io.File;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Kadmin web methods implementation.
@@ -56,12 +62,20 @@ public class KadminApi {
      * export single keytab file
      *
      * @param principal principal name to export keytab file
+     * @param isGlobal string to represent if current export principal is in global mode
      * @return Response
      */
     @GET
     @Path("/exportkeytab")
     @Produces(MediaType.TEXT_PLAIN)
-    public Response exportKeytab(@QueryParam("principal") final String principal) {
+    public Response exportKeytab(@QueryParam("principal") final String principal,
+                                 @QueryParam("global") @DefaultValue("false")
+                                 final String isGlobal) {
+        boolean global = false;
+        String globalModeVlue = "true";
+        if (globalModeVlue.equals(isGlobal)) {
+            global = true;
+        }
         if (httpRequest.isSecure()) {
             WebServer.LOG.info("Exporting keytab file for " + principal + "...");
             String msg;
@@ -75,20 +89,58 @@ public class KadminApi {
                 WebServer.LOG.info(msg);
                 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
             }
-            WebServer.LOG.info("Create keytab file for " + principal + " successfully.");
             if (principal != null) {
-                File path = new File("/tmp/" + System.currentTimeMillis());
-                if (path.mkdirs()) {
-                    File keytabFile = new File(path, principal + ".keytab");
+                if (global) {
+                    // principal is a pattern expression
+                    List<String> princList;
                     try {
-                        localKadmin.exportKeytab(keytabFile, principal);
-                        return Response.ok(keytabFile).header("Content-Disposition", "attachment; filename="
-                                + keytabFile.getName()).build();
-                    } catch (KrbException e) {
-                        msg = "Failed to export keytab. " + e.toString();
+                        princList = localKadmin.getPrincipals(principal);
+                        WebServer.LOG.info("Success to get principals with JSON.");
+                    } catch (Exception e) {
+                        msg = "Failed to get principals,because : " + e.getMessage();
                         WebServer.LOG.error(msg);
                         return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
                     }
+                    if (princList.size() != 0) {
+                        WebServer.LOG.info("Exporting keytab file for " + principal + "...");
+                        File path = new File("/tmp/" + System.currentTimeMillis());
+                        if (path.mkdirs()) {
+                            File keytabFile = new File(path, principal.replace('/', '-')
+                                                                            .replace('*', '-')
+                                                                            .replace('?', '-')
+                                            + ".keytab");
+                            try {
+                                localKadmin.exportKeytab(keytabFile, princList);
+                                WebServer.LOG.info("Create keytab file for principals successfully.");
+                                return Response.ok(keytabFile).header("Content-Disposition",
+                                        "attachment; filename=" + keytabFile.getName()).build();
+                            } catch (KrbException e) {
+                                msg = "Failed to export keytab. " + e.toString();
+                                WebServer.LOG.error(msg);
+                                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+                            }
+                        }
+                    } else {
+                        msg = "No matched principals.";
+                        WebServer.LOG.error(msg);
+                        return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
+                    }
+                } else {
+                    File path = new File("/tmp/" + System.currentTimeMillis());
+                    if (path.mkdirs()) {
+                        File keytabFile = new File(path, principal.replace('/', '-') + ".keytab");
+                        try {
+                            localKadmin.exportKeytab(keytabFile, principal);
+                            WebServer.LOG.info("Create keytab file for " + principal + " successfully.");
+                            return Response.ok(keytabFile).header(
+                                "Content-Disposition", "attachment; filename="
+                                    + keytabFile.getName()).build();
+                        } catch (KrbException e) {
+                            msg = "Failed to export keytab. " + e.toString();
+                            WebServer.LOG.error(msg);
+                            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+                        }
+                    }
                 }
             }
             return Response.serverError().build();
@@ -134,7 +186,7 @@ public class KadminApi {
      * Add principal by name and password.
      *
      * @param principal principal name.
-     * @param password  principal password
+     * @param newPassword principal password
      * @return Response
      */
     @POST
@@ -315,5 +367,60 @@ public class KadminApi {
         }
         return Response.status(Response.Status.FORBIDDEN).entity("HTTPS required.\n").build();
     }
+
+    /**
+     * Get principal by name.
+     *
+     * @param principal principal like "admin" or "admin@HADOOP.COM".
+     * @return Response
+     */
+    @POST
+    @Path("/getprincipal")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getPrincipal(@QueryParam(PrincipalParam.NAME) @DefaultValue(PrincipalParam.DEFAULT)
+                                 final PrincipalParam principal) {
+        if (httpRequest.isSecure()) {
+            WebServer.LOG.info("Request to get a principal named " + principal.getValue());
+            String msg;
+            LocalKadminImpl localKadmin;
+            HasServer hasServer = WebServer.getHasServerFromContext(context);
+            KdcSetting serverSetting = hasServer.getKdcServer().getKdcSetting();
+            try {
+                localKadmin = new LocalKadminImpl(serverSetting);
+            } catch (KrbException e) {
+                msg = "Failed to create local kadmin. " + e.getMessage();
+                WebServer.LOG.error(msg);
+                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+            }
+
+            try {
+                KrbIdentity identity = localKadmin.getPrincipal(principal.getValue());
+                // put single identity in object to send back to client
+                JSONObject principle = new JSONObject();
+                Map<EncryptionType, EncryptionKey> key = identity.getKeys();
+                principle.put("Name", identity.getPrincipalName());
+                principle.put("Expiration date", identity.getExpireTime());
+                principle.put("Created time", identity.getCreatedTime());
+                principle.put("KDC flags", identity.getKdcFlags());
+                principle.put("Key version", identity.getKeyVersion());
+                principle.put("Number of keys", key.size());
+                JSONObject keySet = new JSONObject();
+                int keyCount = 0;
+                for (EncryptionType keyType : key.keySet()) {
+                    keySet.put(String.valueOf(keyCount++), keyType);
+                }
+                principle.put("Keys", keySet);
+                WebServer.LOG.info("Success to get principal with JSON.");
+
+                return Response.ok(principle).build();
+            } catch (Exception e) {
+                msg = "Failed to get principal,because : " + e.getMessage();
+                WebServer.LOG.error(msg);
+                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+            }
+        }
+        return Response.status(Response.Status.FORBIDDEN).entity("HTTPS required.\n").build();
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/has-tool/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-tool/has-tool/pom.xml b/kerby-tool/has-tool/pom.xml
index 0dc5ca4..0844dd4 100644
--- a/kerby-tool/has-tool/pom.xml
+++ b/kerby-tool/has-tool/pom.xml
@@ -42,6 +42,11 @@
             <artifactId>jsch</artifactId>
             <version>${jsch.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>LATEST</version>
+        </dependency>
     </dependencies>
 
 </project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/AdminRemoteTool.java
----------------------------------------------------------------------
diff --git a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/AdminRemoteTool.java b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/AdminRemoteTool.java
index af14dbe..544cec7 100644
--- a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/AdminRemoteTool.java
+++ b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/AdminRemoteTool.java
@@ -25,7 +25,7 @@ import org.apache.kerby.has.common.HasException;
 import org.apache.kerby.has.common.util.HasUtil;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.tool.admin.remote.cmd.AddPrincipalRemoteCmd;
-import org.apache.kerby.kerberos.tool.admin.remote.cmd.AddPrincipalsRemoteCmd;
+import org.apache.kerby.kerberos.tool.admin.remote.cmd.CreatePrincipalsRemoteCmd;
 import org.apache.kerby.kerberos.tool.admin.remote.cmd.AdminRemoteCmd;
 import org.apache.kerby.kerberos.tool.admin.remote.cmd.ChangePasswordRemoteCmd;
 import org.apache.kerby.kerberos.tool.admin.remote.cmd.DeletePrincipalRemoteCmd;
@@ -35,6 +35,8 @@ import org.apache.kerby.kerberos.tool.admin.remote.cmd.ExportKeytabsRemoteCmd;
 import org.apache.kerby.kerberos.tool.admin.remote.cmd.GetHostRolesRemoteCmd;
 import org.apache.kerby.kerberos.tool.admin.remote.cmd.ListPrincipalsRemoteCmd;
 import org.apache.kerby.kerberos.tool.admin.remote.cmd.RenamePrincipalRemoteCmd;
+import org.apache.kerby.kerberos.tool.admin.remote.cmd.GetPrincipalRemoteCommand;
+import org.apache.kerby.kerberos.tool.admin.remote.cmd.KeytabAddRemoteCmd;
 import org.apache.kerby.util.OSUtil;
 import org.jline.reader.Completer;
 import org.jline.reader.EndOfFileException;
@@ -70,14 +72,18 @@ public class AdminRemoteTool {
         + "                         Rename principal\n"
         + "change_password, cpw\n"
         + "                         Change password\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"
-        + "add_principals, addprincs\n"
-        + "                         Add principals\n"
+        + "create_principals, creprincs\n"
+        + "                         Create principals\n"
         + "enable_configure, enable\n"
         + "                         Enable configure\n"
         + "disable_configure, disable\n"
@@ -108,10 +114,9 @@ public class AdminRemoteTool {
 
         System.out.println("enter \"cmd\" to see legal commands.");
 
-        Completer completer = new StringsCompleter("add_principal",
-                "delete_principal", "rename_principal", "change_password", "list_principals",
-                "get_hostroles", "export_keytabs", "add_principals", "enable_configure",
-                "disable_configure");
+        Completer completer = new StringsCompleter("add_principal", "delete_principal", "rename_principal",
+                "change_password", "get_principal", "list_principals", "ktadd", "get_hostroles", "export_keytabs",
+                "create_principals", "enable_configure", "disable_configure");
 
         Terminal terminal = null;
         try {
@@ -160,15 +165,21 @@ public class AdminRemoteTool {
         } else if (cmd.equals("change_password")
             || cmd.startsWith("cpw")) {
             executor = new ChangePasswordRemoteCmd(hasAuthAdminClient);
+        } else if (cmd.equals("get_principal")
+                || cmd.equals("getprinc")) {
+            executor = new GetPrincipalRemoteCommand(hasAuthAdminClient);
         } else if (cmd.equals("list_principals")
             || cmd.equals("listprincs")) {
             executor = new ListPrincipalsRemoteCmd(hasAuthAdminClient);
+        }  else if (cmd.startsWith("ktadd")
+                || cmd.startsWith("xst")) {
+            executor = new KeytabAddRemoteCmd(hasAuthAdminClient);
         } else if (cmd.equals("get_hostroles")
             || cmd.equals("hostroles")) {
             executor = new GetHostRolesRemoteCmd(hasAuthAdminClient);
-        } else if (cmd.equals("add_principals")
-            || cmd.equals("addprincs")) {
-            executor = new AddPrincipalsRemoteCmd(hasAuthAdminClient);
+        } else if (cmd.equals("create_principals")
+            || cmd.equals("creprincs")) {
+            executor = new CreatePrincipalsRemoteCmd(hasAuthAdminClient);
         } else if (cmd.equals("export_keytabs")
             || cmd.equals("expkeytabs")) {
             executor = new ExportKeytabsRemoteCmd(hasAuthAdminClient);

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/AddPrincipalsRemoteCmd.java
----------------------------------------------------------------------
diff --git a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/AddPrincipalsRemoteCmd.java b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/AddPrincipalsRemoteCmd.java
deleted file mode 100644
index 16ebc97..0000000
--- a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/AddPrincipalsRemoteCmd.java
+++ /dev/null
@@ -1,82 +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.kerby.kerberos.tool.admin.remote.cmd;
-
-import org.apache.kerby.has.client.HasAuthAdminClient;
-import org.apache.kerby.kerberos.kerb.KrbException;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.List;
-
-public class AddPrincipalsRemoteCmd extends AdminRemoteCmd {
-    private static final String USAGE = "\nUsage: add_principals [hostRoles-file]\n"
-            + "\t'hostRoles-file' is a file with a hostRoles json string like:\n"
-            + "\t\t{HOSTS: [ {\"name\":\"host1\",\"hostRoles\":\"HDFS\"}, "
-            + "{\"name\":\"host2\",\"hostRoles\":\"HDFS,HBASE\"} ] }\n"
-            + "\tExample:\n"
-            + "\t\tadd_principals hostroles.txt\n";
-
-    public AddPrincipalsRemoteCmd(HasAuthAdminClient authHadmin) {
-        super(authHadmin);
-    }
-
-    @Override
-    public void execute(String[] items) throws KrbException {
-        //String param = items[0];
-        if (items.length != 2) {
-            System.err.println(USAGE);
-            return;
-        }
-
-        File hostRoles = new File(items[1]);
-        if (!hostRoles.exists()) {
-            System.err.println("HostRoles file is not exists.");
-            return;
-        }
-
-        HasAuthAdminClient client = getAuthAdminClient();
-
-        BufferedReader reader;
-        try {
-            reader = new BufferedReader(new FileReader(hostRoles));
-        } catch (FileNotFoundException e) {
-            throw new KrbException("File not exist", e);
-        }
-        StringBuilder sb = new StringBuilder();
-        String tempString;
-        try {
-            while ((tempString = reader.readLine()) != null) {
-                sb.append(tempString);
-            }
-        } catch (IOException e) {
-            throw new KrbException("Errors occurred when read line. ", e);
-        }
-        List<String> results = client.addPrincipalsByRole(sb.toString());
-        if (results != null) {
-            for (int i = 0; i < results.size(); i++) {
-                System.out.println(results.get(i));
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/CreatePrincipalsRemoteCmd.java
----------------------------------------------------------------------
diff --git a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/CreatePrincipalsRemoteCmd.java b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/CreatePrincipalsRemoteCmd.java
new file mode 100644
index 0000000..0c98556
--- /dev/null
+++ b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/CreatePrincipalsRemoteCmd.java
@@ -0,0 +1,82 @@
+/**
+ *  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.kerberos.tool.admin.remote.cmd;
+
+import org.apache.kerby.has.client.HasAuthAdminClient;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+
+public class CreatePrincipalsRemoteCmd extends AdminRemoteCmd {
+    private static final String USAGE = "\nUsage: add_principals [hostRoles-file]\n"
+            + "\t'hostRoles-file' is a file with a hostRoles json string like:\n"
+            + "\t\t{HOSTS: [ {\"name\":\"host1\",\"hostRoles\":\"HDFS\"}, "
+            + "{\"name\":\"host2\",\"hostRoles\":\"HDFS,HBASE\"} ] }\n"
+            + "\tExample:\n"
+            + "\t\tadd_principals hostroles.txt\n";
+
+    public CreatePrincipalsRemoteCmd(HasAuthAdminClient authHadmin) {
+        super(authHadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        //String param = items[0];
+        if (items.length != 2) {
+            System.err.println(USAGE);
+            return;
+        }
+
+        File hostRoles = new File(items[1]);
+        if (!hostRoles.exists()) {
+            System.err.println("HostRoles file is not exists.");
+            return;
+        }
+
+        HasAuthAdminClient client = getAuthAdminClient();
+
+        BufferedReader reader;
+        try {
+            reader = new BufferedReader(new FileReader(hostRoles));
+        } catch (FileNotFoundException e) {
+            throw new KrbException("File not exist", e);
+        }
+        StringBuilder sb = new StringBuilder();
+        String tempString;
+        try {
+            while ((tempString = reader.readLine()) != null) {
+                sb.append(tempString);
+            }
+        } catch (IOException e) {
+            throw new KrbException("Errors occurred when read line. ", e);
+        }
+        List<String> results = client.addPrincipalsByRole(sb.toString());
+        if (results != null) {
+            for (int i = 0; i < results.size(); i++) {
+                System.out.println(results.get(i));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/GetPrincipalRemoteCommand.java
----------------------------------------------------------------------
diff --git a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/GetPrincipalRemoteCommand.java b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/GetPrincipalRemoteCommand.java
new file mode 100644
index 0000000..ce32237
--- /dev/null
+++ b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/GetPrincipalRemoteCommand.java
@@ -0,0 +1,75 @@
+/**
+ *  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.kerberos.tool.admin.remote.cmd;
+
+import org.json.JSONObject;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.has.client.HasAuthAdminClient;
+
+/**
+ * Remote get principal cmd
+ */
+public class GetPrincipalRemoteCommand extends AdminRemoteCmd {
+    private static final String USAGE = "Usage: getprinc principalName\n"
+                                      + "\tExample:\n"
+                                      + "\t\tgetprinc hello@TEST.COM\n";
+
+    public GetPrincipalRemoteCommand(HasAuthAdminClient authHadmin) {
+        super(authHadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length < 2) {
+            System.err.println(USAGE);
+            return;
+        }
+
+        String clientPrincipalName = items[items.length - 1];
+        String principalData = null;
+        HasAuthAdminClient client = getAuthAdminClient();
+        try {
+            principalData = client.getPrincipal(clientPrincipalName);
+        } catch (KrbException e) {
+            System.err.println("Failed to get principal: " + clientPrincipalName + ". " + e.toString());
+        }
+
+        if (principalData == null) {
+            return;
+        } else {
+            System.out.println("Principal is listed:");
+            JSONObject principle = new JSONObject(principalData);
+            System.out.println(
+                    "Principal: " + principle.getString("Name") + "\n"
+                            + "Expiration date: " + principle.getString("Expiration date") + "\n"
+                            + "Created time: "
+                            + principle.getString("Created time") + "\n"
+                            + "KDC flags: " + String.valueOf(principle.getInt("KDC flags")) + "\n"
+                            + "Key version: " + String.valueOf(principle.getInt("Key version")) + "\n"
+                            + "Number of keys: " + String.valueOf(principle.getInt("Number of keys"))
+            );
+
+            JSONObject keySet = principle.getJSONObject("Keys");
+            for (int keyCount = 0; keyCount < principle.getInt("Number of keys"); keyCount++) {
+                System.out.println("key: " + keySet.getString(String.valueOf(keyCount)));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/KeytabAddRemoteCmd.java
----------------------------------------------------------------------
diff --git a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/KeytabAddRemoteCmd.java b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/KeytabAddRemoteCmd.java
new file mode 100644
index 0000000..c125316
--- /dev/null
+++ b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/KeytabAddRemoteCmd.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.kerberos.tool.admin.remote.cmd;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.has.client.HasAuthAdminClient;
+
+import java.io.File;
+
+/**
+ * Remote get principal cmd
+ */
+public class KeytabAddRemoteCmd extends AdminRemoteCmd {
+    private static final String USAGE = "Usage: ktadd [-k[eytab] keytab] "
+                                      + "[principal | -glob princ-exp] [...]\n"
+                                      + "\tExample:\n"
+                                      + "\t\tktadd hello@TEST.COM -k /keytab/location\n";
+    private static final String DEFAULT_KEYTAB_FILE_LOCATION = "/etc/krb5.keytab";
+
+    public KeytabAddRemoteCmd(HasAuthAdminClient authHadmin) {
+        super(authHadmin);
+    }
+
+    @Override
+    public void execute(String[] items) throws KrbException {
+        if (items.length < 2) {
+            System.err.println(USAGE);
+            return;
+        }
+
+        String principal = null;
+        String keytabFileLocation = null;
+        Boolean glob = false;
+
+        int index = 1;
+        while (index < items.length) {
+            String command = items[index];
+            if (command.equals("-k")) {
+                index++;
+                if (index >= items.length) {
+                    System.err.println(USAGE);
+                    return;
+                }
+                keytabFileLocation = items[index].trim();
+            } else if (command.equals("-glob")) {
+                glob = true;
+            } else if (!command.startsWith("-")) {
+                principal = command;
+            }
+            index++;
+        }
+
+        if (keytabFileLocation == null) {
+            keytabFileLocation = DEFAULT_KEYTAB_FILE_LOCATION;
+        }
+        File keytabFile = new File(keytabFileLocation);
+
+        if (principal == null) {
+            System.out.println((glob ? "princ-exp" : "principal") + " not specified!");
+            System.err.println(USAGE);
+            return;
+        }
+
+        HasAuthAdminClient client = getAuthAdminClient();
+        try {
+            if (glob) {
+                client.exportKeytabWithGlob(keytabFile, principal);
+            } else {
+                client.exportKeytab(keytabFile, principal);
+            }
+            System.out.println("Export Keytab to " + keytabFileLocation);
+        } catch (KrbException e) {
+            System.err.println("Principal \"" + principal + "\" fail to add entry to keytab."
+                    + e.toString());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/ListPrincipalsRemoteCmd.java
----------------------------------------------------------------------
diff --git a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/ListPrincipalsRemoteCmd.java b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/ListPrincipalsRemoteCmd.java
index b5d855a..7ad83b7 100644
--- a/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/ListPrincipalsRemoteCmd.java
+++ b/kerby-tool/has-tool/src/main/java/org/apache/kerby/kerberos/tool/admin/remote/cmd/ListPrincipalsRemoteCmd.java
@@ -26,7 +26,8 @@ import java.util.List;
 
 public class ListPrincipalsRemoteCmd extends AdminRemoteCmd {
     private static final String USAGE = "Usage: list_principals [expression]\n"
-            + "\t'expression' is a shell-style glob expression that can contain the wild-card characters ?, *, and []."
+            + "\t'expression' is a shell-style glob expression "
+            + "that can contain the wild-card characters ?, *, and [].\n"
             + "\tExample:\n"
             + "\t\tlist_principals [expression]\n";
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/5ec8b205/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java
----------------------------------------------------------------------
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java
index d96d5a0..71fdee7 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java
@@ -83,7 +83,7 @@ public class KeytabAddCommand extends KadminCommand {
             } else {
                 getKadmin().exportKeytab(keytabFile, principal);
             }
-            System.out.println("Done!");
+            System.out.println("Export Keytab to " + keytabFileLocation);
         } catch (KrbException e) {
             System.err.println("Principal \"" + principal + "\" fail to add entry to keytab."
                     + e.getMessage());