Author: rkanter
Date: Tue Dec  3 01:41:59 2013
New Revision: 1547259

URL: http://svn.apache.org/r1547259
Log:
OOZIE-1491 Make sure HA works with a secure ZooKeeper (rkanter)

Added:
    oozie/trunk/core/src/main/java/org/apache/oozie/util/JaasConfiguration.java
    
oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCaseWithSecurity.java
    
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestJaasConfiguration.java
    
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtilsWithSecurity.java
Modified:
    oozie/trunk/core/pom.xml
    oozie/trunk/core/src/main/java/org/apache/oozie/util/ZKUtils.java
    oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCase.java
    oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtils.java
    oozie/trunk/docs/src/site/twiki/AG_Install.twiki
    oozie/trunk/pom.xml
    oozie/trunk/release-log.txt

Modified: oozie/trunk/core/pom.xml
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/pom.xml?rev=1547259&r1=1547258&r2=1547259&view=diff
==============================================================================
--- oozie/trunk/core/pom.xml (original)
+++ oozie/trunk/core/pom.xml Tue Dec  3 01:41:59 2013
@@ -43,6 +43,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>hadoop-minikdc</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.oozie</groupId>
             <artifactId>oozie-hadoop</artifactId>
             <scope>provided</scope>
@@ -427,6 +433,12 @@
                     </dependency>
                 </dependencies>
             </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <inherited>true</inherited>
+                <extensions>true</extensions>
+            </plugin>
         </plugins>
     </build>
 

Added: 
oozie/trunk/core/src/main/java/org/apache/oozie/util/JaasConfiguration.java
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/src/main/java/org/apache/oozie/util/JaasConfiguration.java?rev=1547259&view=auto
==============================================================================
--- oozie/trunk/core/src/main/java/org/apache/oozie/util/JaasConfiguration.java 
(added)
+++ oozie/trunk/core/src/main/java/org/apache/oozie/util/JaasConfiguration.java 
Tue Dec  3 01:41:59 2013
@@ -0,0 +1,116 @@
+/**
+ * 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.oozie.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+
+/**
+ * Creates a programmatic version of a jaas.conf file.  This can be used 
instead of writing a jaas.conf file and setting
+ * the system property, "java.security.auth.login.config", to point to that 
file.  It is meant to be used for connecting to
+ * ZooKeeper.
+ * <p>
+ * example usage:
+ * JaasConfiguration.addEntry("Client", principal, keytabFile);
+ * 
javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
+ */
+public class JaasConfiguration extends Configuration {
+    private static Map<String, AppConfigurationEntry> entries = new 
HashMap<String, AppConfigurationEntry>();
+    private static JaasConfiguration me = null;
+    private static final String krb5LoginModuleName;
+
+    static  {
+        if (System.getProperty("java.vendor").contains("IBM")) {
+            krb5LoginModuleName = 
"com.ibm.security.auth.module.Krb5LoginModule";
+        }
+        else {
+            krb5LoginModuleName = 
"com.sun.security.auth.module.Krb5LoginModule";
+        }
+    }
+
+    private JaasConfiguration() {
+        // don't need to do anything here but we want to make it private
+    }
+
+    /**
+     * Return the singleton.  You'd typically use it only to do this:
+     * <p>
+     * 
javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
+     *
+     * @return
+     */
+    public static Configuration getInstance() {
+        if (me == null) {
+            me = new JaasConfiguration();
+        }
+        return me;
+    }
+
+    /**
+     * Add an entry to the jaas configuration with the passed in name, 
principal, and keytab.  The other necessary options will be
+     * set for you.
+     *
+     * @param name The name of the entry (e.g. "Client")
+     * @param principal The principal of the user
+     * @param keytab The location of the keytab
+     */
+    public static void addEntry(String name, String principal, String keytab) {
+        Map<String, String> options = new HashMap<String, String>();
+        options.put("keyTab", keytab);
+        options.put("principal", principal);
+        options.put("useKeyTab", "true");
+        options.put("storeKey", "true");
+        options.put("useTicketCache", "false");
+        AppConfigurationEntry entry = new 
AppConfigurationEntry(krb5LoginModuleName,
+                AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 
options);
+        entries.put(name, entry);
+    }
+
+    /**
+     * Removes the specified entry.
+     *
+     * @param name  The name of the entry to remove
+     */
+    public static void removeEntry(String name) {
+        entries.remove(name);
+    }
+
+    /**
+     * Clears all entries.
+     */
+    public static void clearEntries() {
+        entries.clear();
+    }
+
+    /**
+     * Returns the entries map.
+     *
+     * @return the entries map
+     */
+    public static Map<String, AppConfigurationEntry> getEntries() {
+        return entries;
+    }
+
+    @Override
+    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+        return new AppConfigurationEntry[]{entries.get(name)};
+    }
+}

Modified: oozie/trunk/core/src/main/java/org/apache/oozie/util/ZKUtils.java
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/src/main/java/org/apache/oozie/util/ZKUtils.java?rev=1547259&r1=1547258&r2=1547259&view=diff
==============================================================================
--- oozie/trunk/core/src/main/java/org/apache/oozie/util/ZKUtils.java (original)
+++ oozie/trunk/core/src/main/java/org/apache/oozie/util/ZKUtils.java Tue Dec  
3 01:41:59 2013
@@ -18,14 +18,19 @@
 package org.apache.oozie.util;
 
 import com.google.common.annotations.VisibleForTesting;
