zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From h...@apache.org
Subject [1/3] zookeeper git commit: ZOOKEEPER-2792 ZOOKEEPER-1045: Port implementation from branch-3.4 to branch-3.5.
Date Mon, 24 Jul 2017 17:39:49 GMT
Repository: zookeeper
Updated Branches:
  refs/heads/branch-3.5 6ab74115e -> 5a29daede


http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/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
new file mode 100644
index 0000000..4afef41
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdc.java
@@ -0,0 +1,418 @@
+/**
+ * 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.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Mini KDC based on Apache Directory Server that can be embedded in testcases
+ * or used from command line as a standalone KDC.
+ * <p>
+ * <b>From within testcases:</b>
+ * <p>
+ * MiniKdc sets one System property when started and un-set when stopped:
+ * <ul>
+ *   <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
+ * accomplish this a single MiniKdc should be used for all testcases running
+ * in parallel.
+ * <p>
+ * MiniKdc default configuration values are:
+ * <ul>
+ *   <li>org.name=EXAMPLE (used to create the REALM)</li>
+ *   <li>org.domain=COM (used to create the REALM)</li>
+ *   <li>kdc.bind.address=localhost</li>
+ *   <li>kdc.port=0 (ephemeral port)</li>
+ *   <li>instance=DefaultKrbServer</li>
+ *   <li>max.ticket.lifetime=86400000 (1 day)</li>
+ *   <li>max.renewable.lifetime=604800000 (7 days)</li>
+ *   <li>transport=TCP</li>
+ *   <li>debug=false</li>
+ * </ul>
+ * The generated krb5.conf forces TCP connections.
+ */
+/*
+ * This code is originally from HDFS, see the file name MiniKdc there
+ * in case of bug fixing, history, etc.
+ *
+ * Branch : trunk
+ * Github Revision: 916140604ffef59466ba30832478311d3e6249bd
+ */
+public class MiniKdc {
+
+    public static final String JAVA_SECURITY_KRB5_CONF =
+            "java.security.krb5.conf";
+    public static final String SUN_SECURITY_KRB5_DEBUG =
+            "sun.security.krb5.debug";
+
+    public static void main(String[] args) throws Exception {
+        if (args.length < 4) {
+            System.out.println("Arguments: <WORKDIR> <MINIKDCPROPERTIES> " +
+                    "<KEYTABFILE> [<PRINCIPALS>]+");
+            System.exit(1);
+        }
+        File workDir = new File(args[0]);
+        if (!workDir.exists()) {
+            throw new RuntimeException("Specified work directory does not exists: "
+                    + workDir.getAbsolutePath());
+        }
+        Properties conf = createConf();
+        File file = new File(args[1]);
+        if (!file.exists()) {
+            throw new RuntimeException("Specified configuration does not exists: "
+                    + file.getAbsolutePath());
+        }
+        Properties userConf = new Properties();
+        InputStreamReader r = null;
+        try {
+            r = new InputStreamReader(new FileInputStream(file), Charsets.UTF_8);
+            userConf.load(r);
+        } finally {
+            if (r != null) {
+                r.close();
+            }
+        }
+        for (Map.Entry<?, ?> entry : userConf.entrySet()) {
+            conf.put(entry.getKey(), entry.getValue());
+        }
+        final MiniKdc miniKdc = new MiniKdc(conf, workDir);
+        miniKdc.start();
+        File krb5conf = new File(workDir, "krb5.conf");
+        if (miniKdc.getKrb5conf().renameTo(krb5conf)) {
+            File keytabFile = new File(args[2]).getAbsoluteFile();
+            String[] principals = new String[args.length - 3];
+            System.arraycopy(args, 3, principals, 0, args.length - 3);
+            miniKdc.createPrincipal(keytabFile, principals);
+            System.out.println();
+            System.out.println("Standalone MiniKdc Running");
+            System.out.println("---------------------------------------------------");
+            System.out.println("  Realm           : " + miniKdc.getRealm());
+            System.out.println("  Running at      : " + miniKdc.getHost() + ":" +
+                    miniKdc.getHost());
+            System.out.println("  krb5conf        : " + krb5conf);
+            System.out.println();
+            System.out.println("  created keytab  : " + keytabFile);
+            System.out.println("  with principals : " + Arrays.asList(principals));
+            System.out.println();
+            System.out.println(" Do <CTRL-C> or kill <PID> to stop it");
+            System.out.println("---------------------------------------------------");
+            System.out.println();
+            Runtime.getRuntime().addShutdownHook(new Thread() {
+                @Override
+                public void run() {
+                    miniKdc.stop();
+                }
+            });
+        } else {
+            throw new RuntimeException("Cannot rename KDC's krb5conf to "
+                    + krb5conf.getAbsolutePath());
+        }
+    }
+
+    private static final Logger LOG = LoggerFactory.getLogger(MiniKdc.class);
+
+    public static final String ORG_NAME = "org.name";
+    public static final String ORG_DOMAIN = "org.domain";
+    public static final String KDC_BIND_ADDRESS = "kdc.bind.address";
+    public static final String KDC_PORT = "kdc.port";
+    public static final String INSTANCE = "instance";
+    public static final String MAX_TICKET_LIFETIME = "max.ticket.lifetime";
+    public static final String MAX_RENEWABLE_LIFETIME = "max.renewable.lifetime";
+    public static final String TRANSPORT = "transport";
+    public static final String DEBUG = "debug";
+
+    private static final Set<String> PROPERTIES = new HashSet<String>();
+    private static final Properties DEFAULT_CONFIG = new Properties();
+
+    static {
+        PROPERTIES.add(ORG_NAME);
+        PROPERTIES.add(ORG_DOMAIN);
+        PROPERTIES.add(KDC_BIND_ADDRESS);
+        PROPERTIES.add(KDC_BIND_ADDRESS);
+        PROPERTIES.add(KDC_PORT);
+        PROPERTIES.add(INSTANCE);
+        PROPERTIES.add(TRANSPORT);
+        PROPERTIES.add(MAX_TICKET_LIFETIME);
+        PROPERTIES.add(MAX_RENEWABLE_LIFETIME);
+
+        DEFAULT_CONFIG.setProperty(KDC_BIND_ADDRESS, "localhost");
+        DEFAULT_CONFIG.setProperty(KDC_PORT, "0");
+        DEFAULT_CONFIG.setProperty(INSTANCE, "DefaultKrbServer");
+        DEFAULT_CONFIG.setProperty(ORG_NAME, "EXAMPLE");
+        DEFAULT_CONFIG.setProperty(ORG_DOMAIN, "COM");
+        DEFAULT_CONFIG.setProperty(TRANSPORT, "TCP");
+        DEFAULT_CONFIG.setProperty(MAX_TICKET_LIFETIME, "86400000");
+        DEFAULT_CONFIG.setProperty(MAX_RENEWABLE_LIFETIME, "604800000");
+        DEFAULT_CONFIG.setProperty(DEBUG, "false");
+    }
+
+    /**
+     * Convenience method that returns MiniKdc default configuration.
+     * <p>
+     * The returned configuration is a copy, it can be customized before using
+     * it to create a MiniKdc.
+     * @return a MiniKdc default configuration.
+     */
+    public static Properties createConf() {
+        return (Properties) DEFAULT_CONFIG.clone();
+    }
+
+    private Properties conf;
+    private SimpleKdcServer simpleKdc;
+    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.
+     *
+     * @param conf MiniKdc configuration.
+     * @param workDir working directory, it should be the build directory. Under
+     * this directory an ApacheDS working directory will be created, this
+     * directory will be deleted when the MiniKdc stops.
+     * @throws Exception thrown if the MiniKdc could not be created.
+     */
+    public MiniKdc(Properties conf, File workDir) throws Exception {
+        if (!conf.keySet().containsAll(PROPERTIES)) {
+            Set<String> missingProperties = new HashSet<String>(PROPERTIES);
+            missingProperties.removeAll(conf.keySet());
+            throw new IllegalArgumentException("Missing configuration properties: "
+                    + missingProperties);
+        }
+        this.workDir = new File(workDir, Long.toString(System.currentTimeMillis()));
+        if (!this.workDir.exists()
+                && !this.workDir.mkdirs()) {
+            throw new RuntimeException("Cannot create directory " + this.workDir);
+        }
+        LOG.info("Configuration:");
+        LOG.info("---------------------------------------------------------------");
+        for (Map.Entry<?, ?> entry : conf.entrySet()) {
+            LOG.info("  {}: {}", entry.getKey(), entry.getValue());
+        }
+        LOG.info("---------------------------------------------------------------");
+        this.conf = conf;
+        port = Integer.parseInt(conf.getProperty(KDC_PORT));
+        String orgName= conf.getProperty(ORG_NAME);
+        String orgDomain = conf.getProperty(ORG_DOMAIN);
+        realm = orgName.toUpperCase(Locale.ENGLISH) + "."
+                + orgDomain.toUpperCase(Locale.ENGLISH);
+    }
+
+    /**
+     * Returns the port of the MiniKdc.
+     *
+     * @return the port of the MiniKdc.
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns the host of the MiniKdc.
+     *
+     * @return the host of the MiniKdc.
+     */
+    public String getHost() {
+        return conf.getProperty(KDC_BIND_ADDRESS);
+    }
+
+    /**
+     * Returns the realm of the MiniKdc.
+     *
+     * @return the realm of the MiniKdc.
+     */
+    public String getRealm() {
+        return realm;
+    }
+
+    public File getKrb5conf() {
+        krb5conf = new File(System.getProperty(JAVA_SECURITY_KRB5_CONF));
+        return krb5conf;
+    }
+
+    /**
+     * Starts the MiniKdc.
+     *
+     * @throws Exception thrown if the MiniKdc could not be started.
+     */
+    public synchronized void start() throws Exception {
+        if (simpleKdc != null) {
+            throw new RuntimeException("Already started");
+        }
+        simpleKdc = new SimpleKdcServer();
+        prepareKdcServer();
+        simpleKdc.init();
+        resetDefaultRealm();
+        simpleKdc.start();
+        LOG.info("MiniKdc stated.");
+    }
+
+    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 prepareKdcServer() throws Exception {
+        // transport
+        simpleKdc.setWorkDir(workDir);
+        simpleKdc.setKdcHost(getHost());
+        simpleKdc.setKdcRealm(realm);
+        if (transport == null) {
+            transport = conf.getProperty(TRANSPORT);
+        }
+        if (port == 0) {
+            port = NetworkUtil.getServerPort();
+        }
+        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);
+            }
+        } else {
+            throw new IllegalArgumentException("Need to set transport!");
+        }
+        simpleKdc.getKdcConfig().setString(KdcConfigKey.KDC_SERVICE_NAME,
+                conf.getProperty(INSTANCE));
+        if (conf.getProperty(DEBUG) != null) {
+            krb5Debug = getAndSet(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG));
+        }
+    }
+
+    /**
+     * Stops the MiniKdc
+     */
+    public synchronized void stop() {
+        if (simpleKdc != null) {
+            try {
+                simpleKdc.stop();
+            } catch (KrbException e) {
+                e.printStackTrace();
+            } finally {
+                if(conf.getProperty(DEBUG) != null) {
+                    System.setProperty(SUN_SECURITY_KRB5_DEBUG,
+                            Boolean.toString(krb5Debug));
+                }
+            }
+        }
+        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) {
+        if (f.isFile()) {
+            if (! f.delete()) {
+                LOG.warn("WARNING: cannot delete file " + f.getAbsolutePath());
+            }
+        } else {
+            for (File c: f.listFiles()) {
+                delete(c);
+            }
+            if (! f.delete()) {
+                LOG.warn("WARNING: cannot delete directory " + f.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Creates a principal in the KDC with the specified user and password.
+     *
+     * @param principal principal name, do not include the domain.
+     * @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);
+    }
+
+    /**
+     * Creates multiple principals in the KDC and adds them to a keytab file.
+     *
+     * @param keytabFile keytab file to add the created principals.
+     * @param principals principals to add to the KDC, do not include the domain.
+     * @throws Exception thrown if the principals or the keytab file could not be
+     * created.
+     */
+    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);
+        }
+        for (String principal : principals) {
+            simpleKdc.getKadmin().exportKeytab(keytabFile, principal);
+        }
+    }
+
+    /**
+     * 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/5a29daed/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
new file mode 100644
index 0000000..a7bbf7f
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/MiniKdcTest.java
@@ -0,0 +1,184 @@
+/**
+ * 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.zookeeper.server.quorum.auth;
+
+import org.apache.kerby.kerberos.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.login.AppConfigurationEntry;
+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;
+import java.util.HashMap;
+import java.util.Arrays;
+
+/*
+ * This code is originally from HDFS, see the file name TestMiniKdc there
+ * in case of bug fixing, history, etc.
+ *
+ * Branch : trunk
+ * Github Revision: 916140604ffef59466ba30832478311d3e6249bd
+ */
+public class MiniKdcTest extends KerberosSecurityTestcase {
+    private static final boolean IBM_JAVA = System.getProperty("java.vendor")
+            .contains("IBM");
+
+    @Test(timeout = 60000)
+    public void testMiniKdcStart() {
+        MiniKdc kdc = getKdc();
+        Assert.assertNotSame(0, kdc.getPort());
+    }
+
+    @Test(timeout = 60000)
+    public void testKeytabGen() throws Exception {
+        MiniKdc kdc = getKdc();
+        File workDir = getWorkDir();
+
+        kdc.createPrincipal(new File(workDir, "keytab"), "foo/bar", "bar/foo");
+        List<PrincipalName> principalNameList =
+                Keytab.loadKeytab(new File(workDir, "keytab")).getPrincipals();
+
+        Set<String> principals = new HashSet<String>();
+        for (PrincipalName principalName : principalNameList) {
+          principals.add(principalName.getName());
+        }
+
+        Assert.assertEquals(new HashSet<String>(Arrays.asList(
+                "foo/bar@" + kdc.getRealm(), "bar/foo@" + kdc.getRealm())),
+                principals);
+      }
+
+    private static class KerberosConfiguration extends Configuration {
+        private String principal;
+        private String keytab;
+        private boolean isInitiator;
+
+        private KerberosConfiguration(String principal, File keytab,
+                boolean client) {
+            this.principal = principal;
+            this.keytab = keytab.getAbsolutePath();
+            this.isInitiator = client;
+        }
+
+        public static Configuration createClientConfig(String principal,
+                File keytab) {
+            return new KerberosConfiguration(principal, keytab, true);
+        }
+
+        public static Configuration createServerConfig(String principal,
+                File keytab) {
+            return new KerberosConfiguration(principal, keytab, false);
+        }
+
+        private static String getKrb5LoginModuleName() {
+            return System.getProperty("java.vendor").contains("IBM")
+                    ? "com.ibm.security.auth.module.Krb5LoginModule"
+                    : "com.sun.security.auth.module.Krb5LoginModule";
+        }
+
+        @Override
+        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+            Map<String, String> options = new HashMap<String, String>();
+            options.put("principal", principal);
+            options.put("refreshKrb5Config", "true");
+            if (IBM_JAVA) {
+                options.put("useKeytab", keytab);
+                options.put("credsType", "both");
+            } else {
+                options.put("keyTab", keytab);
+                options.put("useKeyTab", "true");
+                options.put("storeKey", "true");
+                options.put("doNotPrompt", "true");
+                options.put("useTicketCache", "true");
+                options.put("renewTGT", "true");
+                options.put("isInitiator", Boolean.toString(isInitiator));
+            }
+            String ticketCache = System.getenv("KRB5CCNAME");
+            if (ticketCache != null) {
+                options.put("ticketCache", ticketCache);
+            }
+            options.put("debug", "true");
+
+            return new AppConfigurationEntry[] {
+                    new AppConfigurationEntry(getKrb5LoginModuleName(),
+                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                            options) };
+        }
+    }
+
+    @Test(timeout = 60000)
+    public void testKerberosLogin() throws Exception {
+        MiniKdc kdc = getKdc();
+        File workDir = getWorkDir();
+        LoginContext loginContext = null;
+        try {
+            String principal = "foo";
+            File keytab = new File(workDir, "foo.keytab");
+            kdc.createPrincipal(keytab, principal);
+
+            Set<Principal> principals = new HashSet<Principal>();
+            principals.add(new KerberosPrincipal(principal));
+
+            // client login
+            Subject subject = new Subject(false, principals,
+                    new HashSet<Object>(), new HashSet<Object>());
+            loginContext = new LoginContext("", subject, null,
+                    KerberosConfiguration.createClientConfig(principal,
+                            keytab));
+            loginContext.login();
+            subject = loginContext.getSubject();
+            Assert.assertEquals(1, subject.getPrincipals().size());
+            Assert.assertEquals(KerberosPrincipal.class,
+                    subject.getPrincipals().iterator().next().getClass());
+            Assert.assertEquals(principal + "@" + kdc.getRealm(),
+                    subject.getPrincipals().iterator().next().getName());
+            loginContext.logout();
+
+            // server login
+            subject = new Subject(false, principals, new HashSet<Object>(),
+                    new HashSet<Object>());
+            loginContext = new LoginContext("", subject, null,
+                    KerberosConfiguration.createServerConfig(principal,
+                            keytab));
+            loginContext.login();
+            subject = loginContext.getSubject();
+            Assert.assertEquals(1, subject.getPrincipals().size());
+            Assert.assertEquals(KerberosPrincipal.class,
+                    subject.getPrincipals().iterator().next().getClass());
+            Assert.assertEquals(principal + "@" + kdc.getRealm(),
+                    subject.getPrincipals().iterator().next().getName());
+            loginContext.logout();
+
+        } finally {
+            if (loginContext != null) {
+                loginContext.logout();
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthTestBase.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthTestBase.java b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthTestBase.java
new file mode 100644
index 0000000..8978d17
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthTestBase.java
@@ -0,0 +1,146 @@
+/**
+ * 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.zookeeper.server.quorum.auth;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;
+import org.apache.zookeeper.test.ClientBase;
+import org.junit.Assert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * QuorumAuthTestBase provides a base class for testing quorum peer mutual
+ * authentication using SASL mechanisms.
+ */
+public class QuorumAuthTestBase extends ZKTestCase {
+    protected static final Logger LOG = LoggerFactory.getLogger(QuorumAuthTestBase.class);
+    protected List<MainThread> mt = new ArrayList<MainThread>();
+    protected static File jaasConfigDir;
+
+    public static void setupJaasConfig(String jaasEntries) {
+        try {
+            jaasConfigDir = ClientBase.createTmpDir();
+            File saslConfFile = new File(jaasConfigDir, "jaas.conf");
+            FileWriter fwriter = new FileWriter(saslConfFile);
+            fwriter.write(jaasEntries);
+            fwriter.close();
+            System.setProperty("java.security.auth.login.config",
+                    saslConfFile.getAbsolutePath());
+        } catch (IOException ioe) {
+            LOG.error("Failed to create tmp directory to hold JAAS conf file", ioe);
+            // could not create tmp directory to hold JAAS conf file : test will
+            // fail now.
+        }
+    }
+
+    public static void cleanupJaasConfig() {
+        if (jaasConfigDir != null) {
+            FileUtils.deleteQuietly(jaasConfigDir);
+        }
+    }
+
+    protected String startQuorum(final int serverCount,
+            Map<String, String> authConfigs, int authServerCount) throws IOException {
+        StringBuilder connectStr = new StringBuilder();
+        final int[] clientPorts = startQuorum(serverCount, connectStr,
+                authConfigs, authServerCount);
+        for (int i = 0; i < serverCount; i++) {
+            Assert.assertTrue("waiting for server " + i + " being up",
+                    ClientBase.waitForServerUp("127.0.0.1:" + clientPorts[i],
+                            ClientBase.CONNECTION_TIMEOUT));
+        }
+        return connectStr.toString();
+    }
+
+    protected int[] startQuorum(final int serverCount, StringBuilder connectStr,
+            Map<String, String> authConfigs, int authServerCount) throws IOException {
+        final int clientPorts[] = new int[serverCount];
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < serverCount; i++) {
+            clientPorts[i] = PortAssignment.unique();
+            String server = String.format(
+                    "server.%d=localhost:%d:%d:participant", i,
+                    PortAssignment.unique(), PortAssignment.unique());
+            sb.append(server + "\n");
+            connectStr.append("127.0.0.1:" + clientPorts[i]);
+            if (i < serverCount - 1) {
+                connectStr.append(",");
+            }
+        }
+        String quorumCfg = sb.toString();
+        // servers with authentication interfaces configured
+        int i = 0;
+        for (; i < authServerCount; i++) {
+            startServer(authConfigs, clientPorts, quorumCfg, i);
+        }
+        // servers without any authentication configured
+        for (int j = 0; j < serverCount - authServerCount; j++, i++) {
+            MainThread mthread = new MainThread(i, clientPorts[i], quorumCfg);
+            mt.add(mthread);
+            mthread.start();
+        }
+        return clientPorts;
+    }
+
+    private void startServer(Map<String, String> authConfigs,
+            final int[] clientPorts, String quorumCfg, int i)
+                    throws IOException {
+        MainThread mthread = new MainThread(i, clientPorts[i], quorumCfg,
+                authConfigs);
+        mt.add(mthread);
+        mthread.start();
+    }
+
+    protected void startServer(MainThread restartPeer,
+            Map<String, String> authConfigs) throws IOException {
+        MainThread mthread = new MainThread(restartPeer.getMyid(),
+                restartPeer.getClientPort(), restartPeer.getQuorumCfgSection(),
+                authConfigs);
+        mt.add(mthread);
+        mthread.start();
+    }
+
+    void shutdownAll() {
+        for (int i = 0; i < mt.size(); i++) {
+            shutdown(i);
+        }
+    }
+
+    MainThread shutdown(int index) {
+        MainThread mainThread = mt.get(index);
+        try {
+            mainThread.shutdown();
+        } catch (InterruptedException e) {
+        } finally {
+            mt.remove(index);
+        }
+        mainThread.deleteBaseDir();
+        return mainThread;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthUpgradeTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthUpgradeTest.java b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthUpgradeTest.java
new file mode 100644
index 0000000..3593245
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumAuthUpgradeTest.java
@@ -0,0 +1,239 @@
+/**
+ * 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.zookeeper.server.quorum.auth;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;
+import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.test.ClientTest;
+import org.apache.zookeeper.test.ClientBase.CountdownWatcher;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Rolling upgrade should do in three steps:
+ *
+ * step-1) Stop the server and set the flags and restart the server.
+ * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false and quorum.auth.serverRequireSasl=false
+ * Ensure that all the servers should complete this step. Now, move to next step.
+ *
+ * step-2) Stop the server one by one and change the flags and restart the server.
+ * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=false
+ * Ensure that all the servers should complete this step. Now, move to next step.
+ *
+ * step-3) Stop the server one by one and change the flags and restart the server.
+ * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=true
+ * Now, all the servers are fully upgraded and running in secured mode.
+ */
+public class QuorumAuthUpgradeTest extends QuorumAuthTestBase {
+    static {
+        String jaasEntries = new String("" + "QuorumServer {\n"
+                + "       org.apache.zookeeper.server.auth.DigestLoginModule required\n"
+                + "       user_test=\"mypassword\";\n" + "};\n"
+                + "QuorumLearner {\n"
+                + "       org.apache.zookeeper.server.auth.DigestLoginModule required\n"
+                + "       username=\"test\"\n"
+                + "       password=\"mypassword\";\n" + "};\n");
+        setupJaasConfig(jaasEntries);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        shutdownAll();
+    }
+
+    @AfterClass
+    public static void cleanup() {
+        cleanupJaasConfig();
+    }
+
+    /**
+     * Test to verify that servers are able to start without any authentication.
+     * peer0 -> quorum.auth.enableSasl=false
+     * peer1 -> quorum.auth.enableSasl=false
+     */
+    @Test(timeout = 30000)
+    public void testNullAuthLearnerServer() throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "false");
+
+        String connectStr = startQuorum(2, authConfigs, 0);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,
+                watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        zk.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        zk.close();
+    }
+
+    /**
+     * Test to verify that servers are able to form quorum.
+     * peer0 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false
+     * peer1 -> quorum.auth.enableSasl=false, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false
+     */
+    @Test(timeout = 30000)
+    public void testAuthLearnerAgainstNullAuthServer() throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+
+        String connectStr = startQuorum(2, authConfigs, 1);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,
+                watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        zk.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        zk.close();
+    }
+
+    /**
+     * Test to verify that servers are able to form quorum.
+     * peer0 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false
+     * peer1 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false
+     */
+    @Test(timeout = 30000)
+    public void testAuthLearnerAgainstNoAuthRequiredServer() throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+
+        String connectStr = startQuorum(2, authConfigs, 2);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,
+                watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        zk.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        zk.close();
+    }
+
+    /**
+     * Test to verify that servers are able to form quorum.
+     * peer0 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=true
+     * peer1 -> quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=true
+     */
+    @Test(timeout = 30000)
+    public void testAuthLearnerServer() throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+
+        String connectStr = startQuorum(2, authConfigs, 2);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,
+                watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        zk.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT);
+        zk.close();
+    }
+
+    /**
+     * Rolling upgrade should do in three steps:
+     *
+     * step-1) Stop the server and set the flags and restart the server.
+     * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=false and quorum.auth.serverRequireSasl=false
+     * Ensure that all the servers should complete this step. Now, move to next step.
+     *
+     * step-2) Stop the server one by one and change the flags and restart the server.
+     * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=false
+     * Ensure that all the servers should complete this step. Now, move to next step.
+     *
+     * step-3) Stop the server one by one and change the flags and restart the server.
+     * quorum.auth.enableSasl=true, quorum.auth.learnerRequireSasl=true and quorum.auth.serverRequireSasl=true
+     * Now, all the servers are fully upgraded and running in secured mode.
+     */
+    @Test(timeout = 90000)
+    public void testRollingUpgrade() throws Exception {
+        // Start peer0,1,2 servers with quorum.auth.enableSasl=false and
+        // quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false
+        // Assume this is an existing cluster.
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "false");
+
+        String connectStr = startQuorum(3, authConfigs, 0);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,
+                watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        zk.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT_SEQUENTIAL);
+
+        //1. Upgrade peer0,1,2 with quorum.auth.enableSasl=true and
+        // quorum.auth.learnerRequireSasl=false, quorum.auth.serverRequireSasl=false
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "false");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "false");
+        restartServer(authConfigs, 0, zk, watcher);
+        restartServer(authConfigs, 1, zk, watcher);
+        restartServer(authConfigs, 2, zk, watcher);
+
+        //2. Upgrade peer0,1,2 with quorum.auth.enableSasl=true and
+        // quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=false
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "false");
+        restartServer(authConfigs, 0, zk, watcher);
+        restartServer(authConfigs, 1, zk, watcher);
+        restartServer(authConfigs, 2, zk, watcher);
+
+        //3. Upgrade peer0,1,2 with quorum.auth.enableSasl=true and
+        // quorum.auth.learnerRequireSasl=true, quorum.auth.serverRequireSasl=true
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        restartServer(authConfigs, 0, zk, watcher);
+        restartServer(authConfigs, 1, zk, watcher);
+        restartServer(authConfigs, 2, zk, watcher);
+
+        //4. Restart peer2 with quorum.auth.learnerEnableSasl=false and
+        // quorum.auth.serverRequireSasl=false. It should fail to join the
+        // quorum as this needs auth.
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "false");
+        MainThread m = shutdown(2);
+        startServer(m, authConfigs);
+        Assert.assertFalse("waiting for server 2 being up", ClientBase
+                .waitForServerUp("127.0.0.1:" + m.getClientPort(), 5000));
+    }
+
+    private void restartServer(Map<String, String> authConfigs, int index,
+            ZooKeeper zk, CountdownWatcher watcher) throws IOException,
+                    KeeperException, InterruptedException, TimeoutException {
+        LOG.info("Restarting server myid=" + index);
+        MainThread m = shutdown(index);
+        startServer(m, authConfigs);
+        Assert.assertTrue("waiting for server" + index + "being up",
+                ClientBase.waitForServerUp("127.0.0.1:" + m.getClientPort(),
+                        ClientBase.CONNECTION_TIMEOUT));
+        watcher.waitForConnected(ClientTest.CONNECTION_TIMEOUT);
+        zk.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE,
+                CreateMode.PERSISTENT_SEQUENTIAL);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumDigestAuthTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumDigestAuthTest.java b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumDigestAuthTest.java
new file mode 100644
index 0000000..5eebdb3
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumDigestAuthTest.java
@@ -0,0 +1,222 @@
+/**
+ * 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.zookeeper.server.quorum.auth;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.server.admin.AdminServer;
+import org.apache.zookeeper.server.quorum.QuorumPeerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerTestBase;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
+import org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;
+import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.test.ClientBase.CountdownWatcher;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class QuorumDigestAuthTest extends QuorumAuthTestBase {
+
+    static {
+        String jaasEntries = new String(""
+                + "QuorumServer {\n"
+                + "       org.apache.zookeeper.server.auth.DigestLoginModule required\n"
+                + "       user_test=\"mypassword\";\n" + "};\n"
+                + "QuorumLearner {\n"
+                + "       org.apache.zookeeper.server.auth.DigestLoginModule required\n"
+                + "       username=\"test\"\n"
+                + "       password=\"mypassword\";\n" + "};\n"
+                + "QuorumLearnerInvalid {\n"
+                + "       org.apache.zookeeper.server.auth.DigestLoginModule required\n"
+                + "       username=\"test\"\n"
+                + "       password=\"invalid\";\n" + "};" + "\n");
+        setupJaasConfig(jaasEntries);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        for (MainThread mainThread : mt) {
+            mainThread.shutdown();
+            mainThread.deleteBaseDir();
+        }
+    }
+
+    @AfterClass
+    public static void cleanup(){
+        cleanupJaasConfig();
+    }
+
+    /**
+     * Test to verify that server is able to start with valid credentials
+     */
+    @Test(timeout = 30000)
+    public void testValidCredentials() throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+
+        String connectStr = startQuorum(3, authConfigs, 3);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,
+                watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        for (int i = 0; i < 10; i++) {
+            zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,
+                    CreateMode.PERSISTENT);
+        }
+        zk.close();
+    }
+
+    /**
+     * Test to verify that server is able to start with invalid credentials if
+     * the configuration is set to quorum.auth.serverRequireSasl=false.
+     * Quorum will talk each other even if the authentication is not succeeded
+     */
+    @Test(timeout = 30000)
+    public void testSaslNotRequiredWithInvalidCredentials() throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT, "QuorumLearnerInvalid");
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "false");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "false");
+        String connectStr = startQuorum(3, authConfigs, 3);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT,
+                watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        for (int i = 0; i < 10; i++) {
+            zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE,
+                    CreateMode.PERSISTENT);
+        }
+        zk.close();
+    }
+
+    /**
+     * Test to verify that server shouldn't start with invalid credentials
+     * if the configuration is set to quorum.auth.serverRequireSasl=true,
+     * quorum.auth.learnerRequireSasl=true
+     */
+    @Test(timeout = 30000)
+    public void testSaslRequiredInvalidCredentials() throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT, "QuorumLearnerInvalid");
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+        int serverCount = 2;
+        final int[] clientPorts = startQuorum(serverCount, new StringBuilder(),
+                authConfigs, serverCount);
+        for (int i = 0; i < serverCount; i++) {
+            boolean waitForServerUp = ClientBase.waitForServerUp(
+                    "127.0.0.1:" + clientPorts[i], QuorumPeerTestBase.TIMEOUT);
+            Assert.assertFalse("Shouldn't start server with invalid credentials",
+                    waitForServerUp);
+        }
+    }
+
+    /**
+     * If quorumpeer learner is not auth enabled then self won't be able to join
+     * quorum. So this test is ensuring that the quorumpeer learner is also auth
+     * enabled while enabling quorum server require sasl.
+     */
+    @Test(timeout = 10000)
+    public void testEnableQuorumServerRequireSaslWithoutQuorumLearnerRequireSasl()
+            throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT,
+                "QuorumLearner");
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "false");
+        MainThread mthread = new MainThread(1, PortAssignment.unique(), "",
+                authConfigs);
+        String args[] = new String[1];
+        args[0] = mthread.getConfFile().toString();
+        try {
+            new QuorumPeerMain() {
+                @Override
+                protected void initializeAndRun(String[] args)
+                        throws ConfigException, IOException, AdminServer.AdminServerException {
+                    super.initializeAndRun(args);
+                }
+            }.initializeAndRun(args);
+            Assert.fail("Must throw exception as quorumpeer learner is not enabled!");
+        } catch (ConfigException e) {
+            // expected
+        }
+    }
+
+
+    /**
+     * If quorumpeer learner is not auth enabled then self won't be able to join
+     * quorum. So this test is ensuring that the quorumpeer learner is also auth
+     * enabled while enabling quorum server require sasl.
+     */
+    @Test(timeout = 10000)
+    public void testEnableQuorumAuthenticationConfigurations()
+            throws Exception {
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT,
+                "QuorumLearner");
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "false");
+
+        // case-1) 'quorum.auth.enableSasl' is off. Tries to enable server sasl.
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "false");
+        MainThread mthread = new MainThread(1, PortAssignment.unique(), "",
+                authConfigs);
+        String args[] = new String[1];
+        args[0] = mthread.getConfFile().toString();
+        try {
+            new QuorumPeerMain() {
+                @Override
+                protected void initializeAndRun(String[] args)
+                        throws ConfigException, IOException, AdminServer.AdminServerException {
+                    super.initializeAndRun(args);
+                }
+            }.initializeAndRun(args);
+            Assert.fail("Must throw exception as quorum sasl is not enabled!");
+        } catch (ConfigException e) {
+            // expected
+        }
+
+        // case-1) 'quorum.auth.enableSasl' is off. Tries to enable learner sasl.
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "false");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+        try {
+            new QuorumPeerMain() {
+                @Override
+                protected void initializeAndRun(String[] args)
+                        throws ConfigException, IOException, AdminServer.AdminServerException {
+                    super.initializeAndRun(args);
+                }
+            }.initializeAndRun(args);
+            Assert.fail("Must throw exception as quorum sasl is not enabled!");
+        } catch (ConfigException e) {
+            // expected
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosAuthTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosAuthTest.java b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosAuthTest.java
new file mode 100644
index 0000000..2cc56a7
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosAuthTest.java
@@ -0,0 +1,110 @@
+/**
+ * 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.zookeeper.server.quorum.auth;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;
+import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.test.ClientBase.CountdownWatcher;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+public class QuorumKerberosAuthTest extends KerberosSecurityTestcase {
+    private static File keytabFile;
+    static {
+        String keytabFilePath = FilenameUtils.normalize(KerberosTestUtils.getKeytabFile(), true);
+        String jaasEntries = new String(""
+                + "QuorumServer {\n"
+                + "       com.sun.security.auth.module.Krb5LoginModule required\n"
+                + "       useKeyTab=true\n"
+                + "       keyTab=\"" + keytabFilePath + "\"\n"
+                + "       storeKey=true\n"
+                + "       useTicketCache=false\n"
+                + "       debug=false\n"
+                + "       principal=\"" + KerberosTestUtils.getServerPrincipal() + "\";\n" + "};\n"
+                + "QuorumLearner {\n"
+                + "       com.sun.security.auth.module.Krb5LoginModule required\n"
+                + "       useKeyTab=true\n"
+                + "       keyTab=\"" + keytabFilePath + "\"\n"
+                + "       storeKey=true\n"
+                + "       useTicketCache=false\n"
+                + "       debug=false\n"
+                + "       principal=\"" + KerberosTestUtils.getLearnerPrincipal() + "\";\n" + "};\n");
+        setupJaasConfig(jaasEntries);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        // create keytab
+        keytabFile = new File(KerberosTestUtils.getKeytabFile());
+        String learnerPrincipal = KerberosTestUtils.getLearnerPrincipal();
+        String serverPrincipal = KerberosTestUtils.getServerPrincipal();
+        learnerPrincipal = learnerPrincipal.substring(0, learnerPrincipal.lastIndexOf("@"));
+        serverPrincipal = serverPrincipal.substring(0, serverPrincipal.lastIndexOf("@"));
+        getKdc().createPrincipal(keytabFile, learnerPrincipal, serverPrincipal);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        for (MainThread mainThread : mt) {
+            mainThread.shutdown();
+            mainThread.deleteBaseDir();
+        }
+    }
+
+    @AfterClass
+    public static void cleanup() {
+        if(keytabFile != null){
+            FileUtils.deleteQuietly(keytabFile);
+        }
+        cleanupJaasConfig();
+    }
+
+    /**
+     * Test to verify that server is able to start with valid credentials
+     */
+    @Test(timeout = 120000)
+    public void testValidCredentials() throws Exception {
+        String serverPrincipal = KerberosTestUtils.getServerPrincipal();
+        serverPrincipal = serverPrincipal.substring(0, serverPrincipal.lastIndexOf("@"));
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);
+        String connectStr = startQuorum(3, authConfigs, 3);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        for (int i = 0; i < 10; i++) {
+            zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        }
+        zk.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosHostBasedAuthTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosHostBasedAuthTest.java b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosHostBasedAuthTest.java
new file mode 100644
index 0000000..fcb7691
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/quorum/auth/QuorumKerberosHostBasedAuthTest.java
@@ -0,0 +1,184 @@
+/**
+ * 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.zookeeper.server.quorum.auth;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.server.quorum.QuorumPeerTestBase.MainThread;
+import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.test.ClientBase.CountdownWatcher;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import junit.framework.Assert;
+
+public class QuorumKerberosHostBasedAuthTest extends KerberosSecurityTestcase {
+    private static File keytabFile;
+    private static String hostServerPrincipal = KerberosTestUtils.getHostServerPrincipal();
+    private static String hostLearnerPrincipal = KerberosTestUtils.getHostLearnerPrincipal();
+    private static String hostNamedLearnerPrincipal = KerberosTestUtils.getHostNamedLearnerPrincipal("myHost");
+    static {
+        setupJaasConfigEntries(hostServerPrincipal, hostLearnerPrincipal, hostNamedLearnerPrincipal);
+    }
+
+    private static void setupJaasConfigEntries(String hostServerPrincipal,
+            String hostLearnerPrincipal, String hostNamedLearnerPrincipal) {
+        String keytabFilePath = FilenameUtils.normalize(KerberosTestUtils.getKeytabFile(), true);
+        String jaasEntries = new String(""
+                + "QuorumServer {\n"
+                + "       com.sun.security.auth.module.Krb5LoginModule required\n"
+                + "       useKeyTab=true\n"
+                + "       keyTab=\"" + keytabFilePath + "\"\n"
+                + "       storeKey=true\n"
+                + "       useTicketCache=false\n"
+                + "       debug=false\n"
+                + "       principal=\"" + KerberosTestUtils.replaceHostPattern(hostServerPrincipal) + "\";\n" + "};\n"
+                + "QuorumLearner {\n"
+                + "       com.sun.security.auth.module.Krb5LoginModule required\n"
+                + "       useKeyTab=true\n"
+                + "       keyTab=\"" + keytabFilePath + "\"\n"
+                + "       storeKey=true\n"
+                + "       useTicketCache=false\n"
+                + "       debug=false\n"
+                + "       principal=\"" + KerberosTestUtils.replaceHostPattern(hostLearnerPrincipal) + "\";\n" + "};\n"
+                + "QuorumLearnerMyHost {\n"
+                + "       com.sun.security.auth.module.Krb5LoginModule required\n"
+                + "       useKeyTab=true\n"
+                + "       keyTab=\"" + keytabFilePath + "\"\n"
+                + "       storeKey=true\n"
+                + "       useTicketCache=false\n"
+                + "       debug=false\n"
+                + "       principal=\"" + hostNamedLearnerPrincipal + "\";\n" + "};\n");
+        setupJaasConfig(jaasEntries);
+    }
+
+    @BeforeClass
+    public static void setUp() throws Exception {
+        // create keytab
+        keytabFile = new File(KerberosTestUtils.getKeytabFile());
+
+        // Creates principals in the KDC and adds them to a keytab file.
+        String learnerPrincipal = hostLearnerPrincipal.substring(0, hostLearnerPrincipal.lastIndexOf("@"));
+        learnerPrincipal = KerberosTestUtils.replaceHostPattern(learnerPrincipal);
+        String serverPrincipal = hostServerPrincipal.substring(0, hostServerPrincipal.lastIndexOf("@"));
+        serverPrincipal = KerberosTestUtils.replaceHostPattern(serverPrincipal);
+
+        // learner with ipaddress in principal
+        String learnerPrincipal2 = hostNamedLearnerPrincipal.substring(0, hostNamedLearnerPrincipal.lastIndexOf("@"));
+        getKdc().createPrincipal(keytabFile, learnerPrincipal, learnerPrincipal2, serverPrincipal);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        for (MainThread mainThread : mt) {
+            mainThread.shutdown();
+            mainThread.deleteBaseDir();
+        }
+    }
+
+    @AfterClass
+    public static void cleanup() {
+        if(keytabFile != null){
+            FileUtils.deleteQuietly(keytabFile);
+        }
+        cleanupJaasConfig();
+    }
+
+    /**
+     * Test to verify that server is able to start with valid credentials
+     */
+    @Test(timeout = 120000)
+    public void testValidCredentials() throws Exception {
+        String serverPrincipal = hostServerPrincipal.substring(0, hostServerPrincipal.lastIndexOf("@"));
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);
+        String connectStr = startQuorum(3, authConfigs, 3);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        for (int i = 0; i < 10; i++) {
+            zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        }
+        zk.close();
+    }
+
+    /**
+     * Test to verify that the bad server connection to the quorum should be rejected.
+     */
+    @Test(timeout = 120000)
+    public void testConnectBadServer() throws Exception {
+        String serverPrincipal = hostServerPrincipal.substring(0, hostServerPrincipal.lastIndexOf("@"));
+        Map<String, String> authConfigs = new HashMap<String, String>();
+        authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
+        authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);
+        String connectStr = startQuorum(3, authConfigs, 3);
+        CountdownWatcher watcher = new CountdownWatcher();
+        ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);
+        watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+        for (int i = 0; i < 10; i++) {
+            zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        }
+        zk.close();
+
+        String quorumCfgSection = mt.get(0).getQuorumCfgSection();
+        StringBuilder sb = new StringBuilder();
+        sb.append(quorumCfgSection);
+
+        int myid = mt.size() + 1;
+        final int clientPort = PortAssignment.unique();
+        String server = String.format("server.%d=localhost:%d:%d:participant",
+                myid, PortAssignment.unique(), PortAssignment.unique());
+        sb.append(server + "\n");
+        quorumCfgSection = sb.toString();
+        authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_LOGIN_CONTEXT,
+                "QuorumLearnerMyHost");
+        MainThread badServer = new MainThread(myid, clientPort, quorumCfgSection,
+                authConfigs);
+        badServer.start();
+        watcher = new CountdownWatcher();
+        connectStr = "127.0.0.1:" + clientPort;
+        zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);
+        try{
+            watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT/3);
+            Assert.fail("Must throw exception as the myHost is not an authorized one!");
+        } catch (TimeoutException e){
+            // expected
+        } finally {
+            zk.close();
+            badServer.shutdown();
+            badServer.deleteBaseDir();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/java/test/org/apache/zookeeper/test/CnxManagerTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/test/CnxManagerTest.java b/src/java/test/org/apache/zookeeper/test/CnxManagerTest.java
index b0eea13..a072bc0 100644
--- a/src/java/test/org/apache/zookeeper/test/CnxManagerTest.java
+++ b/src/java/test/org/apache/zookeeper/test/CnxManagerTest.java
@@ -109,7 +109,7 @@ public class CnxManagerTest extends ZKTestCase {
         public void run(){
             try {
                 QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[0], peerTmpdir[0], peerClientPort[0], 3, 0, 1000, 2, 2);
-                QuorumCnxManager cnxManager = new QuorumCnxManager(peer);
+                QuorumCnxManager cnxManager = peer.createCnxnManager();
                 QuorumCnxManager.Listener listener = cnxManager.listener;
                 if(listener != null){
                     listener.start();
@@ -153,7 +153,7 @@ public class CnxManagerTest extends ZKTestCase {
         thread.start();
 
         QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 1000, 2, 2);
-        QuorumCnxManager cnxManager = new QuorumCnxManager(peer);
+        QuorumCnxManager cnxManager = peer.createCnxnManager();
         QuorumCnxManager.Listener listener = cnxManager.listener;
         if(listener != null){
             listener.start();
@@ -200,7 +200,7 @@ public class CnxManagerTest extends ZKTestCase {
         peerTmpdir[2] = ClientBase.createTmpDir();
 
         QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 1000, 2, 2);
-        QuorumCnxManager cnxManager = new QuorumCnxManager(peer);
+        QuorumCnxManager cnxManager = peer.createCnxnManager();
         QuorumCnxManager.Listener listener = cnxManager.listener;
         if(listener != null){
             listener.start();
@@ -228,7 +228,7 @@ public class CnxManagerTest extends ZKTestCase {
     @Test
     public void testCnxManagerSpinLock() throws Exception {
         QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 1000, 2, 2);
-        QuorumCnxManager cnxManager = new QuorumCnxManager(peer);
+        QuorumCnxManager cnxManager = peer.createCnxnManager();
         QuorumCnxManager.Listener listener = cnxManager.listener;
         if(listener != null){
             listener.start();
@@ -293,7 +293,7 @@ public class CnxManagerTest extends ZKTestCase {
         peers.get(2L).type = LearnerType.OBSERVER;
         QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1],
                 peerClientPort[1], 3, 1, 1000, 2, 2);
-        QuorumCnxManager cnxManager = new QuorumCnxManager(peer);
+        QuorumCnxManager cnxManager = peer.createCnxnManager();
         QuorumCnxManager.Listener listener = cnxManager.listener;
         if (listener != null) {
             listener.start();
@@ -340,7 +340,7 @@ public class CnxManagerTest extends ZKTestCase {
     @Test
     public void testSocketTimeout() throws Exception {
         QuorumPeer peer = new QuorumPeer(peers, peerTmpdir[1], peerTmpdir[1], peerClientPort[1], 3, 1, 2000, 2, 2);
-        QuorumCnxManager cnxManager = new QuorumCnxManager(peer);
+        QuorumCnxManager cnxManager = peer.createCnxnManager();
         QuorumCnxManager.Listener listener = cnxManager.listener;
         if(listener != null){
             listener.start();

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/java/test/org/apache/zookeeper/test/FLEPredicateTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/test/FLEPredicateTest.java b/src/java/test/org/apache/zookeeper/test/FLEPredicateTest.java
index a4244d8..bc43775 100644
--- a/src/java/test/org/apache/zookeeper/test/FLEPredicateTest.java
+++ b/src/java/test/org/apache/zookeeper/test/FLEPredicateTest.java
@@ -41,7 +41,7 @@ public class FLEPredicateTest extends ZKTestCase {
     
     class MockFLE extends FastLeaderElection {
         MockFLE(QuorumPeer peer){
-            super(peer, new QuorumCnxManager(peer));
+            super(peer, peer.createCnxnManager());
         }
         
         boolean predicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch){

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/5a29daed/src/zookeeper.jute
----------------------------------------------------------------------
diff --git a/src/zookeeper.jute b/src/zookeeper.jute
index a404e78..2533ddf 100644
--- a/src/zookeeper.jute
+++ b/src/zookeeper.jute
@@ -236,6 +236,11 @@ module org.apache.zookeeper.server.quorum {
         buffer data; // Only significant when type is request
         vector<org.apache.zookeeper.data.Id> authinfo;
     }
+    class QuorumAuthPacket {
+        long magic;
+        int status;
+        buffer token;
+    }
 }
 
 module org.apache.zookeeper.server.persistence {


Mime
View raw message