You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by ar...@apache.org on 2017/02/13 18:12:11 UTC

zookeeper git commit: ZOOKEEPER-2689: Fix Kerberos Authentication related test cases

Repository: zookeeper
Updated Branches:
  refs/heads/branch-3.4 e51dbeb47 -> e8247eec1


ZOOKEEPER-2689: Fix Kerberos Authentication related test cases

Presently 'MiniKdc.java' uses Apache Kerby which has a build requirement of jdk1.7+, http://directory.apache.org/kerby/developer-guide.html]. Since branch-3.4.x support Java 1.6 or higher, Apache Kerby binding is causing trouble.

I've tried an attempt to rewrite MiniKdc.java test using old way of Kerberos implementation provided by Apache Directory Server project, org.apache.directory.* packages. Please refer MiniKdc implementation of Hadoop, trunk branch git hash revision 42e3a805117ff7cb054c2442f7b0e0cc54be63ad

Author: Rakesh Radhakrishnan <ra...@apache.org>

Reviewers: Mohammad Arshad <ar...@apache.org>

Closes #170 from rakeshadr/ZK-2689


Project: http://git-wip-us.apache.org/repos/asf/zookeeper/repo
Commit: http://git-wip-us.apache.org/repos/asf/zookeeper/commit/e8247eec
Tree: http://git-wip-us.apache.org/repos/asf/zookeeper/tree/e8247eec
Diff: http://git-wip-us.apache.org/repos/asf/zookeeper/diff/e8247eec

Branch: refs/heads/branch-3.4
Commit: e8247eec1103e387e02bbb1e8859b4d468688f48
Parents: e51dbeb
Author: Rakesh Radhakrishnan <ra...@apache.org>
Authored: Mon Feb 13 23:41:31 2017 +0530
Committer: Mohammad Arshad <ar...@apache.org>
Committed: Mon Feb 13 23:41:31 2017 +0530

----------------------------------------------------------------------
 ivy.xml                                         |  56 +--
 .../zookeeper/server/quorum/auth/MiniKdc.java   | 344 ++++++++++++++-----
 .../server/quorum/auth/MiniKdcTest.java         |  18 +-
 3 files changed, 291 insertions(+), 127 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zookeeper/blob/e8247eec/ivy.xml
----------------------------------------------------------------------
diff --git a/ivy.xml b/ivy.xml
index 437b86b..4c11384 100644
--- a/ivy.xml
+++ b/ivy.xml
@@ -78,30 +78,38 @@
     <dependency org="commons-io" name="commons-io" rev="2.4"
                 conf="test->default"/>
 
-    <dependency org="org.apache.kerby" name="kerb-simplekdc" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerby-config" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-core" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-server" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-common" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-admin" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-identity" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-client" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-util" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerb-crypto" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerby-util" rev="1.0.0-RC2"
-                conf="test->default"/>
-    <dependency org="org.apache.kerby" name="kerby-asn1" rev="1.0.0-RC2"
-                conf="test->default"/>
+
+    <!-- Apache directory server project, org.apache.directory.* packages for miniKdc tests -->
+    <dependency org="org.apache.directory.server" name="apacheds-core-api" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+    <dependency org="org.apache.directory.server" name="apacheds-interceptor-kerberos" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+    <dependency org="org.apache.directory.server" name="apacheds-protocol-shared" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+    <dependency org="org.apache.directory.server" name="apacheds-protocol-kerberos" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+    <dependency org="org.apache.directory.server" name="apacheds-ldif-partition" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+    <dependency org="org.apache.directory.server" name="apacheds-mavibot-partition" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+    <dependency org="org.apache.directory.api" name="api-all" rev="1.0.0-M20" conf="test->default">
+        <exclude org="xml-apis" name="xml-apis"/>
+        <exclude org="xpp3" name="xpp3"/>
+        <exclude org="dom4j" name="dom4j"/>
+    </dependency>
+    <dependency org="org.apache.directory.server" name="apacheds-jdbm-partition" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+    <dependency org="org.apache.directory.server" name="apacheds-protocol-ldap" rev="2.0.0-M15" conf="test->default">
+        <exclude org="org.apache.directory.api" name="api-ldap-schema-data"/>
+    </dependency>
+
   </dependencies>
 
 </ivy-module>

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/e8247eec/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdc.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdc.java b/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdc.java
index 4afef41..8e3cb1b 100644
--- a/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdc.java
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdc.java
@@ -17,26 +17,67 @@
  */
 
 package org.apache.zookeeper.server.quorum.auth;