+import java.io.IOException;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.security.auth.login.Configuration;
 import org.apache.curator.RetryPolicy;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.api.ACLProvider;
+import org.apache.curator.framework.imps.DefaultACLProvider;
 import org.apache.curator.retry.ExponentialBackoffRetry;
 import org.apache.curator.utils.EnsurePath;
 import org.apache.curator.x.discovery.ServiceCache;
@@ -33,7 +38,16 @@ import org.apache.curator.x.discovery.Se
 import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
 import org.apache.curator.x.discovery.ServiceInstance;
 import org.apache.curator.x.discovery.details.InstanceSerializer;
+import org.apache.oozie.ErrorCode;
+import static org.apache.oozie.service.HadoopAccessorService.KERBEROS_KEYTAB;
+import static 
org.apache.oozie.service.HadoopAccessorService.KERBEROS_PRINCIPAL;
+import org.apache.oozie.service.ServiceException;
 import org.apache.oozie.service.Services;
+import org.apache.zookeeper.ZooDefs.Perms;
+import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+import org.apache.zookeeper.data.Stat;
 
 
 /**
@@ -48,10 +62,15 @@ import org.apache.oozie.service.Services
  * Each Oozie Server provides metadata that can be shared with the other Oozie 
Servers.  To keep things simple and to make it easy
  * to add additional metadata in the future, we share a Map.  They keys are 
defined in {@link ZKMetadataKeys}.
  * <p>
- * For the service discovery, the structure in ZooKeeper is 
/oozie.zookeeper.namespace/ZK_BASE_PATH/ (default is /oozie/services/).
- * There is currently only one service, named "servers" under which each Oozie 
server creates a ZNode named
+ * For the service discovery, the structure in ZooKeeper is 
/oozie.zookeeper.namespace/ZK_BASE_SERVICES_PATH/ (default is
+ * /oozie/services/).  There is currently only one service, named "servers" 
under which each Oozie server creates a ZNode named
  * ${OOZIE_SERVICE_INSTANCE} (default is the hostname) that contains the 
metadata payload.  For example, with the default settings,
  * an Oozie server named "foo" would create a ZNode at 
/oozie/services/servers/foo where the foo ZNode contains the metadata.
+ * <p>
+ * If oozie.zookeeper.secure is set to true, then Oozie will (a) use jaas to 
connect to ZooKeeper using SASL/Kerberos based on
+ * Oozie's existing security configuration parameters (b) use/convert every 
znode under the namespace (including the namespace
+ * itself) to have ACLs such that only Oozie servers have access (i.e. if 
"service/host@REALM" is the Kerberos principal, then
+ * "service" will be used for the ACLs).
  */
 public class ZKUtils {
     /**
@@ -70,8 +89,13 @@ public class ZKUtils {
      */
     public static final String OOZIE_INSTANCE_ID = "oozie.instance.id";
 
+    /**
+     * oozie-site property for specifying that ZooKeeper is secure.
+     */
+    public static final String ZK_SECURE = "oozie.zookeeper.secure";
+
     private static final String ZK_OOZIE_SERVICE = "servers";
-    private static final String ZK_BASE_PATH = "/services";
+    private static final String ZK_BASE_SERVICES_PATH = "/services";
 
     private static Set<Object> users = new HashSet<Object>();
     private CuratorFramework client = null;
@@ -79,6 +103,7 @@ public class ZKUtils {
     private long zkRegTime;
     private ServiceDiscovery<Map> sDiscovery;
     private ServiceCache<Map> sCache;
+    private List<ACL> saslACL;
     private XLog log;
 
     private static ZKUtils zk = null;
@@ -93,6 +118,7 @@ public class ZKUtils {
         zkId = System.getProperty(OOZIE_INSTANCE_ID);
         createClient();
         advertiseService();
+        checkAndSetACLs();
     }
 
     /**
@@ -130,20 +156,33 @@ public class ZKUtils {
         RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
         String zkConnectionString = 
Services.get().getConf().get(ZK_CONNECTION_STRING, "localhost:2181");
         String zkNamespace = Services.get().getConf().get(ZK_NAMESPACE, 
"oozie");
+        ACLProvider aclProvider;
+        if (Services.get().getConf().getBoolean(ZK_SECURE, false)) {
+            log.info("Connecting to ZooKeeper with SASL/Kerberos and using 
'sasl' ACLs");
+            setJaasConfiguration();
+            System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, 
"Client");
+            System.setProperty("zookeeper.authProvider.1", 
"org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+            saslACL = Collections.singletonList(new ACL(Perms.ALL, new 
Id("sasl", getServicePrincipal())));
+            aclProvider = new SASLOwnerACLProvider();
+        } else {
+            log.info("Connecting to ZooKeeper without authentication");
+            aclProvider = new DefaultACLProvider();     // open to everyone
+        }
         client = CuratorFrameworkFactory.builder()
                                             .namespace(zkNamespace)
                                             .connectString(zkConnectionString)
                                             .retryPolicy(retryPolicy)
+                                            .aclProvider(aclProvider)
                                             .build();
         client.start();
     }
 
     private void advertiseService() throws Exception {
         // Advertise on the service discovery
-        new EnsurePath(ZK_BASE_PATH).ensure(client.getZookeeperClient());
+        new 
EnsurePath(ZK_BASE_SERVICES_PATH).ensure(client.getZookeeperClient());
         InstanceSerializer<Map> instanceSerializer = new 
FixedJsonInstanceSerializer<Map>(Map.class);
         sDiscovery = ServiceDiscoveryBuilder.builder(Map.class)
-                                                .basePath(ZK_BASE_PATH)
+                                                
.basePath(ZK_BASE_SERVICES_PATH)
                                                 .client(client)
                                                 .serializer(instanceSerializer)
                                                 .build();
@@ -196,7 +235,6 @@ public class ZKUtils {
      * or two stale.
      *
      * @return a List of the metadata provided by all of the Oozie Servers.
-     * @throws Exception
      */
     public List<ServiceInstance<Map>> getAllMetaData() {
         List<ServiceInstance<Map>> instances = null;
@@ -245,6 +283,59 @@ public class ZKUtils {
         return index;
     }
 
+    private void checkAndSetACLs() throws Exception {
+        if (Services.get().getConf().getBoolean(ZK_SECURE, false)) {
+            // If znodes were previously created without security enabled, and 
now it is, we need to go through all existing znodes
+            // and set the ACLs for them
+            // We can't get the namespace znode through curator; have to go 
through zk client
+            String namespace = "/" + client.getNamespace();
+            if (client.getZookeeperClient().getZooKeeper().exists(namespace, 
null) != null) {
+                List<ACL> acls = 
client.getZookeeperClient().getZooKeeper().getACL(namespace, new Stat());
+                if (!acls.get(0).getId().getScheme().equals("sasl")) {
+                    log.info("'sasl' ACLs not set; setting...");
+                    List<String> children = 
client.getZookeeperClient().getZooKeeper().getChildren(namespace, null);
+                    for (String child : children) {
+                        checkAndSetACLs(child);
+                    }
+                    
client.getZookeeperClient().getZooKeeper().setACL(namespace, saslACL, -1);
+                }
+            }
+        }
+    }
+
+    private void checkAndSetACLs(String path) throws Exception {
+        List<String> children = client.getChildren().forPath(path);
+        for (String child : children) {
+            checkAndSetACLs(path + "/" + child);
+        }
+        client.setACL().withACL(saslACL).forPath(path);
+    }
+
+    // This gets ignored during most tests, see 
ZKXTestCaseWithSecurity#setupZKServer()
+    private void setJaasConfiguration() throws ServiceException, IOException {
+        String keytabFile = Services.get().getConf().get(KERBEROS_KEYTAB, 
System.getProperty("user.home") + "/oozie.keytab").trim();
+        if (keytabFile.length() == 0) {
+            throw new ServiceException(ErrorCode.E0026, KERBEROS_KEYTAB);
+        }
+        String principal = Services.get().getConf().get(KERBEROS_PRINCIPAL, 
"oozie/localhost@LOCALHOST");
+        if (principal.length() == 0) {
+            throw new ServiceException(ErrorCode.E0026, KERBEROS_PRINCIPAL);
+        }
+
+        // This is equivalent to writing a jaas.conf file and setting the 
system property, "java.security.auth.login.config", to
+        // point to it (but this way we don't have to write a file, and it 
works better for the tests)
+        JaasConfiguration.addEntry("Client", principal, keytabFile);
+        Configuration.setConfiguration(JaasConfiguration.getInstance());
+    }
+
+    private String getServicePrincipal() throws ServiceException {
+        String principal = Services.get().getConf().get(KERBEROS_PRINCIPAL, 
"oozie/localhost@LOCALHOST");
+        if (principal.length() == 0) {
+            throw new ServiceException(ErrorCode.E0026, KERBEROS_PRINCIPAL);
+        }
+        return principal.split("[/@]")[0];
+    }
+
     /**
      * Useful for tests to get the registered classes
      *
@@ -268,4 +359,20 @@ public class ZKUtils {
          */
         public static final String OOZIE_URL = "OOZIE_URL";
     }
+
+    /**
+     * Simple implementation of an {@link ACLProvider} that simply returns 
{@link #saslACL}.
+     */
+    public class SASLOwnerACLProvider implements ACLProvider {
+
+        @Override
+        public List<ACL> getDefaultAcl() {
+            return saslACL;
+        }
+
+        @Override
+        public List<ACL> getAclForPath(String path) {
+            return saslACL;
+        }
+    }
 }

