directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From plusplusjia...@apache.org
Subject [19/27] directory-kerby git commit: DIRKRB-592 Merge kadmin-remote branch to trunk.
Date Thu, 07 Jul 2016 06:42:04 GMT
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteAdminClientTool.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteAdminClientTool.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteAdminClientTool.java
new file mode 100644
index 0000000..27a8da2
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteAdminClientTool.java
@@ -0,0 +1,263 @@
+/**
+ *  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.kerb.admin;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminConfig;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminUtil;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteAddPrincipalCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteDeletePrincipalCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteGetprincsCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemotePrintUsageCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteRenamePrincipalCommand;
+import org.apache.kerby.kerberos.kerb.common.KrbUtil;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.kerberos.kerb.transport.KrbNetwork;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+import org.apache.kerby.util.OSUtil;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+/**
+ * Command use of remote admin
+ */
+public class RemoteAdminClientTool {
+    private static final byte[] EMPTY = new byte[0];
+    private static KrbTransport transport;
+    private static final String PROMPT = RemoteAdminClientTool.class.getSimpleName() + ".local:";
+    private static final String USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\remote-admin-client.cmd" : "Usage: sh bin/remote-admin-client.sh")
+        + " <conf-file>\n"
+        + "\tExample:\n"
+        + "\t\t"
+        + (OSUtil.isWindows()
+        ? "bin\\remote-admin-client.cmd" : "sh bin/remote-admin-client.sh")
+        + " conf\n";
+
+    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"
+        + "listprincs\n"
+        + "          List principals\n";
+
+    public static void main(String[] args) throws Exception {
+        AdminClient adminClient;
+
+        if (args.length < 1) {
+            System.err.println(USAGE);
+            System.exit(1);
+        }
+
+        String confDirPath = args[0];
+
+        File confFile = new File(confDirPath, "adminClient.conf");
+
+        final AdminConfig adminConfig = new AdminConfig();
+        adminConfig.addKrb5Config(confFile);
+
+        KdcConfig tmpKdcConfig = KdcUtil.getKdcConfig(new File(confDirPath));
+        if (tmpKdcConfig == null) {
+            tmpKdcConfig = new KdcConfig();
+        }
+
+        try {
+            Krb5Conf krb5Conf = new Krb5Conf(new File(confDirPath), tmpKdcConfig);
+            krb5Conf.initKrb5conf();
+        } catch (IOException e) {
+            throw new KrbException("Failed to make krb5.conf", e);
+        }
+
+        adminClient = new AdminClient(adminConfig);
+
+        File keytabFile = new File(adminConfig.getKeyTabFile());
+        if (keytabFile == null || !keytabFile.exists()) {
+            System.err.println("Need the valid keytab file value in conf file.");
+            return;
+        }
+
+        String adminRealm = adminConfig.getAdminRealm();
+
+        adminClient.setAdminRealm(adminRealm);
+        adminClient.setAllowTcp(true);
+        adminClient.setAllowUdp(false);
+        adminClient.setAdminTcpPort(adminConfig.getAdminPort());
+
+        adminClient.init();
+        System.out.println("admin init successful");
+
+        TransportPair tpair = null;
+        try {
+            tpair = AdminUtil.getTransportPair(adminClient.getSetting());
+        } catch (KrbException e) {
+            e.printStackTrace();
+        }
+        KrbNetwork network = new KrbNetwork();
+        network.setSocketTimeout(adminClient.getSetting().getTimeout());
+
+        try {
+            transport = network.connect(tpair);
+        } catch (IOException e) {
+            throw new KrbException("Failed to create transport", e);
+        }
+
+        String adminPrincipal = KrbUtil.makeKadminPrincipal(
+            adminClient.getSetting().getKdcRealm()).getName();
+        Subject subject = null;
+        try {
+            subject = AuthUtil.loginUsingKeytab(adminPrincipal,
+                new File(adminConfig.getKeyTabFile()));
+        } catch (LoginException e) {
+            e.printStackTrace();
+        }
+        Subject.doAs(subject, new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                try {
+
+                    Map<String, String> props = new HashMap<String, String>();
+                    props.put(Sasl.QOP, "auth-conf");
+                    props.put(Sasl.SERVER_AUTH, "true");
+                    SaslClient saslClient = null;
+                    try {
+                        String protocol = adminConfig.getProtocol();
+                        String serverName = adminConfig.getServerName();
+                        saslClient = Sasl.createSaslClient(new String[]{"GSSAPI"}, null,
+                            protocol, serverName, props, null);
+                    } catch (SaslException e) {
+                        e.printStackTrace();
+                    }
+                    if (saslClient == null) {
+                        throw new KrbException("Unable to find client implementation for: GSSAPI");
+                    }
+                    byte[] response = new byte[0];
+                    try {
+                        response = saslClient.hasInitialResponse()
+                            ? saslClient.evaluateChallenge(EMPTY) : EMPTY;
+                    } catch (SaslException e) {
+                        e.printStackTrace();
+                    }
+
+                    sendMessage(response, saslClient);
+
+                    ByteBuffer message = transport.receiveMessage();
+
+                    while (!saslClient.isComplete()) {
+                        int ssComplete = message.getInt();
+                        if (ssComplete == 0) {
+                            System.out.println("Sasl Server completed");
+                        }
+                        byte[] arr = new byte[message.remaining()];
+                        message.get(arr);
+                        byte[] challenge = saslClient.evaluateChallenge(arr);
+
+                        sendMessage(challenge, saslClient);
+
+                        if (!saslClient.isComplete()) {
+                            message = transport.receiveMessage();
+                        }
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                return null;
+            }
+        });
+
+        System.out.println("enter \"command\" to see legal commands.");
+
+        try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
+            String input = scanner.nextLine();
+
+            while (!(input.equals("quit") || input.equals("exit") || input.equals("q"))) {
+                excute(adminClient, input);
+                System.out.print(PROMPT);
+                input = scanner.nextLine();
+            }
+        }
+    }
+
+    private static void sendMessage(byte[] challenge, SaslClient saslClient)
+        throws SaslException {
+
+        // 4 is the head to go through network
+        ByteBuffer buffer = ByteBuffer.allocate(challenge.length + 8);
+        buffer.putInt(challenge.length + 4);
+        int scComplete = saslClient.isComplete() ? 0 : 1;
+
+        buffer.putInt(scComplete);
+        buffer.put(challenge);
+        buffer.flip();
+
+        try {
+            transport.sendMessage(buffer);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static void excute(AdminClient adminClient, String input) throws KrbException {
+        input = input.trim();
+        if (input.startsWith("command")) {
+            System.out.println(LEGAL_COMMANDS);
+            return;
+        }
+
+        RemoteCommand executor = null;
+
+        if (input.startsWith("add_principal")
+            || input.startsWith("addprinc")) {
+            executor = new RemoteAddPrincipalCommand(adminClient);
+        } else if (input.startsWith("delete_principal")
+            || input.startsWith("delprinc")) {
+            executor = new RemoteDeletePrincipalCommand(adminClient);
+        } else if (input.startsWith("rename_principal")
+            || input.startsWith("renprinc")) {
+            executor = new RemoteRenamePrincipalCommand(adminClient);
+        } else if (input.startsWith("list_principals")) {
+            executor = new RemoteGetprincsCommand(adminClient);
+        } else if (input.startsWith("listprincs")) {
+            executor = new RemotePrintUsageCommand();
+        } else {
+            System.out.println(LEGAL_COMMANDS);
+            return;
+        }
+        executor.execute(input);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteKadminImpl.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteKadminImpl.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteKadminImpl.java
deleted file mode 100644
index 16115d8..0000000
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteKadminImpl.java
+++ /dev/null
@@ -1,144 +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.kerb.admin;
-
-import org.apache.kerby.KOptions;
-import org.apache.kerby.kerberos.kerb.KrbException;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Server side admin facilities from remote, similar to MIT Kadmin remote mode.
- * It uses GSSAPI and XDR to communicate with remote KDC/kadmind to do the
- * requested operations. In the client side, it simply wraps and sends the
- * request info to the server kadmind side, and then unwraps the response for
- * the operation result.
- *
- * TO BE IMPLEMENTED.
- */
-public class RemoteKadminImpl implements Kadmin {
-
-    @Override
-    public String getKadminPrincipal() {
-        return null;
-    }
-
-    @Override
-    public void addPrincipal(String principal) throws KrbException {
-
-    }
-
-    @Override
-    public void addPrincipal(String principal,
-                             KOptions kOptions) throws KrbException {
-
-    }
-
-    @Override
-    public void addPrincipal(String principal,
-                             String password) throws KrbException {
-
-    }
-
-    @Override
-    public void addPrincipal(String principal, String password,
-                             KOptions kOptions) throws KrbException {
-
-    }
-
-    @Override
-    public void exportKeytab(File keytabFile,
-                             String principal) throws KrbException {
-
-    }
-
-    @Override
-    public void exportKeytab(File keytabFile,
-                             List<String> principals) throws KrbException {
-
-    }
-
-    @Override
-    public void exportKeytab(File keytabFile) throws KrbException {
-
-    }
-
-    @Override
-    public void removeKeytabEntriesOf(File keytabFile,
-                                      String principal) throws KrbException {
-
-    }
-
-    @Override
-    public void removeKeytabEntriesOf(File keytabFile, String principal,
-                                      int kvno) throws KrbException {
-
-    }
-
-    @Override
-    public void removeOldKeytabEntriesOf(File keytabFile,
-                                         String principal) throws KrbException {
-
-    }
-
-    @Override
-    public void deletePrincipal(String principal) throws KrbException {
-
-    }
-
-    @Override
-    public void modifyPrincipal(String principal,
-                                KOptions kOptions) throws KrbException {
-
-    }
-
-    @Override
-    public void renamePrincipal(String oldPrincipalName,
-                                String newPrincipalName) throws KrbException {
-
-    }
-
-    @Override
-    public List<String> getPrincipals() throws KrbException {
-        return null;
-    }
-
-    @Override
-    public List<String> getPrincipals(String globString) throws KrbException {
-        return null;
-    }
-
-    @Override
-    public void changePassword(String principal,
-                               String newPassword) throws KrbException {
-
-    }
-
-    @Override
-    public void updateKeys(String principal) throws KrbException {
-
-    }
-
-    @Override
-    public void release() throws KrbException {
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/Kadmin.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/Kadmin.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/Kadmin.java
new file mode 100644
index 0000000..8f95b37
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/Kadmin.java
@@ -0,0 +1,207 @@
+/**
+ *  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.kerb.admin.kadmin;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Server side admin facilities from remote, similar to MIT kadmin remote mode.
+ */
+public interface Kadmin {
+
+    /**
+     * Get the kadmin principal name.
+     *
+     * @return The kadmin principal name.
+     */
+    String getKadminPrincipal();
+
+    /**
+     * Add principal to backend.
+     *
+     * @param principal The principal to be added into backend
+     * @throws KrbException e
+     */
+    void addPrincipal(String principal) throws KrbException;
+
+    /**
+     * Add principal to backend.
+     *
+     * @param principal The principal to be added into backend
+     * @param kOptions The KOptions with principal info
+     * @throws KrbException e
+     */
+    void addPrincipal(String principal, KOptions kOptions) throws KrbException;
+
+    /**
+     * Add principal to backend.
+     *
+     * @param principal The principal to be added into backend
+     * @param password  The password to create encryption key
+     * @throws KrbException e
+     */
+    void addPrincipal(String principal, String password) throws KrbException;
+
+    /**
+     * Add principal to backend.
+     *
+     * @param principal The principal to be added into backend
+     * @param password  The password to create encryption key
+     * @param kOptions  The KOptions with principal info
+     * @throws KrbException e
+     */
+    void addPrincipal(String principal, String password,
+                      KOptions kOptions) throws KrbException;
+
+    /**
+     * Export all the keys of the specified principal into the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param principal The principal name
+     * @throws KrbException e
+     */
+    void exportKeytab(File keytabFile, String principal) throws KrbException;
+
+    /**
+     * Export all the keys of the specified principals into the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param principals The principal names
+     * @throws KrbException e
+     */
+    void exportKeytab(File keytabFile,
+                      List<String> principals) throws KrbException;
+
+    /**
+     * Export all identity keys to the specified keytab file.
+     *
+     * @param keytabFile The keytab file
+     * @throws KrbException e
+     */
+    void exportKeytab(File keytabFile) throws KrbException;
+
+    /**
+     * Remove all the keys of the specified principal in the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param principal The principal name
+     * @throws KrbException e
+     */
+    void removeKeytabEntriesOf(File keytabFile, String principal)
+            throws KrbException;
+
+    /**
+     * Remove all the keys of the specified principal with specified kvno
+     * in the specified keytab file.
+     *
+     * @param keytabFile The keytab file
+     * @param principal The principal name
+     * @param kvno The kvno
+     * @throws KrbException e
+     */
+    void removeKeytabEntriesOf(File keytabFile, String principal, int kvno)
+            throws KrbException;
+
+    /**
+     * Remove all the old keys of the specified principal
+     * in the specified keytab file.
+     *
+     * @param keytabFile The keytab file
+     * @param principal The principal name
+     * @throws KrbException e
+     */
+    void removeOldKeytabEntriesOf(File keytabFile, String principal)
+            throws KrbException;
+
+    /**
+     * Delete the principal in backend.
+     *
+     * @param principal The principal to be deleted from backend
+     * @throws KrbException e
+     */
+    void deletePrincipal(String principal) throws KrbException;
+
+    /**
+     * Modify the principal with KOptions.
+     *
+     * @param principal The principal to be modified
+     * @param kOptions The KOptions with changed principal info
+     * @throws KrbException e
+     */
+    void modifyPrincipal(String principal, KOptions kOptions) throws KrbException;
+
+    /**
+     * Rename the principal.
+     *
+     * @param oldPrincipalName The original principal name
+     * @param newPrincipalName The new principal name
+     * @throws KrbException e
+     */
+    void renamePrincipal(String oldPrincipalName,
+                         String newPrincipalName) throws KrbException;
+
+    /**
+     * Get all the principal names from backend.
+     *
+     * @return principal list
+     * @throws KrbException e
+     */
+    List<String> getPrincipals() throws KrbException;
+
+    /**
+     * Get all the principal names that meets the pattern
+     *
+     * @param globString The glob string for matching
+     * @return Principal names
+     * @throws KrbException e
+     */
+    List<String> getPrincipals(String globString) throws KrbException;
+
+    /**
+     * Change the password of specified principal.
+     *
+     * @param principal The principal to be updated password
+     * @param newPassword The new password
+     * @throws KrbException e
+     */
+    void changePassword(String principal, String newPassword) throws KrbException;
+
+    /**
+     * Update the random keys of specified principal.
+     *
+     * @param principal The principal to be updated keys
+     * @throws KrbException e
+     */
+    void updateKeys(String principal) throws KrbException;
+
+    /**
+     * Release any resources associated.
+     *
+     * @throws KrbException e
+     */
+    void release() throws KrbException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/KadminOption.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/KadminOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/KadminOption.java
new file mode 100644
index 0000000..f6caa87
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/KadminOption.java
@@ -0,0 +1,76 @@
+/**
+ *  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.kerb.admin.kadmin;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+public enum KadminOption implements KOption {
+    NONE(null),
+    EXPIRE(new KOptionInfo("-expire", "expire time", KOptionType.DATE)),
+    DISABLED(new KOptionInfo("-disabled", "disabled", KOptionType.BOOL)),
+    LOCKED(new KOptionInfo("-locked", "locked", KOptionType.BOOL)),
+    FORCE(new KOptionInfo("-force", "force", KOptionType.NOV)),
+    KVNO(new KOptionInfo("-kvno", "initial key version number", KOptionType.INT)),
+    SIZE(new KOptionInfo("-size", "principal's numbers", KOptionType.STR)),
+    PW(new KOptionInfo("-pw", "password", KOptionType.STR)),
+    RANDKEY(new KOptionInfo("-randkey", "random key", KOptionType.NOV)),
+    KEEPOLD(new KOptionInfo("-keepold", "keep old passowrd", KOptionType.NOV)),
+    KEYSALTLIST(new KOptionInfo("-e", "key saltlist", KOptionType.STR)),
+    K(new KOptionInfo("-k", "keytab file path", KOptionType.STR)),
+    KEYTAB(new KOptionInfo("-keytab", "keytab file path", KOptionType.STR)),
+    CCACHE(new KOptionInfo("-c", "credentials cache", KOptionType.FILE));
+
+    private final KOptionInfo optionInfo;
+
+    KadminOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static KadminOption fromName(String name) {
+        if (name != null) {
+            for (KadminOption ko : values()) {
+                if (ko.optionInfo != null
+                        && ko.optionInfo.getName().equals(name)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+
+    public static KadminOption fromOptionName(String optionName) {
+        if (optionName != null) {
+            for (KadminOption ko : values()) {
+                if (ko.optionInfo != null
+                    && ko.optionInfo.getName().equals(optionName)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java
new file mode 100644
index 0000000..f78ec45
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java
@@ -0,0 +1,309 @@
+/**
+ *  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.kerb.admin.kadmin.local;
+
+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.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.keytab.KeytabEntry;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * LocalKadmin utilities.
+ */
+public final class AdminHelper {
+
+    private AdminHelper() { }
+
+    /**
+     * Export all the keys of the specified principal into the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param identity  The identity
+     * @throws KrbException
+     */
+    static void exportKeytab(File keytabFile, KrbIdentity identity)
+            throws KrbException {
+
+        Keytab keytab = createOrLoadKeytab(keytabFile);
+
+        exportToKeytab(keytab, identity);
+
+        storeKeytab(keytab, keytabFile);
+    }
+
+    /**
+     * Export all the keys of the specified principal into the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param identities  Identities to export to keytabFile
+     * @throws KrbException
+     */
+    static void exportKeytab(File keytabFile, List<KrbIdentity> identities)
+            throws KrbException {
+
+        Keytab keytab = createOrLoadKeytab(keytabFile);
+
+        for (KrbIdentity identity : identities) {
+            exportToKeytab(keytab, identity);
+        }
+
+        storeKeytab(keytab, keytabFile);
+    }
+
+    /**
+     * Load keytab from keytab file.
+     *
+     * @param keytabFile The keytab file
+     * @return The keytab load from keytab file
+     * @throws KrbException
+     */
+    static Keytab loadKeytab(File keytabFile) throws KrbException {
+        Keytab keytab;
+        try {
+            keytab = Keytab.loadKeytab(keytabFile);
+        } catch (IOException e) {
+            throw new KrbException("Failed to load keytab", e);
+        }
+
+        return keytab;
+    }
+
+    /**
+     * If keytab file does not exist, create a new keytab,
+     * otherwise load keytab from keytab file.
+     *
+     * @param keytabFile The keytab file
+     * @return The keytab load from keytab file
+     * @throws KrbException
+     */
+    static Keytab createOrLoadKeytab(File keytabFile) throws KrbException {
+
+        Keytab keytab;
+        try {
+            if (!keytabFile.exists()) {
+                if (!keytabFile.createNewFile()) {
+                    throw new KrbException("Failed to create keytab file "
+                            + keytabFile.getAbsolutePath());
+                }
+                keytab = new Keytab();
+            } else {
+                keytab = Keytab.loadKeytab(keytabFile);
+            }
+        } catch (IOException e) {
+            throw new KrbException("Failed to load or create keytab", e);
+        }
+
+        return keytab;
+    }
+
+    /**
+     * Export all the keys of the specified identity into the keytab.
+     *
+     * @param keytab The keytab
+     * @param identity  The identity
+     * @throws KrbException
+     */
+    static void exportToKeytab(Keytab keytab, KrbIdentity identity)
+        throws KrbException {
+
+        //Add principal to keytab.
+        PrincipalName principal = identity.getPrincipal();
+        KerberosTime timestamp = KerberosTime.now();
+        for (EncryptionType encType : identity.getKeys().keySet()) {
+            EncryptionKey ekey = identity.getKeys().get(encType);
+            int keyVersion = ekey.getKvno();
+            keytab.addEntry(new KeytabEntry(principal, timestamp, keyVersion, ekey));
+        }
+    }
+
+    /**
+     * Store the keytab to keytab file.
+     *
+     * @param keytab   The keytab
+     * @param keytabFile The keytab file
+     * @throws KrbException
+     */
+    static void storeKeytab(Keytab keytab, File keytabFile) throws KrbException {
+        try {
+            keytab.store(keytabFile);
+        } catch (IOException e) {
+            throw new KrbException("Failed to store keytab", e);
+        }
+    }
+
+    /**
+     * Remove all the keys of the specified principal in the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param principalName  The principal name
+     * @throws KrbException
+     */
+    static void removeKeytabEntriesOf(File keytabFile,
+                                             String principalName) throws KrbException {
+        Keytab keytab = loadKeytab(keytabFile);
+
+        keytab.removeKeytabEntries(new PrincipalName(principalName));
+
+        storeKeytab(keytab, keytabFile);
+    }
+
+    /**
+     * Remove all the keys of the specified principal with specified kvno
+     * in the specified keytab file.
+     *
+     * @param keytabFile The keytab file
+     * @param principalName  The principal name
+     * @param kvno The kvno
+     * @throws KrbException
+     */
+    static void removeKeytabEntriesOf(File keytabFile,
+                                      String principalName, int kvno) throws KrbException {
+        Keytab keytab = loadKeytab(keytabFile);
+
+        keytab.removeKeytabEntries(new PrincipalName(principalName), kvno);
+
+        storeKeytab(keytab, keytabFile);
+    }
+
+    /**
+     * Remove all the old keys of the specified principal
+     * in the specified keytab file.
+     *
+     * @param keytabFile The keytab file
+     * @param principalName  The principal name
+     * @throws KrbException
+     */
+    static void removeOldKeytabEntriesOf(File keytabFile,
+                                                String principalName) throws KrbException {
+        Keytab keytab = loadKeytab(keytabFile);
+
+        List<KeytabEntry> entries = keytab.getKeytabEntries(
+                new PrincipalName(principalName));
+
+        int maxKvno = 0;
+        for (KeytabEntry entry : entries) {
+            if (maxKvno < entry.getKvno()) {
+                maxKvno = entry.getKvno();
+            }
+        }
+
+        for (KeytabEntry entry : entries) {
+            if (entry.getKvno() < maxKvno) {
+                keytab.removeKeytabEntry(entry);
+            }
+        }
+
+        storeKeytab(keytab, keytabFile);
+    }
+
+    /**
+     * Create principal.
+     *
+     * @param principal The principal name to be created
+     * @param kOptions  The KOptions with principal info
+     */
+    static KrbIdentity createIdentity(String principal, KOptions kOptions)
+        throws KrbException {
+        KrbIdentity kid = new KrbIdentity(principal);
+        kid.setCreatedTime(KerberosTime.now());
+        if (kOptions.contains(KadminOption.EXPIRE)) {
+            Date date = kOptions.getDateOption(KadminOption.EXPIRE);
+            kid.setExpireTime(new KerberosTime(date.getTime()));
+        } else {
+            kid.setExpireTime(new KerberosTime(253402300799900L));
+        }
+        if (kOptions.contains(KadminOption.KVNO)) {
+            kid.setKeyVersion(kOptions.getIntegerOption(KadminOption.KVNO));
+        } else {
+            kid.setKeyVersion(1);
+        }
+        kid.setDisabled(false);
+        kid.setLocked(false);
+
+        return kid;
+    }
+
+    /**
+     * Modify the principal with KOptions.
+     *
+     * @param identity The identity to be modified
+     * @param kOptions  The KOptions with changed principal info
+     * @throws KrbException
+     */
+    static void updateIdentity(KrbIdentity identity, KOptions kOptions) {
+        if (kOptions.contains(KadminOption.EXPIRE)) {
+            Date date = kOptions.getDateOption(KadminOption.EXPIRE);
+            identity.setExpireTime(new KerberosTime(date.getTime()));
+        }
+        if (kOptions.contains(KadminOption.DISABLED)) {
+            identity.setDisabled(kOptions.getBooleanOption(KadminOption.DISABLED, false));
+        }
+        if (kOptions.contains(KadminOption.LOCKED)) {
+            identity.setLocked(kOptions.getBooleanOption(KadminOption.LOCKED, false));
+        }
+    }
+
+    /**
+     * Get all the Pattern for matching from glob string.
+     * The glob string can contain "." "*" and "[]"
+     *
+     * @param globString The glob string for matching
+     * @return pattern
+     * @throws KrbException
+     */
+    static Pattern getPatternFromGlobPatternString(String globString) throws KrbException {
+        if (globString == null || globString.equals("")) {
+            return null;
+        }
+        if (!Pattern.matches("^[0-9A-Za-z._/@*?\\[\\]\\-]+$", globString)) {
+            throw new KrbException("Glob pattern string contains invalid character");
+        }
+
+        String patternString = globString;
+        patternString = patternString.replaceAll("\\.", "\\\\.");
+        patternString = patternString.replaceAll("\\?", ".");
+        patternString = patternString.replaceAll("\\*", ".*");
+        patternString = "^" + patternString + "$";
+
+        Pattern pt;
+        try {
+            pt = Pattern.compile(patternString);
+        } catch (PatternSyntaxException e) {
+            throw new KrbException("Invalid glob pattern string");
+        }
+        return pt;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadmin.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadmin.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadmin.java
new file mode 100644
index 0000000..5fd2d0d
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadmin.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.kerberos.kerb.admin.kadmin.local;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.Kadmin;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+
+/**
+ * Server side admin facilities for local, similar to MIT kadmin local mode. It
+ * may be not accurate regarding 'local' because, if the identity backend itself
+ * is supported to be accessed from remote, it won't have to be remote; but if
+ * not, then it must be local to the KDC admin bounded with the local backend.
+ *
+ * Note, suitable with Kerby AdminServerImpl based KDCs like Kerby KDC.
+ */
+public interface LocalKadmin extends Kadmin {
+
+    /**
+     * Check the built-in principals, will throw KrbException if not exist.
+     * @throws KrbException e
+     */
+    void checkBuiltinPrincipals() throws KrbException;
+
+    /**
+     * Create build-in principals.
+     * @throws KrbException e
+     */
+    void createBuiltinPrincipals() throws KrbException;
+
+    /**
+     * Delete build-in principals.
+     * @throws KrbException e
+     */
+    void deleteBuiltinPrincipals() throws KrbException;
+
+    /**
+     * Get kdc config.
+     *
+     * @return The kdc config.
+     */
+    KdcConfig getKdcConfig();
+
+    /**
+     * Get backend config.
+     *
+     * @return The backend config.
+     */
+    BackendConfig getBackendConfig();
+
+    /**
+     * Get identity backend.
+     *
+     * @return IdentityBackend
+     */
+    IdentityBackend getIdentityBackend();
+
+    /**
+     * Get the identity from backend.
+     *
+     * @param principalName The principal name
+     * @return identity
+     * @throws KrbException e
+     */
+    KrbIdentity getPrincipal(String principalName) throws KrbException;
+
+    int size() throws KrbException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadminImpl.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadminImpl.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadminImpl.java
new file mode 100644
index 0000000..80fc10b
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadminImpl.java
@@ -0,0 +1,407 @@
+/**
+ *  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.kerb.admin.kadmin.local;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcSetting;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.kerberos.kerb.server.ServerSetting;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.common.KrbUtil;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The implementation of admin side admin facilities for local mode.
+ */
+public class LocalKadminImpl implements LocalKadmin {
+    private static final Logger LOG = LoggerFactory.getLogger(LocalKadminImpl.class);
+
+    private final ServerSetting serverSetting;
+    private final IdentityBackend backend;
+
+    /**
+     * Construct with prepared AdminServerConfig and BackendConfig.
+     *
+     * @param kdcConfig     The kdc config
+     * @param backendConfig The backend config
+     * @throws KrbException e
+     */
+    public LocalKadminImpl(KdcConfig kdcConfig,
+                           BackendConfig backendConfig) throws KrbException {
+        this.backend = KdcUtil.getBackend(backendConfig);
+        this.serverSetting = new KdcSetting(kdcConfig, backendConfig);
+    }
+
+    //
+    public LocalKadminImpl(ServerSetting serverSetting) throws KrbException {
+        this.backend = KdcUtil.getBackend(serverSetting.getBackendConfig());
+        this.serverSetting = serverSetting;
+    }
+
+    /**
+     * Construct with prepared conf dir.
+     *
+     * @param confDir The path of conf dir
+     * @throws KrbException e
+     */
+    public LocalKadminImpl(File confDir) throws KrbException {
+        KdcConfig tmpKdcConfig = KdcUtil.getKdcConfig(confDir);
+        if (tmpKdcConfig == null) {
+            tmpKdcConfig = new KdcConfig();
+        }
+
+        BackendConfig tmpBackendConfig = KdcUtil.getBackendConfig(confDir);
+        if (tmpBackendConfig == null) {
+            tmpBackendConfig = new BackendConfig();
+        }
+
+        this.serverSetting = new KdcSetting(tmpKdcConfig, tmpBackendConfig);
+
+        backend = KdcUtil.getBackend(tmpBackendConfig);
+    }
+
+    /**
+     * Construct with prepared AdminServerSetting and Backend.
+     *
+     * @param kdcSetting The kdc setting
+     * @param backend    The identity backend
+     */
+    public LocalKadminImpl(KdcSetting kdcSetting, IdentityBackend backend) {
+        this.serverSetting = kdcSetting;
+        this.backend = backend;
+    }
+
+    /**
+     * Get the tgs principal name.
+     */
+    private String getTgsPrincipal() {
+        return KrbUtil.makeTgsPrincipal(serverSetting.getKdcRealm()).getName();
+    }
+
+    @Override
+    public String getKadminPrincipal() {
+        return KrbUtil.makeKadminPrincipal(serverSetting.getKdcRealm()).getName();
+    }
+
+    @Override
+    public void checkBuiltinPrincipals() throws KrbException {
+        String tgsPrincipal = getTgsPrincipal();
+        String kadminPrincipal = getKadminPrincipal();
+        if (backend.getIdentity(tgsPrincipal) == null
+            || backend.getIdentity(kadminPrincipal) == null) {
+            String errorMsg = "The built-in principals do not exist in backend,"
+                + " please run the kdcinit tool.";
+            LOG.error(errorMsg);
+            throw new KrbException(errorMsg);
+        }
+    }
+
+    @Override
+    public void createBuiltinPrincipals() throws KrbException {
+        String tgsPrincipal = getTgsPrincipal();
+        if (backend.getIdentity(tgsPrincipal) == null) {
+            addPrincipal(tgsPrincipal);
+        } else {
+            String errorMsg = "The tgs principal already exists in backend.";
+            LOG.error(errorMsg);
+            throw new KrbException(errorMsg);
+        }
+
+        String kadminPrincipal = getKadminPrincipal();
+        if (backend.getIdentity(kadminPrincipal) == null) {
+            addPrincipal(kadminPrincipal);
+        } else {
+            String errorMsg = "The kadmin principal already exists in backend.";
+            LOG.error(errorMsg);
+            throw new KrbException(errorMsg);
+        }
+    }
+
+    @Override
+    public void deleteBuiltinPrincipals() throws KrbException {
+        deletePrincipal(getTgsPrincipal());
+        deletePrincipal(getKadminPrincipal());
+    }
+
+    @Override
+    public KdcConfig getKdcConfig() {
+        return serverSetting.getKdcConfig();
+    }
+
+    @Override
+    public BackendConfig getBackendConfig() {
+        return serverSetting.getBackendConfig();
+    }
+
+    @Override
+    public IdentityBackend getIdentityBackend() {
+        return backend;
+    }
+
+    @Override
+    public void addPrincipal(String principal) throws KrbException {
+        principal = fixPrincipal(principal);
+        addPrincipal(principal, new KOptions());
+    }
+
+    @Override
+    public void addPrincipal(String principal, KOptions kOptions)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        KrbIdentity identity = AdminHelper.createIdentity(principal, kOptions);
+        List<EncryptionKey> keys = EncryptionUtil.generateKeys(
+                getKdcConfig().getEncryptionTypes());
+        identity.addKeys(keys);
+        backend.addIdentity(identity);
+    }
+
+    @Override
+    public void addPrincipal(String principal, String password)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        addPrincipal(principal, password, new KOptions());
+    }
+
+    @Override
+    public void addPrincipal(String principal, String password, KOptions kOptions)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        KrbIdentity identity = AdminHelper.createIdentity(principal, kOptions);
+        List<EncryptionKey> keys = EncryptionUtil.generateKeys(principal, password,
+                getKdcConfig().getEncryptionTypes());
+        identity.addKeys(keys);
+        backend.addIdentity(identity);
+    }
+
+    @Override
+    public void exportKeytab(File keytabFile, String principal)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        List<String> principals = new ArrayList<>(1);
+        principals.add(principal);
+        exportKeytab(keytabFile, principals);
+    }
+
+    @Override
+    public void exportKeytab(File keytabFile, List<String> principals)
+            throws KrbException {
+        //Get Identity
+        List<KrbIdentity> identities = new LinkedList<>();
+        for (String principal : principals) {
+            KrbIdentity identity = backend.getIdentity(principal);
+            if (identity == null) {
+                throw new KrbException("Can not find the identity for pincipal "
+                        + principal);
+            }
+            identities.add(identity);
+        }
+
+        AdminHelper.exportKeytab(keytabFile, identities);
+    }
+
+    @Override
+    public void exportKeytab(File keytabFile) throws KrbException {
+        Keytab keytab = AdminHelper.createOrLoadKeytab(keytabFile);
+
+        Iterable<String> principals = backend.getIdentities();
+        for (String principal : principals) {
+            KrbIdentity identity = backend.getIdentity(principal);
+            if (identity != null) {
+                AdminHelper.exportToKeytab(keytab, identity);
+            }
+        }
+
+        AdminHelper.storeKeytab(keytab, keytabFile);
+    }
+
+    @Override
+    public void removeKeytabEntriesOf(File keytabFile, String principal)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        AdminHelper.removeKeytabEntriesOf(keytabFile, principal);
+    }
+
+    @Override
+    public void removeKeytabEntriesOf(File keytabFile, String principal, int kvno)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        AdminHelper.removeKeytabEntriesOf(keytabFile, principal, kvno);
+    }
+
+    @Override
+    public void removeOldKeytabEntriesOf(File keytabFile, String principal)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        AdminHelper.removeOldKeytabEntriesOf(keytabFile, principal);
+    }
+
+    @Override
+    public void deletePrincipal(String principal) throws KrbException {
+        principal = fixPrincipal(principal);
+        backend.deleteIdentity(principal);
+    }
+
+    @Override
+    public void modifyPrincipal(String principal, KOptions kOptions)
+            throws KrbException {
+        principal = fixPrincipal(principal);
+        KrbIdentity identity = backend.getIdentity(principal);
+        if (identity == null) {
+            throw new KrbException("Principal \""
+                    + principal + "\" does not exist.");
+        }
+        AdminHelper.updateIdentity(identity, kOptions);
+        backend.updateIdentity(identity);
+    }
+
+    @Override
+    public void renamePrincipal(String oldPrincipalName, String newPrincipalName)
+            throws KrbException {
+        oldPrincipalName = fixPrincipal(oldPrincipalName);
+        newPrincipalName = fixPrincipal(newPrincipalName);
+        KrbIdentity oldIdentity = backend.getIdentity(newPrincipalName);
+        if (oldIdentity != null) {
+            throw new KrbException("Principal \""
+                    + oldIdentity.getPrincipalName() + "\" is already exist.");
+        }
+        KrbIdentity identity = backend.getIdentity(oldPrincipalName);
+        if (identity == null) {
+            throw new KrbException("Principal \""
+                    + oldPrincipalName + "\" does not exist.");
+        }
+        backend.deleteIdentity(oldPrincipalName);
+
+        identity.setPrincipalName(newPrincipalName);
+        identity.setPrincipal(new PrincipalName(newPrincipalName));
+        backend.addIdentity(identity);
+    }
+
+    @Override
+    public KrbIdentity getPrincipal(String principalName) throws KrbException {
+        KrbIdentity identity = backend.getIdentity(principalName);
+        return identity;
+    }
+
+    @Override
+    public List<String> getPrincipals() throws KrbException {
+        Iterable<String> principalNames = backend.getIdentities();
+        List<String> principalList = new LinkedList<>();
+        Iterator<String> iterator = principalNames.iterator();
+        while (iterator.hasNext()) {
+            principalList.add(iterator.next());
+        }
+        return principalList;
+    }
+
+    @Override
+    public List<String> getPrincipals(String globString) throws KrbException {
+        Pattern pt = AdminHelper.getPatternFromGlobPatternString(globString);
+        if (pt == null) {
+            return getPrincipals();
+        }
+
+        Boolean containsAt = pt.pattern().indexOf('@') != -1;
+        List<String> result = new LinkedList<>();
+
+        List<String> principalNames = getPrincipals();
+        for (String principal: principalNames) {
+            String toMatch = containsAt ? principal : principal.split("@")[0];
+            Matcher m = pt.matcher(toMatch);
+            if (m.matches()) {
+                result.add(principal);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void changePassword(String principal,
+                               String newPassword) throws KrbException {
+        principal = fixPrincipal(principal);
+        KrbIdentity identity = backend.getIdentity(principal);
+        if (identity == null) {
+            throw new KrbException("Principal " + principal
+                    + "was not found. Please check the input and try again");
+        }
+        List<EncryptionKey> keys = EncryptionUtil.generateKeys(principal, newPassword,
+                getKdcConfig().getEncryptionTypes());
+        identity.addKeys(keys);
+
+        backend.updateIdentity(identity);
+    }
+
+    @Override
+    public void updateKeys(String principal) throws KrbException {
+        principal = fixPrincipal(principal);
+        KrbIdentity identity = backend.getIdentity(principal);
+        if (identity == null) {
+            throw new KrbException("Principal " + principal
+                    + "was not found. Please check the input and try again");
+        }
+        List<EncryptionKey> keys = EncryptionUtil.generateKeys(
+                getKdcConfig().getEncryptionTypes());
+        identity.addKeys(keys);
+        backend.updateIdentity(identity);
+    }
+
+    @Override
+    public void release() throws KrbException {
+        if (backend != null) {
+            backend.stop();
+        }
+    }
+
+    /**
+     * get size of principal
+     */
+    @Override
+    public int size() throws KrbException {
+        return this.getPrincipals().size();
+    }
+
+    /**
+     * Fix principal name, making it complete.
+     *
+     * @param principal The principal name
+     */
+    private String fixPrincipal(String principal) {
+        if (!principal.contains("@")) {
+            principal += "@" + serverSetting.getKdcRealm();
+        }
+        return principal;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminClient.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminClient.java
new file mode 100644
index 0000000..01c336d
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminClient.java
@@ -0,0 +1,204 @@
+/**
+ *  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.kerb.admin.kadmin.remote;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.Kadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl.DefaultInternalAdminClient;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl.InternalAdminClient;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * A Admin client API for applications to interact with Admin Server
+ */
+public class AdminClient {
+
+    private final AdminConfig adminConfig;
+    private final KOptions commonOptions;
+    private final AdminSetting adminSetting;
+
+    private InternalAdminClient innerClient;
+
+    /**
+     * Default constructor.
+     * @throws KrbException e
+     */
+    public AdminClient() throws KrbException {
+        this.adminConfig = AdminUtil.getDefaultConfig();
+        this.commonOptions = new KOptions();
+        this.adminSetting = new AdminSetting(commonOptions, adminConfig);
+    }
+
+    /**
+     * Construct with prepared AdminConfig.
+     * @param adminConfig The krb config
+     */
+    public AdminClient(AdminConfig adminConfig) {
+        this.adminConfig = adminConfig;
+        this.commonOptions = new KOptions();
+        this.adminSetting = new AdminSetting(commonOptions, adminConfig);
+    }
+
+    /**
+     * Constructor with conf dir
+     * @param confDir The conf dir
+     * @throws KrbException e
+     */
+    public AdminClient(File confDir) throws KrbException {
+        this.commonOptions = new KOptions();
+        this.adminConfig = AdminUtil.getConfig(confDir);
+        this.adminSetting = new AdminSetting(commonOptions, adminConfig);
+    }
+
+    /**
+     * Constructor with prepared AdminClient.
+     * @param krbClient The krb client
+     */
+    public AdminClient(AdminClient krbClient) {
+        this.commonOptions = krbClient.commonOptions;
+        this.adminConfig = krbClient.adminConfig;
+        this.adminSetting = krbClient.adminSetting;
+        this.innerClient = krbClient.innerClient;
+    }
+
+    /**
+     * Set KDC realm for ticket request
+     * @param realm The realm
+     */
+    public void setAdminRealm(String realm) {
+        commonOptions.add(AdminOption.ADMIN_REALM, realm);
+    }
+
+    public void setKeyTabFile(File file) {
+        commonOptions.add(AdminOption.KEYTAB_FILE, file);
+    }
+
+    /**
+     * Set Admin Server host.
+     * @param kdcHost The kdc host
+     */
+    public void setKdcHost(String kdcHost) {
+        commonOptions.add(AdminOption.ADMIN_HOST, kdcHost);
+    }
+
+    /**
+     * Set Admin Server tcp port.
+     * @param kdcTcpPort The kdc tcp port
+     */
+    public void setAdminTcpPort(int kdcTcpPort) {
+        if (kdcTcpPort < 1) {
+            throw new IllegalArgumentException("Invalid port");
+        }
+        commonOptions.add(AdminOption.ADMIN_TCP_PORT, kdcTcpPort);
+        setAllowTcp(true);
+    }
+
+    /**
+     * Set to allow UDP or not.
+     * @param allowUdp true if allow udp
+     */
+    public void setAllowUdp(boolean allowUdp) {
+        commonOptions.add(AdminOption.ALLOW_UDP, allowUdp);
+    }
+
+    /**
+     * Set to allow TCP or not.
+     * @param allowTcp true if allow tcp
+     */
+    public void setAllowTcp(boolean allowTcp) {
+        commonOptions.add(AdminOption.ALLOW_TCP, allowTcp);
+    }
+
+    /**
+     * Set Admin Server udp port. Only makes sense when allowUdp is set.
+     * @param adminUdpPort The kdc udp port
+     */
+    public void setAdminUdpPort(int adminUdpPort) {
+        if (adminUdpPort < 1) {
+            throw new IllegalArgumentException("Invalid port");
+        }
+        commonOptions.add(AdminOption.ADMIN_UDP_PORT, adminUdpPort);
+        setAllowUdp(true);
+    }
+
+    /**
+     * Set time out for connection
+     * @param timeout in seconds
+     */
+    public void setTimeout(int timeout) {
+        commonOptions.add(AdminOption.CONN_TIMEOUT, timeout);
+    }
+
+    /**
+     * Init the client.
+     * @throws KrbException e
+     */
+    public void init() throws KrbException {
+        innerClient = new DefaultInternalAdminClient(adminSetting);
+        innerClient.init();
+    }
+
+    /**
+     * Get krb client settings from options and configs.
+     * @return setting
+     */
+    public AdminSetting getSetting() {
+        return adminSetting;
+    }
+
+    public AdminConfig getAdminConfig() {
+        return adminConfig;
+    }
+
+    public void requestAddPrincipal(String principal) throws KrbException {
+        Kadmin remote = new RemoteKadminImpl(innerClient);
+        remote.addPrincipal(principal);
+    }
+
+    public void requestAddPrincipal(String principal, String password) throws KrbException {
+        Kadmin remote = new RemoteKadminImpl(innerClient);
+        remote.addPrincipal(principal, password);
+    }
+
+    public void requestDeletePrincipal(String principal) throws KrbException {
+        Kadmin remote = new RemoteKadminImpl(innerClient);
+        remote.deletePrincipal(principal);
+    }
+
+    public void requestRenamePrincipal(String oldPrincipal, String newPrincipal) throws KrbException {
+        Kadmin remote = new RemoteKadminImpl(innerClient);
+        remote.renamePrincipal(oldPrincipal, newPrincipal);
+    }
+
+    public List<String> requestGetprincs() throws KrbException {
+        Kadmin remote = new RemoteKadminImpl(innerClient);
+        List<String> principalLists = remote.getPrincipals();
+        return principalLists;
+    }
+
+    public List<String> requestGetprincsWithExp(String exp) throws KrbException {
+        Kadmin remote = new RemoteKadminImpl(innerClient);
+        List<String> principalLists = remote.getPrincipals(exp);
+        return principalLists;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfig.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfig.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfig.java
new file mode 100644
index 0000000..e2e6443
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfig.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.kerberos.kerb.admin.kadmin.remote;
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+/**
+ * Kerb client side configuration API.
+ */
+public class AdminConfig extends Krb5Conf {
+    private static final String LIBDEFAULT = "libdefaults";
+
+    public boolean enableDebug() {
+        return getBoolean(AdminConfigKey.KRB_DEBUG, true, LIBDEFAULT);
+    }
+
+    /**
+     * Get KDC host name
+     *
+     * @return The kdc host
+     */
+    public String getAdminHost() {
+        return getString(
+            AdminConfigKey.ADMIN_HOST, true, LIBDEFAULT);
+    }
+
+    /**
+     * Get KDC port, as both TCP and UDP ports
+     *
+     * @return The kdc host
+     */
+    public int getAdminPort() {
+        Integer kdcPort = getInt(AdminConfigKey.ADMIN_PORT, true, LIBDEFAULT);
+        if (kdcPort != null) {
+            return kdcPort.intValue();
+        }
+        return -1;
+    }
+
+    /**
+     * Get KDC TCP port
+     *
+     * @return The kdc tcp port
+     */
+    public int getAdminTcpPort() {
+        Integer kdcPort = getInt(AdminConfigKey.ADMIN_TCP_PORT, true, LIBDEFAULT);
+        if (kdcPort != null && kdcPort > 0) {
+            return kdcPort.intValue();
+        }
+        return getAdminPort();
+    }
+
+    /**
+     * Is to allow UDP for KDC
+     *
+     * @return true to allow UDP, false otherwise
+     */
+    public boolean allowUdp() {
+        return getBoolean(AdminConfigKey.ADMIN_ALLOW_UDP, true, LIBDEFAULT)
+                || getInt(AdminConfigKey.ADMIN_UDP_PORT, true, LIBDEFAULT) != null
+            || getInt(AdminConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+    }
+
+    /**
+     * Is to allow TCP for KDC
+     *
+     * @return true to allow TCP, false otherwise
+     */
+    public boolean allowTcp() {
+        return getBoolean(AdminConfigKey.ADMIN_ALLOW_TCP, true, LIBDEFAULT)
+                || getInt(AdminConfigKey.ADMIN_TCP_PORT, true, LIBDEFAULT) != null
+            || getInt(AdminConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+    }
+
+    /**
+     * Get KDC UDP port
+     *
+     * @return The kdc udp port
+     */
+    public int getAdminUdpPort() {
+        Integer kdcPort = getInt(AdminConfigKey.ADMIN_UDP_PORT, true, LIBDEFAULT);
+        if (kdcPort != null && kdcPort > 0) {
+            return kdcPort.intValue();
+        }
+        return getAdminPort();
+    }
+
+    /**
+     * Get KDC realm.
+     * @return The kdc realm
+     */
+    public String getAdminRealm() {
+        String realm = getString(AdminConfigKey.ADMIN_REALM, false, LIBDEFAULT);
+        if (realm == null) {
+            realm = getString(AdminConfigKey.DEFAULT_REALM, false, LIBDEFAULT);
+            if (realm == null) {
+                realm = (String) AdminConfigKey.ADMIN_REALM.getDefaultValue();
+            }
+        }
+
+        return realm;
+    }
+
+    public String getKeyTabFile() {
+        return getString(AdminConfigKey.KEYTAB_FILE, true, LIBDEFAULT);
+    }
+
+    public String getProtocol() {
+        return getString(AdminConfigKey.PROTOCOL, true, LIBDEFAULT);
+    }
+
+    public String getServerName() {
+        return getString(AdminConfigKey.SERVER_NAME, true, LIBDEFAULT);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfigKey.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfigKey.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfigKey.java
new file mode 100644
index 0000000..4227930
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfigKey.java
@@ -0,0 +1,58 @@
+/**
+ *  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.kerb.admin.kadmin.remote;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum AdminConfigKey implements ConfigKey {
+    KRB_DEBUG(true),
+    ADMIN_HOST("localhost"),
+    ADMIN_PORT(null),
+    ADMIN_ALLOW_UDP(false),
+    ADMIN_ALLOW_TCP(false),
+    ADMIN_UDP_PORT(null),
+    ADMIN_TCP_PORT(null),
+    ADMIN_DOMAIN("example.com"),
+    DEFAULT_REALM(null),
+    ADMIN_REALM("EXAMPLE.COM"),
+    KEYTAB_FILE,
+    PROTOCOL,
+    SERVER_NAME("localhost");
+
+    private Object defaultValue;
+
+    AdminConfigKey() {
+        this.defaultValue = null;
+    }
+
+    AdminConfigKey(Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public String getPropertyKey() {
+        return name().toLowerCase();
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return this.defaultValue;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminContext.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminContext.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminContext.java
new file mode 100644
index 0000000..67219a6
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminContext.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.kerberos.kerb.admin.kadmin.remote;
+
+public class AdminContext {
+
+    private AdminSetting adminSetting;
+
+    /**
+     * Init with krbsetting.
+     * @param adminSetting The krb setting
+     */
+    public void init(AdminSetting adminSetting) {
+        this.adminSetting = adminSetting;
+    }
+
+    /**
+     * Get krbsetting.
+     * @return The krb setting
+     */
+    public AdminSetting getAdminSetting() {
+        return adminSetting;
+    }
+
+    /**
+     * Get krbconfig.
+     * @return The krb config
+     */
+    public AdminConfig getConfig() {
+        return adminSetting.getAdminConfig();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminHandler.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminHandler.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminHandler.java
new file mode 100644
index 0000000..9debfdd
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminHandler.java
@@ -0,0 +1,162 @@
+/**
+ *  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.kerb.admin.kadmin.remote;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.AdminRequest;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminMessageCode;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminMessageType;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminReq;
+import org.apache.kerby.kerberos.kerb.admin.message.KadminCode;
+import org.apache.kerby.xdr.XdrFieldInfo;
+import org.apache.kerby.xdr.type.XdrStructType;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+public abstract class AdminHandler {
+
+    /**
+     * Init with krbcontext.
+     *
+     * @param context The krbcontext
+     */
+    public void init(AdminContext context) {
+
+    }
+
+    /**
+     * Handle the kdc request.
+     *
+     * @param adminRequest The admin request
+     * @throws KrbException e
+     */
+    public void handleRequest(AdminRequest adminRequest) throws KrbException {
+        adminRequest.process();
+        AdminReq adminReq = adminRequest.getAdminReq();
+        ByteBuffer requestMessage = KadminCode.encodeMessage(adminReq);
+        requestMessage.flip();
+
+        try {
+            sendMessage(adminRequest, requestMessage);
+        } catch (IOException e) {
+            throw new KrbException("Admin sends request message failed", e);
+        }
+
+    }
+
+    /**
+     * Process the response message from kdc.
+     *
+     * @param adminRequest The admin request
+     * @param responseMessage The message from kdc
+     * @throws KrbException e
+     */
+    public void onResponseMessage(AdminRequest adminRequest,
+                                  ByteBuffer responseMessage) throws KrbException {
+
+
+        XdrStructType decoded = new AdminMessageCode();
+        try {
+            decoded.decode(responseMessage);
+        } catch (IOException e) {
+            throw new KrbException("On response message failed.", e);
+        }
+        XdrFieldInfo[] fieldInfos = decoded.getValue().getXdrFieldInfos();
+        AdminMessageType type = (AdminMessageType) fieldInfos[0].getValue();
+
+        switch (type) {
+            case ADD_PRINCIPAL_REP:
+                if (adminRequest.getAdminReq().getAdminMessageType()
+                    == AdminMessageType.ADD_PRINCIPAL_REQ) {
+                    System.out.println((String) fieldInfos[2].getValue());
+                } else {
+                    throw new KrbException("Response message type error: need "
+                    + AdminMessageType.ADD_PRINCIPAL_REP);
+                }
+                break;
+            case DELETE_PRINCIPAL_REP:
+                if (adminRequest.getAdminReq().getAdminMessageType()
+                    == AdminMessageType.DELETE_PRINCIPAL_REQ) {
+                    System.out.println((String) fieldInfos[2].getValue());
+                } else {
+                    throw new KrbException("Response message type error: need "
+                    + AdminMessageType.DELETE_PRINCIPAL_REP);
+                }
+                break;
+            case RENAME_PRINCIPAL_REP:
+                if (adminRequest.getAdminReq().getAdminMessageType()
+                    == AdminMessageType.RENAME_PRINCIPAL_REQ) {
+                    System.out.println((String) fieldInfos[2].getValue());
+                } else {
+                    throw new KrbException("Response message type error: need "
+                    + AdminMessageType.RENAME_PRINCIPAL_REP);
+                }
+                break;
+            default:
+                throw new KrbException("Response message type error: " + type);
+        }
+    }
+
+    public List<String> onResponseMessageForList(AdminRequest adminRequest,
+                                  ByteBuffer responseMessage) throws KrbException {
+        List<String> princalsList = null;
+
+        XdrStructType decoded = new AdminMessageCode();
+        try {
+            decoded.decode(responseMessage);
+        } catch (IOException e) {
+            throw new KrbException("On response message failed.", e);
+        }
+        XdrFieldInfo[] fieldInfos = decoded.getValue().getXdrFieldInfos();
+        AdminMessageType type = (AdminMessageType) fieldInfos[0].getValue();
+
+        switch (type) {
+            case GET_PRINCS_REP:
+                if (adminRequest.getAdminReq().getAdminMessageType()
+                        == AdminMessageType.GET_PRINCS_REQ) {
+                    String[] temp = ((String) fieldInfos[2].getValue()).trim().split(" ");
+                    princalsList = Arrays.asList(temp);
+                } else {
+                    throw new KrbException("Response message type error: need "
+                            + AdminMessageType.GET_PRINCS_REP);
+                }
+                break;
+            default:
+                throw new KrbException("Response message type error: " + type);
+        }
+
+        return princalsList;
+    }
+
+    /**
+     * Send message to kdc.
+     *
+     * @param adminRequest The admin request
+     * @param requestMessage The request message to kdc
+     * @throws IOException e
+     */
+    protected abstract void sendMessage(AdminRequest adminRequest,
+                                        ByteBuffer requestMessage) throws IOException;
+
+    protected abstract List<String> handleRequestForList(AdminRequest adminRequest) throws KrbException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminOption.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminOption.java
new file mode 100644
index 0000000..fc2d45b
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminOption.java
@@ -0,0 +1,102 @@
+/**
+ *  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.kerb.admin.kadmin.remote;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * This defines all the options that come across the client side.
+ */
+public enum AdminOption implements KOption {
+    NONE(null),
+
+    ADMIN_REALM(new KOptionInfo("admin-realm", "kdc realm",
+        KOptionType.STR)),
+    ADMIN_HOST(new KOptionInfo("admin-host", "kdc host",
+        KOptionType.STR)),
+    ADMIN_TCP_PORT(new KOptionInfo("admin-tcp-port", "kdc tcp port",
+        KOptionType.INT)),
+    ALLOW_UDP(new KOptionInfo("allow-udp", "allow udp",
+        KOptionType.BOOL)),
+    ALLOW_TCP(new KOptionInfo("allow-tcp", "allow tcp",
+        KOptionType.BOOL)),
+    ADMIN_UDP_PORT(new KOptionInfo("admin-udp-port", "kdc udp port",
+        KOptionType.INT)),
+    CONN_TIMEOUT(new KOptionInfo("conn-timeout", "connection timeout",
+        KOptionType.INT)),
+
+    LIFE_TIME(new KOptionInfo("life-time", "life time",
+        KOptionType.INT)),
+    START_TIME(new KOptionInfo("start-time", "start time",
+        KOptionType.INT)),
+    RENEWABLE_TIME(new KOptionInfo("renewable_lifetime", "renewable lifetime",
+        KOptionType.INT)),
+    INCLUDE_ADDRESSES(new KOptionInfo("include_addresses",
+        "include addresses")),
+    AS_ENTERPRISE_PN(new KOptionInfo("as-enterprise-pn",
+        "client is enterprise principal name")),
+    CLIENT_PRINCIPAL(new KOptionInfo("client-principal", "Client principal",
+        KOptionType.STR)),
+
+    USE_PASSWD(new KOptionInfo("using-password", "using password")),
+    USER_PASSWD(new KOptionInfo("user-passwd", "User plain password")),
+
+    USE_KEYTAB(new KOptionInfo("use-keytab", "use keytab")),
+    USE_DFT_KEYTAB(new KOptionInfo("use-dft-keytab", "use default client keytab (with -k)")),
+    KEYTAB_FILE(new KOptionInfo("keytab-file", "filename of keytab to use",
+        KOptionType.FILE)),
+
+    KRB5_CACHE(new KOptionInfo("krb5-cache", "K5 cache name",
+        KOptionType.FILE)),
+    SERVICE_PRINCIPAL(new KOptionInfo("service-principal", "service principal",
+        KOptionType.STR)),
+    SERVER_PRINCIPAL(new KOptionInfo("admin-principal", "admin principal",
+        KOptionType.STR)),
+    ARMOR_CACHE(new KOptionInfo("armor-cache", "armor credential cache",
+        KOptionType.STR)),
+    USE_TGT(new KOptionInfo("use-tgt", "use tgt to get service ticket",
+        KOptionType.OBJ)),
+    CONF_DIR(new KOptionInfo("-conf", "conf dir", KOptionType.DIR));
+
+    private final KOptionInfo optionInfo;
+
+    AdminOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static AdminOption fromOptionName(String optionName) {
+        if (optionName != null) {
+            for (AdminOption ko : values()) {
+                if (ko.optionInfo != null
+                    && ko.optionInfo.getName().equals(optionName)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminSetting.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminSetting.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminSetting.java
new file mode 100644
index 0000000..1e519ea
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminSetting.java
@@ -0,0 +1,129 @@
+/**
+ *  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.kerb.admin.kadmin.remote;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Admin client setting that combines common options and client config.
+ */
+public class AdminSetting {
+    private final KOptions commonOptions;
+    private final AdminConfig adminConfig;
+
+    public AdminSetting(KOptions commonOptions, AdminConfig config) {
+        this.commonOptions = commonOptions;
+        this.adminConfig = config;
+    }
+
+    public AdminSetting(AdminConfig config) {
+        this.commonOptions = new KOptions();
+        this.adminConfig = config;
+    }
+
+    public AdminConfig getAdminConfig() {
+        return adminConfig;
+    }
+
+    public String getKdcRealm() {
+        String kdcRealm = commonOptions.getStringOption(AdminOption.ADMIN_REALM);
+        if (kdcRealm == null || kdcRealm.isEmpty()) {
+            kdcRealm = adminConfig.getAdminRealm();
+        }
+        return kdcRealm;
+    }
+
+    public String getKdcHost() {
+        String kdcHost = commonOptions.getStringOption(AdminOption.ADMIN_HOST);
+        if (kdcHost == null) {
+            return adminConfig.getAdminHost();
+        }
+        return kdcHost;
+    }
+
+    /**
+     * Check kdc tcp setting and see if any bad.
+     * @return valid tcp port or -1 if not allowTcp
+     * @throws KrbException e
+     */
+    public int checkGetKdcTcpPort() throws KrbException {
+        if (allowTcp()) {
+            int kdcPort = getKdcTcpPort();
+            if (kdcPort < 1) {
+                throw new KrbException("KDC tcp port isn't set or configured");
+            }
+            return kdcPort;
+        }
+        return -1;
+    }
+
+    /**
+     * Check kdc udp setting and see if any bad.
+     * @return valid udp port or -1 if not allowUdp
+     * @throws KrbException e
+     */
+    public int checkGetKdcUdpPort() throws KrbException {
+        if (allowUdp()) {
+            int kdcPort = getKdcUdpPort();
+            if (kdcPort < 1) {
+                throw new KrbException("KDC udp port isn't set or configured");
+            }
+            return kdcPort;
+        }
+        return -1;
+    }
+
+    public int getKdcTcpPort() {
+        int tcpPort = commonOptions.getIntegerOption(AdminOption.ADMIN_TCP_PORT);
+        if (tcpPort > 0) {
+            return tcpPort;
+        }
+        return adminConfig.getAdminTcpPort();
+    }
+
+    public boolean allowUdp() {
+        Boolean allowUdp = commonOptions.getBooleanOption(
+                AdminOption.ALLOW_UDP, adminConfig.allowUdp());
+        return allowUdp;
+    }
+
+    public boolean allowTcp() {
+        Boolean allowTcp = commonOptions.getBooleanOption(
+                AdminOption.ALLOW_TCP, adminConfig.allowTcp());
+        return allowTcp;
+    }
+
+    public int getKdcUdpPort() {
+        int udpPort = commonOptions.getIntegerOption(AdminOption.ADMIN_UDP_PORT);
+        if (udpPort > 0) {
+            return udpPort;
+        }
+        return adminConfig.getAdminUdpPort();
+    }
+
+    public int getTimeout() {
+        int timeout = commonOptions.getIntegerOption(AdminOption.CONN_TIMEOUT);
+        if (timeout > 0) {
+            return timeout;
+        }
+        return 1000; // by default
+    }
+}


Mime
View raw message