+
 import org.apache.commons.io.Charsets;
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.server.KdcConfigKey;
-import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
-import org.apache.kerby.util.IOUtil;
-import org.apache.kerby.util.NetworkUtil;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.text.StrSubstitutor;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schemaextractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schemaloader.LdifSchemaLoader;
+import org.apache.directory.api.ldap.schemamanager.impl.DefaultSchemaManager;
+import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.core.DefaultDirectoryService;
+import org.apache.directory.server.core.api.CacheService;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.InstanceLayout;
+import org.apache.directory.server.core.api.schema.SchemaPartition;
+import org.apache.directory.server.core.kerberos.KeyDerivationInterceptor;
+import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
+import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
+import org.apache.directory.server.core.partition.ldif.LdifPartition;
+import org.apache.directory.server.kerberos.KerberosConfig;
+import org.apache.directory.server.kerberos.kdc.KdcServer;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory;
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;
+import org.apache.directory.server.protocol.shared.transport.TcpTransport;
+import org.apache.directory.server.protocol.shared.transport.UdpTransport;
+import org.apache.directory.server.xdbm.Index;
+import org.apache.directory.shared.kerberos.KerberosTime;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
+import org.apache.directory.shared.kerberos.components.EncryptionKey;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.UUID;
 
 /**
  * Mini KDC based on Apache Directory Server that can be embedded in testcases
@@ -44,10 +85,11 @@ import java.util.Set;
  * <p>
  * <b>From within testcases:</b>
  * <p>
- * MiniKdc sets one System property when started and un-set when stopped:
+ * MiniKdc sets 2 System properties when started and un-sets them when stopped:
  * <ul>
- *   <li>sun.security.krb5.debug: set to the debug value provided in the
- *   configuration</li>
+ * <li>java.security.krb5.conf: set to the MiniKDC real/host/port</li>
+ * <li>sun.security.krb5.debug: set to the debug value provided in the
+ * configuration</li>
  * </ul>
  * Because of this, multiple MiniKdc instances cannot be started in parallel.
  * For example, running testcases in parallel that start a KDC each. To
@@ -73,7 +115,7 @@ import java.util.Set;
  * in case of bug fixing, history, etc.
  *
  * Branch : trunk
- * Github Revision: 916140604ffef59466ba30832478311d3e6249bd
+ * Github Revision: 42e3a805117ff7cb054c2442f7b0e0cc54be63ad
  */
 public class MiniKdc {
 
@@ -81,6 +123,8 @@ public class MiniKdc {
             "java.security.krb5.conf";
     public static final String SUN_SECURITY_KRB5_DEBUG =
             "sun.security.krb5.debug";
+    private static final File testData = new File(
+            System.getProperty("test.data.dir", "build/test/data"));
 
     public static void main(String[] args) throws Exception {
         if (args.length < 4) {
@@ -195,17 +239,13 @@ public class MiniKdc {
     }
 
     private Properties conf;
-    private SimpleKdcServer simpleKdc;
+    private DirectoryService ds;
+    private KdcServer kdc;
     private int port;
     private String realm;
     private File workDir;
     private File krb5conf;
-    private String transport;
-    private boolean krb5Debug;
 
-    public void setTransport(String transport) {
-        this.transport = transport;
-    }
     /**
      * Creates a MiniKdc.
      *
@@ -235,7 +275,12 @@ public class MiniKdc {
         LOG.info("---------------------------------------------------------------");
         this.conf = conf;
         port = Integer.parseInt(conf.getProperty(KDC_PORT));
-        String orgName= conf.getProperty(ORG_NAME);
+        if (port == 0) {
+            ServerSocket ss = new ServerSocket(0, 1, InetAddress.getByName(conf.getProperty(KDC_BIND_ADDRESS)));
+            port = ss.getLocalPort();
+            ss.close();
+        }
+        String orgName = conf.getProperty(ORG_NAME);
         String orgDomain = conf.getProperty(ORG_DOMAIN);
         realm = orgName.toUpperCase(Locale.ENGLISH) + "."
                 + orgDomain.toUpperCase(Locale.ENGLISH);
@@ -269,7 +314,6 @@ public class MiniKdc {
     }
 
     public File getKrb5conf() {
-        krb5conf = new File(System.getProperty(JAVA_SECURITY_KRB5_CONF));
         return krb5conf;
     }
 
@@ -279,81 +323,186 @@ public class MiniKdc {
      * @throws Exception thrown if the MiniKdc could not be started.
      */
     public synchronized void start() throws Exception {
-        if (simpleKdc != null) {
+        if (kdc != null) {
             throw new RuntimeException("Already started");
         }
-        simpleKdc = new SimpleKdcServer();
-        prepareKdcServer();
-        simpleKdc.init();
-        resetDefaultRealm();
-        simpleKdc.start();
-        LOG.info("MiniKdc stated.");
+        initDirectoryService();
+        initKDCServer();
     }
 
-    private void resetDefaultRealm() throws IOException {
-        InputStream templateResource = new FileInputStream(
-                getKrb5conf().getAbsolutePath());
-        String content = IOUtil.readInput(templateResource);
-        content = content.replaceAll("default_realm = .*\n",
-                "default_realm = " + getRealm() + "\n");
-        IOUtil.writeFile(content, getKrb5conf());
+    private void initDirectoryService() throws Exception {
+        ds = new DefaultDirectoryService();
+        ds.setInstanceLayout(new InstanceLayout(workDir));
+
+        CacheService cacheService = new CacheService();
+        ds.setCacheService(cacheService);
+
+        // first load the schema
+        InstanceLayout instanceLayout = ds.getInstanceLayout();
+        File schemaPartitionDirectory = new File(instanceLayout.getPartitionsDirectory(), "schema");
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor(instanceLayout.getPartitionsDirectory());
+        extractor.extractOrCopy();
+
+        SchemaLoader loader = new LdifSchemaLoader(schemaPartitionDirectory);
+        SchemaManager schemaManager = new DefaultSchemaManager(loader);
+        schemaManager.loadAllEnabled();
+        ds.setSchemaManager(schemaManager);
+        // Init the LdifPartition with schema
+        LdifPartition schemaLdifPartition = new LdifPartition(schemaManager);
+        schemaLdifPartition.setPartitionPath(schemaPartitionDirectory.toURI());
+
+        // The schema partition
+        SchemaPartition schemaPartition = new SchemaPartition(schemaManager);
+        schemaPartition.setWrappedPartition(schemaLdifPartition);
+        ds.setSchemaPartition(schemaPartition);
+
+        JdbmPartition systemPartition = new JdbmPartition(ds.getSchemaManager());
+        systemPartition.setId("system");
+        systemPartition.setPartitionPath(
+                new File(ds.getInstanceLayout().getPartitionsDirectory(), systemPartition.getId()).toURI());
+        systemPartition.setSuffixDn(new Dn(ServerDNConstants.SYSTEM_DN));
+        systemPartition.setSchemaManager(ds.getSchemaManager());
+        ds.setSystemPartition(systemPartition);
+
+        ds.getChangeLog().setEnabled(false);
+        ds.setDenormalizeOpAttrsEnabled(true);
+        ds.addLast(new KeyDerivationInterceptor());
+
+        // create one partition
+        String orgName = conf.getProperty(ORG_NAME).toLowerCase(Locale.ENGLISH);
+        String orgDomain = conf.getProperty(ORG_DOMAIN).toLowerCase(Locale.ENGLISH);
+
+        JdbmPartition partition = new JdbmPartition(ds.getSchemaManager());
+        partition.setId(orgName);
+        partition.setPartitionPath(new File(ds.getInstanceLayout().getPartitionsDirectory(), orgName).toURI());
+        partition.setSuffixDn(new Dn("dc=" + orgName + ",dc=" + orgDomain));
+        ds.addPartition(partition);
+        // indexes
+        Set<Index<?, ?, String>> indexedAttributes = new HashSet<Index<?, ?, String>>();
+        indexedAttributes.add(new JdbmIndex<String, Entry>("objectClass", false));
+        indexedAttributes.add(new JdbmIndex<String, Entry>("dc", false));
+        indexedAttributes.add(new JdbmIndex<String, Entry>("ou", false));
+        partition.setIndexedAttributes(indexedAttributes);
+
+        // And start the ds
+        ds.setInstanceId(conf.getProperty(INSTANCE));
+        ds.startup();
+        // context entry, after ds.startup()
+        Dn dn = new Dn("dc=" + orgName + ",dc=" + orgDomain);
+        Entry entry = ds.newEntry(dn);
+        entry.add("objectClass", "top", "domain");
+        entry.add("dc", orgName);
+        ds.getAdminSession().add(entry);
     }
 
-    private void prepareKdcServer() throws Exception {
-        // transport
-        simpleKdc.setWorkDir(workDir);
-        simpleKdc.setKdcHost(getHost());
-        simpleKdc.setKdcRealm(realm);
-        if (transport == null) {
-            transport = conf.getProperty(TRANSPORT);
+    private void initKDCServer() throws Exception {
+        String orgName = conf.getProperty(ORG_NAME);
+        String orgDomain = conf.getProperty(ORG_DOMAIN);
+        String bindAddress = conf.getProperty(KDC_BIND_ADDRESS);
+        final Map<String, String> map = new HashMap<String, String>();
+        map.put("0", orgName.toLowerCase(Locale.ENGLISH));
+        map.put("1", orgDomain.toLowerCase(Locale.ENGLISH));
+        map.put("2", orgName.toUpperCase(Locale.ENGLISH));
+        map.put("3", orgDomain.toUpperCase(Locale.ENGLISH));
+        map.put("4", bindAddress);
+
+        InputStream is1 = getMinikdcResourceAsStream("minikdc.ldiff");
+
+        SchemaManager schemaManager = ds.getSchemaManager();
+        LdifReader reader = null;
+
+        try {
+            final String content = StrSubstitutor.replace(IOUtils.toString(is1), map);
+            reader = new LdifReader(new StringReader(content));
+
+            for (LdifEntry ldifEntry : reader) {
+                ds.getAdminSession().add(new DefaultEntry(schemaManager, ldifEntry.getEntry()));
+            }
+        } finally {
+            IOUtils.closeQuietly(reader);
+            IOUtils.closeQuietly(is1);
         }
-        if (port == 0) {
-            port = NetworkUtil.getServerPort();
+
+        KerberosConfig kerberosConfig = new KerberosConfig();
+        kerberosConfig.setMaximumRenewableLifetime(Long.parseLong(conf.getProperty(MAX_RENEWABLE_LIFETIME)));
+        kerberosConfig.setMaximumTicketLifetime(Long.parseLong(conf.getProperty(MAX_TICKET_LIFETIME)));
+        kerberosConfig.setSearchBaseDn(String.format("dc=%s,dc=%s", orgName, orgDomain));
+        kerberosConfig.setPaEncTimestampRequired(false);
+        kdc = new KdcServer(kerberosConfig);
+        kdc.setDirectoryService(ds);
+
+        // transport
+        String transport = conf.getProperty(TRANSPORT);
+        if (transport.trim().equals("TCP")) {
+            kdc.addTransports(new TcpTransport(bindAddress, port, 3, 50));
+        } else if (transport.trim().equals("UDP")) {
+            kdc.addTransports(new UdpTransport(port));
+        } else {
+            throw new IllegalArgumentException("Invalid transport: " + transport);
         }
-        if (transport != null) {
-            if (transport.trim().equals("TCP")) {
-                simpleKdc.setKdcTcpPort(port);
-                simpleKdc.setAllowUdp(false);
-            } else if (transport.trim().equals("UDP")) {
-                simpleKdc.setKdcUdpPort(port);
-                simpleKdc.setAllowTcp(false);
-            } else {
-                throw new IllegalArgumentException("Invalid transport: " + transport);
+        kdc.setServiceName(conf.getProperty(INSTANCE));
+        kdc.start();
+
+        StringBuilder sb = new StringBuilder();
+        InputStream is2 = getMinikdcResourceAsStream("minikdc-krb5.conf");
+
+        BufferedReader r = null;
+
+        try {
+            r = new BufferedReader(new InputStreamReader(is2, Charsets.UTF_8));
+            String line = r.readLine();
+
+            while (line != null) {
+                sb.append(line).append("{3}");
+                line = r.readLine();
             }
-        } else {
-            throw new IllegalArgumentException("Need to set transport!");
+        } finally {
+            IOUtils.closeQuietly(r);
+            IOUtils.closeQuietly(is2);
         }
-        simpleKdc.getKdcConfig().setString(KdcConfigKey.KDC_SERVICE_NAME,
-                conf.getProperty(INSTANCE));
-        if (conf.getProperty(DEBUG) != null) {
-            krb5Debug = getAndSet(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG));
+
+        krb5conf = new File(workDir, "krb5.conf").getAbsoluteFile();
+        FileUtils.writeStringToFile(krb5conf, MessageFormat.format(sb.toString(), getRealm(), getHost(),
+                Integer.toString(getPort()), System.getProperty("line.separator")));
+        System.setProperty(JAVA_SECURITY_KRB5_CONF, krb5conf.getAbsolutePath());
+
+        System.setProperty(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG, "false"));
+
+        // refresh the config
+        Class<?> classRef;
+        if (System.getProperty("java.vendor").contains("IBM")) {
+            classRef = Class.forName("com.ibm.security.krb5.internal.Config");
+        } else {
+            classRef = Class.forName("sun.security.krb5.Config");
         }
+        Method refreshMethod = classRef.getMethod("refresh", new Class[0]);
+        refreshMethod.invoke(classRef, new Object[0]);
+
+        LOG.info("MiniKdc listening at port: {}", getPort());
+        LOG.info("MiniKdc setting JVM krb5.conf to: {}", krb5conf.getAbsolutePath());
+    }
+
+    private InputStream getMinikdcResourceAsStream(String resourceName)
+            throws FileNotFoundException {
+        File kdcResourceFile = new File(testData, "/kerberos/" + resourceName);
+        return new FileInputStream(kdcResourceFile);
     }
 
     /**
      * Stops the MiniKdc
      */
     public synchronized void stop() {
-        if (simpleKdc != null) {
+        if (kdc != null) {
+            System.getProperties().remove(JAVA_SECURITY_KRB5_CONF);
+            System.getProperties().remove(SUN_SECURITY_KRB5_DEBUG);
+            kdc.stop();
             try {
-                simpleKdc.stop();
-            } catch (KrbException e) {
-                e.printStackTrace();
-            } finally {
-                if(conf.getProperty(DEBUG) != null) {
-                    System.setProperty(SUN_SECURITY_KRB5_DEBUG,
-                            Boolean.toString(krb5Debug));
-                }
+                ds.shutdown();
+            } catch (Exception ex) {
+                LOG.error("Could not shutdown ApacheDS properly: {}", ex.toString(), ex);
             }
         }
         delete(workDir);
-        try {
-            // Will be fixed in next Kerby version.
-            Thread.sleep(1000);
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-        LOG.info("MiniKdc stopped.");
     }
 
     private void delete(File f) {
@@ -378,9 +527,20 @@ public class MiniKdc {
      * @param password password.
      * @throws Exception thrown if the principal could not be created.
      */
-    public synchronized void createPrincipal(String principal, String password)
-            throws Exception {
-        simpleKdc.createPrincipal(principal, password);
+    public synchronized void createPrincipal(String principal, String password) throws Exception {
+        String orgName = conf.getProperty(ORG_NAME);
+        String orgDomain = conf.getProperty(ORG_DOMAIN);
+        String baseDn = "ou=users,dc=" + orgName.toLowerCase(Locale.ENGLISH) + ",dc="
+                + orgDomain.toLowerCase(Locale.ENGLISH);
+        String content = "dn: uid=" + principal + "," + baseDn + "\n" + "objectClass: top\n" + "objectClass: person\n"
+                + "objectClass: inetOrgPerson\n" + "objectClass: krb5principal\n" + "objectClass: krb5kdcentry\n"
+                + "cn: " + principal + "\n" + "sn: " + principal + "\n" + "uid: " + principal + "\n" + "userPassword: "
+                + password + "\n" + "krb5PrincipalName: " + principal + "@" + getRealm() + "\n"
+                + "krb5KeyVersionNumber: 0";
+
+        for (LdifEntry ldifEntry : new LdifReader(new StringReader(content))) {
+            ds.getAdminSession().add(new DefaultEntry(ds.getSchemaManager(), ldifEntry.getEntry()));
+        }
     }
 
     /**
@@ -394,25 +554,21 @@ public class MiniKdc {
     public synchronized void createPrincipal(File keytabFile,
                                              String ... principals)
             throws Exception {
-        simpleKdc.createPrincipals(principals);
-        if (keytabFile.exists() && !keytabFile.delete()) {
-            LOG.error("Failed to delete keytab file: " + keytabFile);
-        }
+        String generatedPassword = UUID.randomUUID().toString();
+        Keytab keytab = new Keytab();
+        List<KeytabEntry> entries = new ArrayList<KeytabEntry>();
         for (String principal : principals) {
-            simpleKdc.getKadmin().exportKeytab(keytabFile, principal);
+            createPrincipal(principal, generatedPassword);
+            principal = principal + "@" + getRealm();
+            KerberosTime timestamp = new KerberosTime();
+            for (Map.Entry<EncryptionType, EncryptionKey> entry : KerberosKeyFactory
+                    .getKerberosKeys(principal, generatedPassword).entrySet()) {
+                EncryptionKey ekey = entry.getValue();
+                byte keyVersion = (byte) ekey.getKeyVersion();
+                entries.add(new KeytabEntry(principal, 1L, timestamp, keyVersion, ekey));
+            }
         }
+        keytab.setEntries(entries);
+        keytab.write(keytabFile);
     }
-
-    /**
-     * Set the System property; return the old value for caching.
-     *
-     * @param sysprop property
-     * @param debug true or false
-     * @return the previous value
-     */
-    private boolean getAndSet(String sysprop, String debug) {
-        boolean old = Boolean.getBoolean(sysprop);
-        System.setProperty(sysprop, debug);
-        return old;
-    }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/e8247eec/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdcTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdcTest.java b/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdcTest.java
index a7bbf7f..196d8be 100644
--- a/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdcTest.java
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdcTest.java
@@ -18,8 +18,8 @@
 
 package org.apache.zookeeper.server.quorum.auth;
 
-import org.apache.kerby.kerberos.kerb.keytab.Keytab;
-import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -30,7 +30,6 @@ import javax.security.auth.login.Configuration;
 import javax.security.auth.login.LoginContext;
 import java.io.File;
 import java.security.Principal;
-import java.util.List;
 import java.util.Set;
 import java.util.Map;
 import java.util.HashSet;
@@ -60,16 +59,17 @@ public class MiniKdcTest extends KerberosSecurityTestcase {
         File workDir = getWorkDir();
 
         kdc.createPrincipal(new File(workDir, "keytab"), "foo/bar", "bar/foo");
-        List<PrincipalName> principalNameList =
-                Keytab.loadKeytab(new File(workDir, "keytab")).getPrincipals();
+        Keytab kt = Keytab.read(new File(workDir, "keytab"));
 
         Set<String> principals = new HashSet<String>();
-        for (PrincipalName principalName : principalNameList) {
-          principals.add(principalName.getName());
+        for (KeytabEntry entry : kt.getEntries()) {
+            principals.add(entry.getPrincipalName());
         }
-
+        //here principals use \ instead of /
+        //because org.apache.directory.server.kerberos.shared.keytab.KeytabDecoder
+        // .getPrincipalName(IoBuffer buffer) use \\ when generates principal
         Assert.assertEquals(new HashSet<String>(Arrays.asList(
-                "foo/bar@" + kdc.getRealm(), "bar/foo@" + kdc.getRealm())),
+                "foo\\bar@" + kdc.getRealm(), "bar\\foo@" + kdc.getRealm())),
                 principals);
       }