Modified: oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCase.java
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCase.java?rev=1547259&r1=1547258&r2=1547259&view=diff
==============================================================================
--- oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCase.java 
(original)
+++ oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCase.java Tue 
Dec  3 01:41:59 2013
@@ -32,6 +32,7 @@ import org.apache.curator.x.discovery.Se
 import org.apache.curator.x.discovery.details.InstanceSerializer;
 import org.apache.oozie.service.Services;
 import org.apache.oozie.util.FixedJsonInstanceSerializer;
+import org.apache.oozie.util.ZKUtils;
 
 /**
  * Provides a version of XTestCase that also runs a ZooKeeper server and 
provides some utilities for interacting and simulating ZK
@@ -43,11 +44,16 @@ import org.apache.oozie.util.FixedJsonIn
  * To simulate another Oozie server, the DummyZKOozie object can be used; you 
can specify a ZooKeeper ID and Oozie URL for it in
  * the constructor.  Unlike this test class, it will advertise on the ZK 
service discovery, so it will appear as another Oozie
  * Server to anything using ZKUtils (though it does not use ZKUtils itself so 
it can have different information).
+ * To simulate another ZK-aware class, DummyUser can be used, which will use 
ZKUtils for interacting with ZK, including advertising
+ * on the service discovery; it also provides access to its ZKUtils instance.
+ * <p>
+ * To use security, see {@link ZKXTestCaseWithSecurity}.
  */
 public abstract class ZKXTestCase extends XTestCase {
     private TestingServer zkServer;
     private CuratorFramework client = null;
     private ServiceDiscovery<Map> sDiscovery = null;
+
     /**
      * The ZooKeeper ID for "this" Oozie server
      */
@@ -57,8 +63,7 @@ public abstract class ZKXTestCase extend
     protected void setUp() throws Exception {
         super.setUp();
         new Services().init();
-        // Start the ZooKeeper server and set Oozie ZK properties
-        zkServer = new TestingServer();
+        zkServer = setupZKServer();
         Services.get().getConf().set("oozie.zookeeper.connection.string", 
zkServer.getConnectString());
         setSystemProperty("oozie.instance.id", ZK_ID);
         createClient();
@@ -78,6 +83,16 @@ public abstract class ZKXTestCase extend
     }
 
     /**
+     * Creates and sets up the embedded ZooKeeper server.  Test subclasses 
should have no reason to override this method.
+     *
+     * @return the embedded ZooKeeper server
+     * @throws Exception
+     */
+    protected TestingServer setupZKServer() throws Exception {
+        return new TestingServer();
+    }
+
+    /**
      * Returns the connection string for ZooKeeper.
      *
      * @return the conection string for ZooKeeeper
@@ -209,5 +224,47 @@ public abstract class ZKXTestCase extend
                 .build();
         }
     }
+
+    /**
+     * Provides a class that can can register/unregister with the ZKUtils.  It 
also provides access to the ZKUtils object.  This is
+     * useful for testing features of the of ZKUtils class.  It will register 
when {@link DummyUser#register()} is called.  Make
+     * sure to call {@link DummyUser#unregister()} when done using it.
+     */
+    protected class DummyUser {
+
+        public DummyUser() {
+        }
+        private ZKUtils zk = null;
+
+        /**
+         * Registers with ZKUtils.
+         *
+         * @throws Exception
+         */
+        public void register() throws Exception {
+            zk = ZKUtils.register(this);
+            sleep(1000);    // Sleep to allow ZKUtils ServiceCache to update
+        }
+
+        /**
+         * Unregisters with ZKUtils.
+         */
+        public void unregister() {
+            if (zk != null) {
+                zk.unregister(this);
+                sleep(1000);    // Sleep to allow ZKUtils ServiceCache to 
update
+            }
+            zk = null;
+        }
+
+        /**
+         * Accessor for the ZKUtils object used by this class.
+         *
+         * @return The ZKUtils object
+         */
+        public ZKUtils getZKUtils() {
+            return zk;
+        }
+    }
 }
 

Added: 
oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCaseWithSecurity.java
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCaseWithSecurity.java?rev=1547259&view=auto
==============================================================================
--- 
oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCaseWithSecurity.java
 (added)
+++ 
oozie/trunk/core/src/test/java/org/apache/oozie/test/ZKXTestCaseWithSecurity.java
 Tue Dec  3 01:41:59 2013
@@ -0,0 +1,133 @@
+/**
+ * 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.oozie.test;
+
+import java.io.File;
+import javax.security.auth.login.Configuration;
+
+import org.apache.curator.test.TestingServer;
+import org.apache.hadoop.minikdc.MiniKdc;
+import org.apache.oozie.service.HadoopAccessorService;
+import org.apache.oozie.service.Services;
+import org.apache.oozie.util.JaasConfiguration;
+import org.apache.zookeeper.server.ZooKeeperSaslServer;
+
+/**
+ * Provides a version of {@link ZKXTestCase} with security.  A MiniKdc will be 
started (so no special outside setup is needed) and
+ * the embedded ZooKeeper provided by this class will support connecting to it 
with SASL/Kerberos authentication.  However,
+ * currently, the client returned by {@link #getClient()) and the client used 
by DummyZKOozie do not authenticate, so they won't
+ * have full access to any znodes with "sasl" ACLs (this is not always true, 
see {@link #setupZKServer()).
+ * <p>
+ * Anything using {@link ZKUtils} can connect using authentication by simply 
setting "oozie.zookeeper.secure" to "true" before
+ * creating the first thing that uses ZKUtils.  Make sure to set it back to 
false when done.
+ */
+public abstract class ZKXTestCaseWithSecurity extends ZKXTestCase {
+    private MiniKdc kdc = null;
+    private File keytabFile;
+    private String originalKeytabLoc;
+    private String originalPrincipal;
+
+    /**
+     * The primary part of the principal name for the Kerberos user
+     */
+    protected static final String PRIMARY_PRINCIPAL = "oozie";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Set the keytab location and principal to the miniKDC values
+        originalKeytabLoc = 
Services.get().getConf().get(HadoopAccessorService.KERBEROS_KEYTAB);
+        originalPrincipal = 
Services.get().getConf().get(HadoopAccessorService.KERBEROS_PRINCIPAL);
+        Services.get().getConf().set(HadoopAccessorService.KERBEROS_KEYTAB, 
keytabFile.getAbsolutePath());
+        Services.get().getConf().set(HadoopAccessorService.KERBEROS_PRINCIPAL, 
getPrincipal());
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Restore these values
+        Services.get().getConf().set(HadoopAccessorService.KERBEROS_KEYTAB, 
originalKeytabLoc);
+        Services.get().getConf().set(HadoopAccessorService.KERBEROS_PRINCIPAL, 
originalPrincipal);
+        // Just in case the test forgets to set this back
+        Services.get().getConf().set("oozie.zookeeper.secure", "false");
+        super.tearDown();
+        if (kdc != null) {
+            kdc.stop();
+        }
+    }
+
+    /**
+     * Creates and sets up the embedded ZooKeeper server.  Test subclasses 
should have no reason to override this method.
+     * <p>
+     * Here we override it to start the MiniKdc, set the jaas configuration, 
configure ZooKeeper for SASL/Kerberos authentication
+     * and ACLs, and to start the ZooKeeper server.
+     * <p>
+     * Unfortunately, ZooKeeper security requires setting the security for the 
entire JVM.  And for the tests, we're running the
+     * ZK server and one or more clients from the same JVM, so things get 
messy.  There are two ways to tell ZooKeeper to
+     * authenticate: (1) set the system property, 
"java.security.auth.login.config", to a jaas.conf file and (2) create a
+     * javax.security.auth.login.Configuration object with the same info as 
the jaas.conf and set it.  In either case, once set and
+     * something has authenticated, it seems that it can't be unset or 
changed, and there's no way to log out.  By setting the
+     * system property, "javax.security.auth.useSubjectCredsOnly", to "false" 
we can sort-of change the jaas Configuration, but its
+     * kind of funny about it.  Another effect of this is that we have to add 
jaas entries for the "Server" and "Client" here
+     * instead of just the "Server" here and the "Client" in the normal place 
({@link ZKUtils}) or it will be unable to find the
+     * "Client" info.  Also, because there is no way to logout, once any 
client has authenticated once, all subsequent clients will
+     * automatically connect using the same authentication; trying to stop 
this is futile and either results in an error or has no
+     * effect.  This means that there's no way to do any tests with an 
unauthenticated client.  Also, if any tests using secure
+     * ZooKeeper get run before tests not using secure ZooKeeper, they will 
likely fail because it will try to use authentication:
+     * so they should be run separately.
+     *
+     * @return the embedded ZooKeeper server
+     * @throws Exception
+     */
+    @Override
+    protected TestingServer setupZKServer() throws Exception {
+        // Not entirely sure exactly what 
"javax.security.auth.useSubjectCredsOnly=false" does, but it has something to 
do with
+        // re-authenticating in cases where it otherwise wouldn't.  One of the 
sections on this page briefly mentions it:
+        // 
http://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/tutorials/Troubleshooting.html
+        setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");
+
+        // Setup KDC and principal
+        kdc = new MiniKdc(MiniKdc.createConf(), new File(getTestCaseDir()));
+        kdc.start();
+        keytabFile = new File(getTestCaseDir(), "test.keytab");
+        String serverPrincipal = "zookeeper/" + kdc.getHost();
+        kdc.createPrincipal(keytabFile, getPrincipal(), serverPrincipal);
+
+        setSystemProperty("zookeeper.authProvider.1", 
"org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+        setSystemProperty("zookeeper.kerberos.removeHostFromPrincipal", 
"true");
+        setSystemProperty("zookeeper.kerberos.removeRealmFromPrincipal", 
"true");
+
+        JaasConfiguration.addEntry("Server", serverPrincipal, 
keytabFile.getAbsolutePath());
+        // Here's where we add the "Client" to the jaas configuration, even 
though we'd like not to
+        JaasConfiguration.addEntry("Client", getPrincipal(), 
keytabFile.getAbsolutePath());
+        Configuration.setConfiguration(JaasConfiguration.getInstance());
+
+        setSystemProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, 
"Server");
+
+        return new TestingServer();
+    }
+
+    /**
+     * Returns the principal of the Kerberos user.  This would be {@link 
#PRIMARY_PRINCIPAL}/_host_
+     *
+     * @return the principal of the Kerberos user
+     */
+    protected String getPrincipal() {
+        return PRIMARY_PRINCIPAL + "/" + kdc.getHost();
+    }
+}
+

Added: 
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestJaasConfiguration.java
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/src/test/java/org/apache/oozie/util/TestJaasConfiguration.java?rev=1547259&view=auto
==============================================================================
--- 
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestJaasConfiguration.java 
(added)
+++ 
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestJaasConfiguration.java 
Tue Dec  3 01:41:59 2013
@@ -0,0 +1,81 @@
+/**
+ * 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.oozie.util;
+
+import java.util.Map;
+import javax.security.auth.login.AppConfigurationEntry;
+import org.apache.oozie.test.XTestCase;
+
+public class TestJaasConfiguration extends XTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    // We won't test actually using it to authenticate because that gets messy 
and may conflict with other tests; but we can test
+    // that it otherwise behaves correctly
+    public void test() throws Exception {
+        String krb5LoginModuleName;
+        if (System.getProperty("java.vendor").contains("IBM")) {
+            krb5LoginModuleName = 
"com.ibm.security.auth.module.Krb5LoginModule";
+        }
+        else {
+            krb5LoginModuleName = 
"com.sun.security.auth.module.Krb5LoginModule";
+        }
+
+        JaasConfiguration.clearEntries();
+        assertTrue(JaasConfiguration.getEntries().isEmpty());
+
+        JaasConfiguration.addEntry("foo", "foo/localhost", 
"/some/location/foo");
+        assertEquals(1, JaasConfiguration.getEntries().size());
+        JaasConfiguration.addEntry("bar", "bar/localhost", 
"/some/location/bar");
+        assertEquals(2, JaasConfiguration.getEntries().size());
+        JaasConfiguration.addEntry("zoo", "zoo/localhost", 
"/some/location/zoo");
+        assertEquals(3, JaasConfiguration.getEntries().size());
+        checkEntry(krb5LoginModuleName, "foo", "foo/localhost", 
"/some/location/foo");
+        checkEntry(krb5LoginModuleName, "bar", "bar/localhost", 
"/some/location/bar");
+        checkEntry(krb5LoginModuleName, "zoo", "zoo/localhost", 
"/some/location/zoo");
+
+        JaasConfiguration.removeEntry("bar");
+        assertEquals(2, JaasConfiguration.getEntries().size());
+        checkEntry(krb5LoginModuleName, "foo", "foo/localhost", 
"/some/location/foo");
+        checkEntry(krb5LoginModuleName, "zoo", "zoo/localhost", 
"/some/location/zoo");
+
+        JaasConfiguration.clearEntries();
+        assertTrue(JaasConfiguration.getEntries().isEmpty());
+    }
+
+    private void checkEntry(String loginModuleName, String name, String 
principal, String keytab) {
+        AppConfigurationEntry entry = JaasConfiguration.getEntries().get(name);
+        assertEquals(loginModuleName, entry.getLoginModuleName());
+        assertEquals(AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 
entry.getControlFlag());
+        Map<String, ?> options = entry.getOptions();
+        assertEquals(keytab, options.get("keyTab"));
+        assertEquals(principal, options.get("principal"));
+        assertEquals("true", options.get("useKeyTab"));
+        assertEquals("true", options.get("storeKey"));
+        assertEquals("false", options.get("useTicketCache"));
+        assertEquals(5, options.size());
+    }
+}

Modified: oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtils.java
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtils.java?rev=1547259&r1=1547258&r2=1547259&view=diff
==============================================================================
--- oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtils.java 
(original)
+++ oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtils.java Tue 
Dec  3 01:41:59 2013
@@ -39,26 +39,6 @@ public class TestZKUtils extends ZKXTest
         super.tearDown();
     }
 
-    private class DummyUser {
-        private ZKUtils zk = null;
-        void register() throws Exception {
-            zk = ZKUtils.register(this);
-            sleep(1000);    // Sleep to allow ZKUtils ServiceCache to update
-        }
-
-        void unregister() {
-            if (zk != null) {
-                zk.unregister(this);
-                sleep(1000);    // Sleep to allow ZKUtils ServiceCache to 
update
-            }
-            zk = null;
-        }
-
-        ZKUtils getZKUtils() {
-            return zk;
-        }
-    }
-
     public void testRegisterAdvertiseUnadvertiseUnregister() throws Exception {
         CuratorFramework client = getClient();
         ServiceDiscovery<Map> sDiscovery = getServiceDiscovery();

Added: 
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtilsWithSecurity.java
URL: 
http://svn.apache.org/viewvc/oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtilsWithSecurity.java?rev=1547259&view=auto
==============================================================================
--- 
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtilsWithSecurity.java
 (added)
+++ 
oozie/trunk/core/src/test/java/org/apache/oozie/util/TestZKUtilsWithSecurity.java
 Tue Dec  3 01:41:59 2013
@@ -0,0 +1,187 @@
+/**
+ * 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.oozie.util;
+
+import java.util.List;
+import static junit.framework.Assert.assertEquals;
+
+import org.apache.oozie.lock.LockToken;
+import org.apache.oozie.service.Services;
+import org.apache.oozie.service.ZKLocksService;
+import org.apache.oozie.test.ZKXTestCaseWithSecurity;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+
+public class TestZKUtilsWithSecurity extends ZKXTestCaseWithSecurity {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testCheckAndSetACLs() throws Exception {
+        // We want to verify the ACLs on locks and the service discovery; 
ZKUtils does the service discovery and starting
+        // ZKLocksService will use ZKUtils which will start advertising on the 
service discovery.  We can also acquire a lock so
+        // it will create a lock znode.
+        ZKLocksService zkls = new ZKLocksService();
+        try {
+            zkls.init(Services.get());
+            LockToken lock = zkls.getWriteLock("foo", 3);
+            lock.release();
+            List<ACL> acls = 
getClient().getZookeeperClient().getZooKeeper().getACL("/oozie", new Stat());
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("world", acls.get(0).getId().getScheme());
+            assertEquals("anyone", acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/locks");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("world", acls.get(0).getId().getScheme());
+            assertEquals("anyone", acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/locks/foo");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("world", acls.get(0).getId().getScheme());
+            assertEquals("anyone", acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("world", acls.get(0).getId().getScheme());
+            assertEquals("anyone", acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services/servers");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("world", acls.get(0).getId().getScheme());
+            assertEquals("anyone", acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services/servers/" + ZK_ID);
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("world", acls.get(0).getId().getScheme());
+            assertEquals("anyone", acls.get(0).getId().getId());
+        }
+        finally {
+            // unregistering all users of ZKUtils (i.e. ZKLocksService) will 
cause it to disconnect so when we set
+            // "oozie.zookeeper.secure" to true, it will again connect but 
using SASL/Kerberos
+            zkls.destroy();
+        }
+
+        // Verify that the expected paths created above still exist with the 
"world" ACLs
+        List<ACL> acls = 
getClient().getZookeeperClient().getZooKeeper().getACL("/oozie", new Stat());
+        assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+        assertEquals("world", acls.get(0).getId().getScheme());
+        assertEquals("anyone", acls.get(0).getId().getId());
+        acls = getClient().getACL().forPath("/locks");
+        assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+        assertEquals("world", acls.get(0).getId().getScheme());
+        assertEquals("anyone", acls.get(0).getId().getId());
+        acls = getClient().getACL().forPath("/locks/foo");
+        assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+        assertEquals("world", acls.get(0).getId().getScheme());
+        assertEquals("anyone", acls.get(0).getId().getId());
+        acls = getClient().getACL().forPath("/services");
+        assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+        assertEquals("world", acls.get(0).getId().getScheme());
+        assertEquals("anyone", acls.get(0).getId().getId());
+        acls = getClient().getACL().forPath("/services/servers");
+        assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+        assertEquals("world", acls.get(0).getId().getScheme());
+        assertEquals("anyone", acls.get(0).getId().getId());
+
+        zkls = new ZKLocksService();
+        try {
+            Services.get().getConf().set("oozie.zookeeper.secure", "true");
+            // Now that security is enabled, it will trigger the 
checkAndSetACLs() code to go through and set all of the previously
+            // created znodes to have "sasl" ACLs
+            zkls.init(Services.get());
+            acls = 
getClient().getZookeeperClient().getZooKeeper().getACL("/oozie", new Stat());
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/locks");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/locks/foo");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services/servers");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services/servers/" + ZK_ID);
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+        }
+        finally {
+            zkls.destroy();
+            Services.get().getConf().set("oozie.zookeeper.secure", "false");
+        }
+    }
+
+    public void testNewUsingACLs() throws Exception {
+        // We want to verify the ACLs on new locks and the service discovery; 
ZKUtils does the service discovery and starting
+        // ZKLocksService will use ZKUtils which will start advertising on the 
service discovery.  We can also acquire a lock so
+        // it will create a lock znode.
+        ZKLocksService zkls = new ZKLocksService();
+        try {
+            Services.get().getConf().set("oozie.zookeeper.secure", "true");
+            // Verify that the znodes don't already exist
+            
assertNull(getClient().getZookeeperClient().getZooKeeper().exists("/oozie", 
null));
+            assertNull(getClient().checkExists().forPath("/locks"));
+            assertNull(getClient().checkExists().forPath("/services"));
+            // Check that new znodes will use the ACLs
+            zkls.init(Services.get());
+            LockToken lock = zkls.getWriteLock("foo", 3);
+            lock.release();
+            List<ACL> acls = 
getClient().getZookeeperClient().getZooKeeper().getACL("/oozie", new Stat());
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/locks");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/locks/foo");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services/servers");
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+            acls = getClient().getACL().forPath("/services/servers/" + ZK_ID);
+            assertEquals(ZooDefs.Perms.ALL, acls.get(0).getPerms());
+            assertEquals("sasl", acls.get(0).getId().getScheme());
+            assertEquals(PRIMARY_PRINCIPAL, acls.get(0).getId().getId());
+        }
+        finally {
+            zkls.destroy();
+            Services.get().getConf().set("oozie.zookeeper.secure", "false");
+        }
+    }
+}

Modified: oozie/trunk/docs/src/site/twiki/AG_Install.twiki
URL: 
http://svn.apache.org/viewvc/oozie/trunk/docs/src/site/twiki/AG_Install.twiki?rev=1547259&r1=1547258&r2=1547259&view=diff
==============================================================================
--- oozie/trunk/docs/src/site/twiki/AG_Install.twiki (original)
+++ oozie/trunk/docs/src/site/twiki/AG_Install.twiki Tue Dec  3 01:41:59 2013
@@ -790,9 +790,37 @@ be missing information until that server
 
 ---++++ Security
 
-Oozie HA works with the existing Oozie security framework and settings.  There 
are no additional security settings specific to HA;
-however, for log streaming to work properly in a secure setup, 
=oozie.authentication.type= must be set properly on each server
-(though this is already required if using security in the first place).
+Oozie HA works with the existing Oozie security framework and settings. For 
log streaming to work properly in a secure
+setup =oozie.authentication.type= must be set properly on each server (though 
this is already required if using security in the
+first place).
+
+(Optional) To prevent unauthorized users or programs from interacting with or 
reading the znodes used by Oozie in ZooKeeper,
+you can tell Oozie to use Kerberos-backed ACLs.  To enforce this for all of 
the Oozie-related znodes, simply add the following
+property to oozie-site.xml in all Oozie servers and set it to =true=.  The 
default is =false=.
+
+<verbatim>
+<property>
+    <name>oozie.zookeeper.secure</name>
+    <value>true</value>
+</property>
+</verbatim>
+
+Note: The Kerberos principals of each of the Oozie servers should have the 
same primary name (i.e. in =primary/instance@REALM=, each
+server should have the same value for =primary=).
+
+*Important:* Once this property is set to =true=, it will set the ACLs on all 
existing Oozie-related znodes to only allow Kerberos
+authenticated users with a principal that has the same primary as described 
above (also for any subsequently created new znodes).
+This means that if you ever want to turn this feature off, you will have to 
manually connect to ZooKeeper using a Kerberos principal
+with the same primary and either delete all znodes under and including the 
namespace (i.e. if =oozie.zookeeper.namespace= = =oozie=
+then that would be =/oozie=); alternatively, instead of deleting them all, you 
can manually set all of their ACLs to =world:anyone=.
+In either case, make sure that no Oozie servers are running while this is 
being done.
+
+Also, in your zoo.cfg for ZooKeeper, make sure to set the following properties:
+<verbatim>
+authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
+kerberos.removeHostFromPrincipal=true
+kerberos.removeRealmFromPrincipal=true
+</verbatim>
 
 ---++ Starting and Stopping Oozie
 

Modified: oozie/trunk/pom.xml
URL: 
http://svn.apache.org/viewvc/oozie/trunk/pom.xml?rev=1547259&r1=1547258&r2=1547259&view=diff
==============================================================================
--- oozie/trunk/pom.xml (original)
+++ oozie/trunk/pom.xml Tue Dec  3 01:41:59 2013
@@ -248,6 +248,13 @@
                 <type>war</type>
             </dependency>
 
+            <dependency>
+                <groupId>org.apache.hadoop</groupId>
+                <artifactId>hadoop-minikdc</artifactId>
+                <!-- TODO: Replace version once MiniKdc is in a released 
version of Hadoop -->
+                <version>2.3.0-SNAPSHOT</version>
+            </dependency>
+
             <!-- client -->
             <dependency>
                 <groupId>org.apache.hadoop</groupId>
@@ -862,6 +869,11 @@
                     <artifactId>openjpa-maven-plugin</artifactId>
                     <version>${openjpa.version}</version>
                 </plugin>
+                <plugin>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-bundle-plugin</artifactId>
+                    <version>2.4.0</version>
+                </plugin>
             </plugins>
         </pluginManagement>
 
@@ -982,6 +994,11 @@
                              Requires at least Hadoop 1.2.0 or 2.2.0.
                         -->
                         
<exclude>**/TestMapReduceActionExecutorUberJar.java</exclude>
+
+                        <!-- Explictly use -Dtest=TestZKUtilsWithSecurity to 
test the ZKUtils with security.
+                             It can conflict with other non-secure tests that 
use zookeeper
+                        -->
+                        <exclude>**/TestZKUtilsWithSecurity.java</exclude>
                     </excludes>
                     <!-- DO NOT CHANGE THIS VALUES, TESTCASES CANNOT RUN IN 
PARALLEL -->
                     <parallel>classes</parallel>

Modified: oozie/trunk/release-log.txt
URL: 
http://svn.apache.org/viewvc/oozie/trunk/release-log.txt?rev=1547259&r1=1547258&r2=1547259&view=diff
==============================================================================
--- oozie/trunk/release-log.txt (original)
+++ oozie/trunk/release-log.txt Tue Dec  3 01:41:59 2013
@@ -1,5 +1,6 @@
 -- Oozie 4.1.0 release (trunk - unreleased)
 
+OOZIE-1491 Make sure HA works with a secure ZooKeeper (rkanter)
 OOZIE-1615 shell action cannot find script file and fails in uber mode (ryota)
 OOZIE-1605 Add common custom filter applied to Wf/Coord/Bundle jobs on oozie 
UI (ryota)
 OOZIE-1474 Fix logging issues - latency, accurate job ids, coord Job UI to 
show job logs (mona)


Reply via email to