knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From m...@apache.org
Subject [44/49] knox git commit: KNOX-998 - Merge from trunk 0.14.0 code
Date Thu, 14 Dec 2017 21:13:31 GMT
http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/util/RemoteRegistryConfigTestUtils.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/util/RemoteRegistryConfigTestUtils.java b/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/util/RemoteRegistryConfigTestUtils.java
new file mode 100644
index 0000000..2854998
--- /dev/null
+++ b/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/util/RemoteRegistryConfigTestUtils.java
@@ -0,0 +1,117 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.service.config.remote.util;
+
+import java.util.Collection;
+import java.util.Map;
+
+public class RemoteRegistryConfigTestUtils {
+
+    public static final String PROPERTY_TYPE = "type";
+    public static final String PROPERTY_NAME = "name";
+    public static final String PROPERTY_ADDRESS = "address";
+    public static final String PROPERTY_NAMESAPCE = "namespace";
+    public static final String PROPERTY_SECURE = "secure";
+    public static final String PROPERTY_AUTH_TYPE = "authType";
+    public static final String PROPERTY_PRINCIPAL = "principal";
+    public static final String PROPERTY_CRED_ALIAS = "credentialAlias";
+    public static final String PROPERTY_KEYTAB = "keyTab";
+    public static final String PROPERTY_USE_KEYTAB = "useKeyTab";
+    public static final String PROPERTY_USE_TICKET_CACHE = "useTicketCache";
+
+    public static String createRemoteConfigRegistriesXML(Collection<Map<String, String>> configProperties) {
+        String result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+                        "<remote-configuration-registries>\n";
+
+        for (Map<String, String> props : configProperties) {
+            String authType = props.get(PROPERTY_AUTH_TYPE);
+            if ("Kerberos".equalsIgnoreCase(authType)) {
+                result +=
+                   createRemoteConfigRegistryXMLWithKerberosAuth(props.get(PROPERTY_TYPE),
+                                                                 props.get(PROPERTY_NAME),
+                                                                 props.get(PROPERTY_ADDRESS),
+                                                                 props.get(PROPERTY_PRINCIPAL),
+                                                                 props.get(PROPERTY_KEYTAB),
+                                                                 Boolean.valueOf(props.get(PROPERTY_USE_KEYTAB)),
+                                                                 Boolean.valueOf(props.get(PROPERTY_USE_TICKET_CACHE)));
+            } else if ("Digest".equalsIgnoreCase(authType)) {
+                result +=
+                    createRemoteConfigRegistryXMLWithDigestAuth(props.get(PROPERTY_TYPE),
+                                                                props.get(PROPERTY_NAME),
+                                                                props.get(PROPERTY_ADDRESS),
+                                                                props.get(PROPERTY_PRINCIPAL),
+                                                                props.get(PROPERTY_CRED_ALIAS));
+            } else {
+                result += createRemoteConfigRegistryXMLNoAuth(props.get(PROPERTY_TYPE),
+                                                              props.get(PROPERTY_NAME),
+                                                              props.get(PROPERTY_ADDRESS));
+            }
+        }
+
+        result += "</remote-configuration-registries>\n";
+
+        return result;
+    }
+
+    public static String createRemoteConfigRegistryXMLWithKerberosAuth(String type,
+                                                                       String name,
+                                                                       String address,
+                                                                       String principal,
+                                                                       String keyTab,
+                                                                       boolean userKeyTab,
+                                                                       boolean useTicketCache) {
+        return "  <remote-configuration-registry>\n" +
+               "    <name>" + name + "</name>\n" +
+               "    <type>" + type + "</type>\n" +
+               "    <address>" + address + "</address>\n" +
+               "    <secure>true</secure>\n" +
+               "    <auth-type>" + "Kerberos" + "</auth-type>\n" +
+               "    <principal>" + principal + "</principal>\n" +
+               "    <keytab>" + keyTab + "</keytab>\n" +
+               "    <use-keytab>" + String.valueOf(userKeyTab) + "</use-keytab>\n" +
+               "    <use-ticket-cache>" + String.valueOf(useTicketCache) + "</use-ticket-cache>\n" +
+               "  </remote-configuration-registry>\n";
+    }
+
+    public static String createRemoteConfigRegistryXMLWithDigestAuth(String type,
+                                                                     String name,
+                                                                     String address,
+                                                                     String principal,
+                                                                     String credentialAlias) {
+        return "  <remote-configuration-registry>\n" +
+               "    <name>" + name + "</name>\n" +
+               "    <type>" + type + "</type>\n" +
+               "    <address>" + address + "</address>\n" +
+               "    <secure>true</secure>\n" +
+               "    <auth-type>" + "Digest" + "</auth-type>\n" +
+               "    <principal>" + principal + "</principal>\n" +
+               "    <credential-alias>" + credentialAlias + "</credential-alias>\n" +
+               "  </remote-configuration-registry>\n";
+    }
+
+
+    public static String createRemoteConfigRegistryXMLNoAuth(String type,
+                                                             String name,
+                                                             String address) {
+        return "  <remote-configuration-registry>\n" +
+               "    <name>" + name + "</name>\n" +
+               "    <type>" + type + "</type>\n" +
+               "    <address>" + address + "</address>\n" +
+               "  </remote-configuration-registry>\n";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryClientServiceTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryClientServiceTest.java b/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryClientServiceTest.java
new file mode 100644
index 0000000..8a817a4
--- /dev/null
+++ b/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryClientServiceTest.java
@@ -0,0 +1,424 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.service.config.remote.zk;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.test.InstanceSpec;
+import org.apache.curator.test.TestingCluster;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceFactory;
+import org.apache.knox.gateway.service.config.remote.util.RemoteRegistryConfigTestUtils;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class RemoteConfigurationRegistryClientServiceTest {
+
+    /**
+     * Test a configuration for an unsecured remote registry, included in the gateway configuration.
+     */
+    @Test
+    public void testUnsecuredZooKeeperWithSimpleRegistryConfig() throws Exception {
+        final String REGISTRY_CLIENT_NAME = "unsecured-zk-registry-name";
+        final String PRINCIPAL = null;
+        final String PWD = null;
+        final String CRED_ALIAS = null;
+
+        // Configure and start a secure ZK cluster
+        TestingCluster zkCluster = setupAndStartSecureTestZooKeeper(PRINCIPAL, PWD);
+
+        try {
+            // Create the setup client for the test cluster, and initialize the test znodes
+            CuratorFramework setupClient = initializeTestClientAndZNodes(zkCluster, PRINCIPAL);
+
+            // Mock configuration
+            GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+            final String registryConfigValue =
+                        GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE + "=" + ZooKeeperClientService.TYPE + ";" +
+                        GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS + "=" + zkCluster.getConnectString();
+            EasyMock.expect(config.getRemoteRegistryConfiguration(REGISTRY_CLIENT_NAME))
+                    .andReturn(registryConfigValue)
+                    .anyTimes();
+            EasyMock.expect(config.getRemoteRegistryConfigurationNames())
+                    .andReturn(Collections.singletonList(REGISTRY_CLIENT_NAME)).anyTimes();
+            EasyMock.replay(config);
+
+            doTestZooKeeperClient(setupClient, REGISTRY_CLIENT_NAME, config, CRED_ALIAS, PWD);
+        } finally {
+            zkCluster.stop();
+        }
+    }
+
+    /**
+     * Test multiple configurations for an unsecured remote registry.
+     */
+    @Test
+    public void testMultipleUnsecuredZooKeeperWithSimpleRegistryConfig() throws Exception {
+        final String REGISTRY_CLIENT_NAME_1 = "zkclient1";
+        final String REGISTRY_CLIENT_NAME_2 = "zkclient2";
+        final String PRINCIPAL = null;
+        final String PWD = null;
+        final String CRED_ALIAS = null;
+
+        // Configure and start a secure ZK cluster
+        TestingCluster zkCluster = setupAndStartSecureTestZooKeeper(PRINCIPAL, PWD);
+
+        try {
+            // Create the setup client for the test cluster, and initialize the test znodes
+            CuratorFramework setupClient = initializeTestClientAndZNodes(zkCluster, PRINCIPAL);
+
+            // Mock configuration
+            GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+            final String registryConfigValue1 =
+                                GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE + "=" + ZooKeeperClientService.TYPE + ";" +
+                                GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS + "=" + zkCluster.getConnectString();
+            EasyMock.expect(config.getRemoteRegistryConfiguration(REGISTRY_CLIENT_NAME_1))
+                    .andReturn(registryConfigValue1).anyTimes();
+            final String registryConfigValue2 =
+                                GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE + "=" + ZooKeeperClientService.TYPE + ";" +
+                                GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS + "=" + zkCluster.getConnectString();
+            EasyMock.expect(config.getRemoteRegistryConfiguration(REGISTRY_CLIENT_NAME_2))
+                    .andReturn(registryConfigValue2).anyTimes();
+            EasyMock.expect(config.getRemoteRegistryConfigurationNames())
+                    .andReturn(Arrays.asList(REGISTRY_CLIENT_NAME_1, REGISTRY_CLIENT_NAME_2)).anyTimes();
+            EasyMock.replay(config);
+
+            // Create the client service instance
+            RemoteConfigurationRegistryClientService clientService =
+                    RemoteConfigurationRegistryClientServiceFactory.newInstance(config);
+            assertEquals("Wrong registry client service type.", clientService.getClass(), CuratorClientService.class);
+            clientService.setAliasService(null);
+            clientService.init(config, null);
+            clientService.start();
+
+            RemoteConfigurationRegistryClient client1 = clientService.get(REGISTRY_CLIENT_NAME_1);
+            assertNotNull(client1);
+
+            RemoteConfigurationRegistryClient client2 = clientService.get(REGISTRY_CLIENT_NAME_2);
+            assertNotNull(client2);
+
+            doTestZooKeeperClient(setupClient, REGISTRY_CLIENT_NAME_1, clientService, false);
+            doTestZooKeeperClient(setupClient, REGISTRY_CLIENT_NAME_2, clientService, false);
+        } finally {
+            zkCluster.stop();
+        }
+    }
+
+    /**
+     * Test a configuration for a secure remote registry, included in the gateway configuration.
+     */
+    @Test
+    public void testZooKeeperWithSimpleRegistryConfig() throws Exception {
+        final String AUTH_TYPE = "digest";
+        final String REGISTRY_CLIENT_NAME = "zk-registry-name";
+        final String PRINCIPAL = "knox";
+        final String PWD = "knoxtest";
+        final String CRED_ALIAS = "zkCredential";
+
+        // Configure and start a secure ZK cluster
+        TestingCluster zkCluster = setupAndStartSecureTestZooKeeper(PRINCIPAL, PWD);
+
+        try {
+            // Create the setup client for the test cluster, and initialize the test znodes
+            CuratorFramework setupClient = initializeTestClientAndZNodes(zkCluster, PRINCIPAL);
+
+            // Mock configuration
+            GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+            final String registryConfigValue =
+                            GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE + "=" + ZooKeeperClientService.TYPE + ";" +
+                            GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS + "=" + zkCluster.getConnectString() + ";" +
+                            GatewayConfig.REMOTE_CONFIG_REGISTRY_AUTH_TYPE + "=" + AUTH_TYPE + ";" +
+                            GatewayConfig.REMOTE_CONFIG_REGISTRY_PRINCIPAL + "=" + PRINCIPAL + ";" +
+                            GatewayConfig.REMOTE_CONFIG_REGISTRY_CREDENTIAL_ALIAS + "=" + CRED_ALIAS;
+            EasyMock.expect(config.getRemoteRegistryConfiguration(REGISTRY_CLIENT_NAME))
+                    .andReturn(registryConfigValue)
+                    .anyTimes();
+            EasyMock.expect(config.getRemoteRegistryConfigurationNames())
+                    .andReturn(Collections.singletonList(REGISTRY_CLIENT_NAME)).anyTimes();
+            EasyMock.replay(config);
+
+            doTestZooKeeperClient(setupClient, REGISTRY_CLIENT_NAME, config, CRED_ALIAS, PWD);
+        } finally {
+            zkCluster.stop();
+        }
+    }
+
+    /**
+     * Test the remote registry configuration external to, and referenced from, the gateway configuration, for a secure
+     * client.
+     */
+    @Test
+    public void testZooKeeperWithSingleExternalRegistryConfig() throws Exception {
+        final String AUTH_TYPE = "digest";
+        final String REGISTRY_CLIENT_NAME = "my-zookeeper_registryNAME";
+        final String PRINCIPAL = "knox";
+        final String PWD = "knoxtest";
+        final String CRED_ALIAS = "zkCredential";
+
+        // Configure and start a secure ZK cluster
+        TestingCluster zkCluster = setupAndStartSecureTestZooKeeper(PRINCIPAL, PWD);
+
+        File tmpRegConfigFile = null;
+
+        try {
+            // Create the setup client for the test cluster, and initialize the test znodes
+            CuratorFramework setupClient = initializeTestClientAndZNodes(zkCluster, PRINCIPAL);
+
+            // Mock configuration
+            Map<String, String> registryConfigProps = new HashMap<>();
+            registryConfigProps.put("type", ZooKeeperClientService.TYPE);
+            registryConfigProps.put("name", REGISTRY_CLIENT_NAME);
+            registryConfigProps.put("address", zkCluster.getConnectString());
+            registryConfigProps.put("secure", "true");
+            registryConfigProps.put("authType", AUTH_TYPE);
+            registryConfigProps.put("principal", PRINCIPAL);
+            registryConfigProps.put("credentialAlias", CRED_ALIAS);
+            String registryConfigXML =
+                  RemoteRegistryConfigTestUtils.createRemoteConfigRegistriesXML(Collections.singleton(registryConfigProps));
+            tmpRegConfigFile = File.createTempFile("myRemoteRegistryConfig", "xml");
+            FileUtils.writeStringToFile(tmpRegConfigFile, registryConfigXML);
+
+            System.setProperty("org.apache.knox.gateway.remote.registry.config.file", tmpRegConfigFile.getAbsolutePath());
+
+            GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+            EasyMock.replay(config);
+
+            doTestZooKeeperClient(setupClient, REGISTRY_CLIENT_NAME, config, CRED_ALIAS, PWD);
+        } finally {
+            zkCluster.stop();
+            if (tmpRegConfigFile != null && tmpRegConfigFile.exists()) {
+                tmpRegConfigFile.delete();
+            }
+            System.clearProperty("org.apache.knox.gateway.remote.registry.config.file");
+        }
+    }
+
+    /**
+     * Setup and start a secure test ZooKeeper cluster.
+     */
+    private TestingCluster setupAndStartSecureTestZooKeeper(String principal, String digestPassword) throws Exception {
+        final boolean applyAuthentication = (principal != null);
+
+        // Configure security for the ZK cluster instances
+        Map<String, Object> customInstanceSpecProps = new HashMap<>();
+
+        if (applyAuthentication) {
+            customInstanceSpecProps.put("authProvider.1", "org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
+            customInstanceSpecProps.put("requireClientAuthScheme", "sasl");
+        }
+
+        // Define the test cluster
+        List<InstanceSpec> instanceSpecs = new ArrayList<>();
+        for (int i = 0 ; i < 3 ; i++) {
+            InstanceSpec is = new InstanceSpec(null, -1, -1, -1, false, (i+1), -1, -1, customInstanceSpecProps);
+            instanceSpecs.add(is);
+        }
+        TestingCluster zkCluster = new TestingCluster(instanceSpecs);
+
+        if (applyAuthentication) {
+            // Setup ZooKeeper server SASL
+            Map<String, String> digestOptions = new HashMap<>();
+            digestOptions.put("user_" + principal, digestPassword);
+            final AppConfigurationEntry[] serverEntries =
+                    {new AppConfigurationEntry("org.apache.zookeeper.server.auth.DigestLoginModule",
+                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                            digestOptions)};
+            Configuration.setConfiguration(new Configuration() {
+                @Override
+                public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+                    return ("Server".equalsIgnoreCase(name)) ? serverEntries : null;
+                }
+            });
+        }
+
+        // Start the cluster
+        zkCluster.start();
+
+        return zkCluster;
+    }
+
+    /**
+     * Create a ZooKeeper client with SASL digest auth configured, and initialize the test znodes.
+     */
+    private CuratorFramework initializeTestClientAndZNodes(TestingCluster zkCluster, String principal) throws Exception {
+        // Create the client for the test cluster
+        CuratorFramework setupClient = CuratorFrameworkFactory.builder()
+                                                              .connectString(zkCluster.getConnectString())
+                                                              .retryPolicy(new ExponentialBackoffRetry(100, 3))
+                                                              .build();
+        assertNotNull(setupClient);
+        setupClient.start();
+
+        List<ACL> acls = new ArrayList<>();
+        if (principal != null) {
+            acls.add(new ACL(ZooDefs.Perms.ALL, new Id("sasl", principal)));
+        } else {
+            acls.add(new ACL(ZooDefs.Perms.ALL, ZooDefs.Ids.ANYONE_ID_UNSAFE));
+        }
+        setupClient.create().creatingParentsIfNeeded().withACL(acls).forPath("/knox/config/descriptors");
+        setupClient.create().creatingParentsIfNeeded().withACL(acls).forPath("/knox/config/shared-providers");
+
+        List<ACL> negativeACLs = new ArrayList<>();
+        if (principal != null) {
+            negativeACLs.add(new ACL(ZooDefs.Perms.ALL, new Id("sasl", "notyou")));
+        } else {
+            negativeACLs.add(new ACL(ZooDefs.Perms.ALL, ZooDefs.Ids.ANYONE_ID_UNSAFE));
+        }
+        setupClient.create().creatingParentsIfNeeded().withACL(negativeACLs).forPath("/someotherconfig");
+
+        return setupClient;
+    }
+
+    private void doTestZooKeeperClient(final CuratorFramework setupClient,
+                                       final String           testClientName,
+                                       final GatewayConfig    config,
+                                       final String           credentialAlias,
+                                       final String           digestPassword) throws Exception {
+        boolean isSecureTest = (credentialAlias != null && digestPassword != null);
+
+        // Mock alias service
+        AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
+        EasyMock.expect(aliasService.getPasswordFromAliasForGateway(credentialAlias))
+                .andReturn(isSecureTest ? digestPassword.toCharArray() : null)
+                .anyTimes();
+        EasyMock.replay(aliasService);
+
+        // Create the client service instance
+        RemoteConfigurationRegistryClientService clientService =
+                RemoteConfigurationRegistryClientServiceFactory.newInstance(config);
+        assertEquals("Wrong registry client service type.", clientService.getClass(), CuratorClientService.class);
+        clientService.setAliasService(aliasService);
+        clientService.init(config, null);
+        clientService.start();
+
+        doTestZooKeeperClient(setupClient, testClientName, clientService, isSecureTest);
+    }
+
+    /**
+     * Test secure ZooKeeper client interactions.
+     *
+     * @param setupClient    The client used for interacting with ZooKeeper independent from the registry client service.
+     * @param testClientName The name of the client to use from the registry client service.
+     * @param clientService  The RemoteConfigurationRegistryClientService
+     * @param isSecureTest   Flag to indicate whether this is a secure interaction test
+     */
+    private void doTestZooKeeperClient(final CuratorFramework                         setupClient,
+                                       final String                                   testClientName,
+                                       final RemoteConfigurationRegistryClientService clientService,
+                                       boolean                                        isSecureTest) throws Exception {
+
+        RemoteConfigurationRegistryClient client = clientService.get(testClientName);
+        assertNotNull(client);
+        List<String> descriptors = client.listChildEntries("/knox/config/descriptors");
+        assertNotNull(descriptors);
+        for (String descriptor : descriptors) {
+            System.out.println("Descriptor: " + descriptor);
+        }
+
+        List<String> providerConfigs = client.listChildEntries("/knox/config/shared-providers");
+        assertNotNull(providerConfigs);
+        for (String providerConfig : providerConfigs) {
+            System.out.println("Provider config: " + providerConfig);
+        }
+
+        List<String> someotherConfig = client.listChildEntries("/someotherconfig");
+        if (isSecureTest) {
+            assertNull("Expected null because of the ACL mismatch.", someotherConfig);
+        } else {
+            assertNotNull(someotherConfig);
+        }
+
+        // Test listeners
+        final String MY_NEW_ZNODE = "/clientServiceTestNode";
+        final String MY_NEW_DATA_ZNODE = MY_NEW_ZNODE + "/mydata";
+
+        if (setupClient.checkExists().forPath(MY_NEW_ZNODE) != null) {
+            setupClient.delete().deletingChildrenIfNeeded().forPath(MY_NEW_ZNODE);
+        }
+
+        final List<String> listenerLog = new ArrayList<>();
+        client.addChildEntryListener(MY_NEW_ZNODE, (c, type, path) -> {
+            listenerLog.add("EXTERNAL: " + type.toString() + ":" + path);
+            if (RemoteConfigurationRegistryClient.ChildEntryListener.Type.ADDED.equals(type)) {
+                try {
+                    c.addEntryListener(path, (cc, p, d) -> listenerLog.add("EXTERNAL: " + p + ":" + (d != null ? new String(d) : "null")));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+
+        client.createEntry(MY_NEW_ZNODE);
+        client.createEntry(MY_NEW_DATA_ZNODE, "more test data");
+        String testData = client.getEntryData(MY_NEW_DATA_ZNODE);
+        assertNotNull(testData);
+        assertEquals("more test data", testData);
+
+        assertTrue(client.entryExists(MY_NEW_DATA_ZNODE));
+        client.setEntryData(MY_NEW_DATA_ZNODE, "still more data");
+
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            //
+        }
+
+        client.setEntryData(MY_NEW_DATA_ZNODE, "changed completely");
+
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            //
+        }
+
+        client.deleteEntry(MY_NEW_DATA_ZNODE);
+
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            //
+        }
+
+        assertFalse(listenerLog.isEmpty());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfigTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfigTest.java b/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfigTest.java
new file mode 100644
index 0000000..7a123f4
--- /dev/null
+++ b/gateway-service-remoteconfig/src/test/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfigTest.java
@@ -0,0 +1,255 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.service.config.remote.zk;
+
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
+import org.apache.knox.gateway.service.config.remote.zk.RemoteConfigurationRegistryJAASConfig;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class RemoteConfigurationRegistryJAASConfigTest {
+
+    @Test
+    public void testZooKeeperDigestContextEntry() throws Exception {
+        List<RemoteConfigurationRegistryConfig> registryConfigs = new ArrayList<>();
+        final String ENTRY_NAME       = "my_digest_context";
+        final String DIGEST_PRINCIPAL = "myIdentity";
+        final String DIGEST_PWD_ALIAS = "myAlias";
+        final String DIGEST_PWD       = "mysecret";
+
+        AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
+        EasyMock.expect(aliasService.getPasswordFromAliasForGateway(DIGEST_PWD_ALIAS)).andReturn(DIGEST_PWD.toCharArray()).anyTimes();
+        EasyMock.replay(aliasService);
+
+        registryConfigs.add(createDigestConfig(ENTRY_NAME, DIGEST_PRINCIPAL, DIGEST_PWD_ALIAS));
+
+        try {
+            RemoteConfigurationRegistryJAASConfig jaasConfig =
+                                    RemoteConfigurationRegistryJAASConfig.configure(registryConfigs, aliasService);
+
+            // Make sure there are no entries for an invalid context entry name
+            assertNull(jaasConfig.getAppConfigurationEntry("invalid"));
+
+            // Validate the intended context entry
+            validateDigestContext(jaasConfig,
+                                  ENTRY_NAME,
+                                  RemoteConfigurationRegistryJAASConfig.digestLoginModules.get("ZOOKEEPER"),
+                                  DIGEST_PRINCIPAL,
+                                  DIGEST_PWD);
+        } finally {
+            Configuration.setConfiguration(null);
+        }
+    }
+
+    @Test
+    public void testKerberosContextEntry() throws Exception {
+        List<RemoteConfigurationRegistryConfig> registryConfigs = new ArrayList<>();
+        final String ENTRY_NAME = "my_kerberos_context";
+        final String PRINCIPAL  = "myIdentity";
+
+        File dummyKeyTab = File.createTempFile("my_context", "keytab");
+        registryConfigs.add(createKerberosConfig(ENTRY_NAME, PRINCIPAL, dummyKeyTab.getAbsolutePath()));
+
+        try {
+            RemoteConfigurationRegistryJAASConfig jaasConfig =
+                                            RemoteConfigurationRegistryJAASConfig.configure(registryConfigs, null);
+
+            // Make sure there are no entries for an invalid context entry name
+            assertNull(jaasConfig.getAppConfigurationEntry("invalid"));
+
+            // Validate the intended context entry
+            validateKerberosContext(jaasConfig,
+                                    ENTRY_NAME,
+                                    PRINCIPAL,
+                                    dummyKeyTab.getAbsolutePath(),
+                                    true,
+                                    false);
+
+        } finally {
+            Configuration.setConfiguration(null);
+        }
+    }
+
+    @Test
+    public void testZooKeeperMultipleContextEntries() throws Exception {
+        List<RemoteConfigurationRegistryConfig> registryConfigs = new ArrayList<>();
+        final String KERBEROS_ENTRY_NAME = "my_kerberos_context";
+        final String KERBEROS_PRINCIPAL  = "myKerberosIdentity";
+        final String DIGEST_ENTRY_NAME   = "my_digest_context";
+        final String DIGEST_PRINCIPAL    = "myDigestIdentity";
+        final String DIGEST_PWD_ALIAS    = "myAlias";
+        final String DIGEST_PWD          = "mysecret";
+
+        AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
+        EasyMock.expect(aliasService.getPasswordFromAliasForGateway(DIGEST_PWD_ALIAS)).andReturn(DIGEST_PWD.toCharArray()).anyTimes();
+        EasyMock.replay(aliasService);
+
+        File dummyKeyTab = File.createTempFile("my_context", "keytab");
+        registryConfigs.add(createKerberosConfig(KERBEROS_ENTRY_NAME, KERBEROS_PRINCIPAL, dummyKeyTab.getAbsolutePath()));
+        registryConfigs.add(createDigestConfig(DIGEST_ENTRY_NAME, DIGEST_PRINCIPAL, DIGEST_PWD_ALIAS));
+
+        try {
+            RemoteConfigurationRegistryJAASConfig jaasConfig =
+                                        RemoteConfigurationRegistryJAASConfig.configure(registryConfigs, aliasService);
+
+            // Make sure there are no entries for an invalid context entry name
+            assertNull(jaasConfig.getAppConfigurationEntry("invalid"));
+
+            // Validate the kerberos context entry
+            validateKerberosContext(jaasConfig,
+                                    KERBEROS_ENTRY_NAME,
+                                    KERBEROS_PRINCIPAL,
+                                    dummyKeyTab.getAbsolutePath(),
+                                    true,
+                                    false);
+
+            // Validate the digest context entry
+            validateDigestContext(jaasConfig,
+                                  DIGEST_ENTRY_NAME,
+                                  RemoteConfigurationRegistryJAASConfig.digestLoginModules.get("ZOOKEEPER"),
+                                  DIGEST_PRINCIPAL,
+                                  DIGEST_PWD);
+
+        } finally {
+            Configuration.setConfiguration(null);
+        }
+    }
+
+    @Test
+    public void testZooKeeperDigestContextEntryWithoutAliasService() throws Exception {
+        List<RemoteConfigurationRegistryConfig> registryConfigs = new ArrayList<>();
+        final String ENTRY_NAME       = "my_digest_context";
+        final String DIGEST_PRINCIPAL = "myIdentity";
+        final String DIGEST_PWD_ALIAS = "myAlias";
+
+        registryConfigs.add(createDigestConfig(ENTRY_NAME, DIGEST_PRINCIPAL, DIGEST_PWD_ALIAS));
+
+        try {
+            RemoteConfigurationRegistryJAASConfig jaasConfig =
+                                            RemoteConfigurationRegistryJAASConfig.configure(registryConfigs, null);
+            fail("Expected IllegalArgumentException because the AliasService is not available.");
+        } catch (IllegalArgumentException e) {
+            // Expected
+            assertTrue(e.getMessage().contains("AliasService"));
+        } catch (Throwable e) {
+            fail("Wrong exception encountered: " + e.getClass().getName() + ", " + e.getMessage());
+        } finally {
+            Configuration.setConfiguration(null);
+        }
+    }
+
+    private static RemoteConfigurationRegistryConfig createDigestConfig(String entryName,
+                                                                        String principal,
+                                                                        String credentialAlias) {
+        return createDigestConfig(entryName, principal, credentialAlias, "ZooKeeper");
+    }
+
+    private static RemoteConfigurationRegistryConfig createDigestConfig(String entryName,
+                                                                        String principal,
+                                                                        String credentialAlias,
+                                                                        String registryType) {
+        RemoteConfigurationRegistryConfig rc = EasyMock.createNiceMock(RemoteConfigurationRegistryConfig.class);
+        EasyMock.expect(rc.getRegistryType()).andReturn(registryType).anyTimes();
+        EasyMock.expect(rc.getName()).andReturn(entryName).anyTimes();
+        EasyMock.expect(rc.isSecureRegistry()).andReturn(true).anyTimes();
+        EasyMock.expect(rc.getAuthType()).andReturn("digest").anyTimes();
+        EasyMock.expect(rc.getPrincipal()).andReturn(principal).anyTimes();
+        EasyMock.expect(rc.getCredentialAlias()).andReturn(credentialAlias).anyTimes();
+        EasyMock.replay(rc);
+        return rc;
+    }
+
+
+    private static RemoteConfigurationRegistryConfig createKerberosConfig(String entryName,
+                                                                          String principal,
+                                                                          String keyTabPath) {
+        return createKerberosConfig(entryName, principal, keyTabPath, "ZooKeeper");
+    }
+
+    private static RemoteConfigurationRegistryConfig createKerberosConfig(String entryName,
+                                                                          String principal,
+                                                                          String keyTabPath,
+                                                                          String registryType) {
+        return createKerberosConfig(entryName, principal, keyTabPath, null, null, registryType);
+    }
+
+    private static RemoteConfigurationRegistryConfig createKerberosConfig(String entryName,
+                                                                          String principal,
+                                                                          String keyTabPath,
+                                                                          Boolean useKeyTab,
+                                                                          Boolean useTicketCache,
+                                                                          String registryType) {
+        RemoteConfigurationRegistryConfig rc = EasyMock.createNiceMock(RemoteConfigurationRegistryConfig.class);
+        EasyMock.expect(rc.getRegistryType()).andReturn(registryType).anyTimes();
+        EasyMock.expect(rc.getName()).andReturn(entryName).anyTimes();
+        EasyMock.expect(rc.isSecureRegistry()).andReturn(true).anyTimes();
+        EasyMock.expect(rc.getAuthType()).andReturn("kerberos").anyTimes();
+        EasyMock.expect(rc.getPrincipal()).andReturn(principal).anyTimes();
+        EasyMock.expect(rc.getKeytab()).andReturn(keyTabPath).anyTimes();
+        EasyMock.expect(rc.isUseKeyTab()).andReturn(useKeyTab != null ? useKeyTab : true).anyTimes();
+        EasyMock.expect(rc.isUseTicketCache()).andReturn(useTicketCache != null ? useTicketCache : false).anyTimes();
+        EasyMock.replay(rc);
+        return rc;
+    }
+
+    private static void validateDigestContext(RemoteConfigurationRegistryJAASConfig config,
+                                              String                                entryName,
+                                              String                                loginModule,
+                                              String                                principal,
+                                              String                                password) throws Exception {
+        AppConfigurationEntry[] myContextEntries = config.getAppConfigurationEntry(entryName);
+        assertNotNull(myContextEntries);
+        assertEquals(1, myContextEntries.length);
+        AppConfigurationEntry entry = myContextEntries[0];
+        assertTrue(entry.getLoginModuleName().equals(loginModule));
+        Map<String, ?> entryOpts = entry.getOptions();
+        assertEquals(principal, entryOpts.get("username"));
+        assertEquals(password, entryOpts.get("password"));
+    }
+
+    private static void validateKerberosContext(RemoteConfigurationRegistryJAASConfig config,
+                                                String                                entryName,
+                                                String                                principal,
+                                                String                                keyTab,
+                                                boolean                               useKeyTab,
+                                                boolean                               useTicketCache) throws Exception {
+        AppConfigurationEntry[] myContextEntries = config.getAppConfigurationEntry(entryName);
+        assertNotNull(myContextEntries);
+        assertEquals(1, myContextEntries.length);
+        AppConfigurationEntry entry = myContextEntries[0];
+        assertTrue(entry.getLoginModuleName().endsWith(".security.auth.module.Krb5LoginModule"));
+        Map<String, ?> entryOpts = entry.getOptions();
+        assertEquals(principal, entryOpts.get("principal"));
+        assertEquals(keyTab, entryOpts.get("keyTab"));
+        assertEquals(useKeyTab, Boolean.valueOf((String)entryOpts.get("isUseKeyTab")));
+        assertEquals(useTicketCache, Boolean.valueOf((String)entryOpts.get("isUseTicketCache")));
+    }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClient.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClient.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClient.java
deleted file mode 100644
index bfb4518..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClient.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.services.config.client;
-
-import java.util.List;
-
-public interface RemoteConfigurationRegistryClient {
-
-    String getAddress();
-
-    boolean isAuthenticationConfigured();
-
-    boolean entryExists(String path);
-
-    List<EntryACL> getACL(String path);
-
-    void setACL(String path, List<EntryACL> acls);
-
-    List<String> listChildEntries(String path);
-
-    String getEntryData(String path);
-
-    String getEntryData(String path, String encoding);
-
-    void createEntry(String path);
-
-    void createEntry(String path, String data);
-
-    void createEntry(String path, String data, String encoding);
-
-    int setEntryData(String path, String data);
-
-    int setEntryData(String path, String data, String encoding);
-
-    void deleteEntry(String path);
-
-    void addChildEntryListener(String path, ChildEntryListener listener) throws Exception;
-
-    void addEntryListener(String path, EntryListener listener) throws Exception;
-
-    void removeEntryListener(String path) throws Exception;
-
-    interface ChildEntryListener {
-
-        enum Type {
-            ADDED,
-            REMOVED,
-            UPDATED
-        }
-
-        void childEvent(RemoteConfigurationRegistryClient client, ChildEntryListener.Type type, String path);
-    }
-
-    interface EntryListener {
-        void entryChanged(RemoteConfigurationRegistryClient client, String path, byte[] data);
-    }
-
-    interface EntryACL {
-        String getId();
-        String getType();
-        Object getPermissions();
-        boolean canRead();
-        boolean canWrite();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClientService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClientService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClientService.java
deleted file mode 100644
index 1467f75..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/config/client/RemoteConfigurationRegistryClientService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.services.config.client;
-
-import org.apache.hadoop.gateway.services.Service;
-import org.apache.hadoop.gateway.services.security.AliasService;
-
-public interface RemoteConfigurationRegistryClientService extends Service {
-
-    void setAliasService(AliasService aliasService);
-
-    RemoteConfigurationRegistryClient get(String l);
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/ClusterConfigurationMonitorService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/ClusterConfigurationMonitorService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/ClusterConfigurationMonitorService.java
deleted file mode 100644
index 961f2e5..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/ClusterConfigurationMonitorService.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology;
-
-import org.apache.hadoop.gateway.services.Service;
-import org.apache.hadoop.gateway.topology.discovery.ClusterConfigurationMonitor;
-
-/**
- * Gateway service for managing cluster configuration monitors.
- */
-public interface ClusterConfigurationMonitorService extends Service {
-
-    /**
-     *
-     * @param type The type of monitor (e.g., Ambari)
-     *
-     * @return The monitor associated with the specified type, or null if there is no such monitor.
-     */
-    ClusterConfigurationMonitor getMonitor(String type);
-
-
-    /**
-     * Register for configuration change notifications from <em>any</em> of the monitors managed by this service.
-     *
-     * @param listener The listener to register.
-     */
-    void addListener(ClusterConfigurationMonitor.ConfigurationChangeListener listener);
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitor.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitor.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitor.java
deleted file mode 100644
index fc3614d..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitor.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.discovery;
-
-public interface ClusterConfigurationMonitor {
-
-    /**
-     * Start the monitor.
-     */
-    void start();
-
-    /**
-     * Stop the monitor.
-     */
-    void stop();
-
-    /**
-     *
-     * @param interval The polling interval, in seconds
-     */
-    void setPollingInterval(int interval);
-
-    /**
-     * Register for notifications from the monitor.
-     */
-    void addListener(ConfigurationChangeListener listener);
-
-    /**
-     * Monitor listener interface for receiving notifications that a configuration has changed.
-     */
-    interface ConfigurationChangeListener {
-        void onConfigurationChange(String source, String clusterName);
-    }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java
deleted file mode 100644
index a8d5f30..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.discovery;
-
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.services.security.AliasService;
-
-public interface ClusterConfigurationMonitorProvider {
-
-    String getType();
-
-    ClusterConfigurationMonitor newInstance(GatewayConfig config, AliasService aliasService);
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitor.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitor.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitor.java
deleted file mode 100644
index 82c5809..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitor.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.monitor;
-
-public interface RemoteConfigurationMonitor {
-
-    void start() throws Exception;
-
-    void stop() throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java
deleted file mode 100644
index d19dace..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.monitor;
-
-
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService;
-
-public interface RemoteConfigurationMonitorProvider {
-
-    /**
-     *
-     * @param config        The gateway configuration.
-     * @param clientService The RemoteConfigurationRegistryClientService for accessing the remote configuration.
-     *
-     * @return A RemoteConfigurationMonitor for keeping the local config in sync with the remote config
-     */
-    RemoteConfigurationMonitor newInstance(GatewayConfig config, RemoteConfigurationRegistryClientService clientService);
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClient.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClient.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClient.java
new file mode 100644
index 0000000..5afae63
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClient.java
@@ -0,0 +1,80 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.services.config.client;
+
+import java.util.List;
+
+public interface RemoteConfigurationRegistryClient {
+
+    String getAddress();
+
+    boolean isAuthenticationConfigured();
+
+    boolean entryExists(String path);
+
+    List<EntryACL> getACL(String path);
+
+    void setACL(String path, List<EntryACL> acls);
+
+    List<String> listChildEntries(String path);
+
+    String getEntryData(String path);
+
+    String getEntryData(String path, String encoding);
+
+    void createEntry(String path);
+
+    void createEntry(String path, String data);
+
+    void createEntry(String path, String data, String encoding);
+
+    int setEntryData(String path, String data);
+
+    int setEntryData(String path, String data, String encoding);
+
+    void deleteEntry(String path);
+
+    void addChildEntryListener(String path, ChildEntryListener listener) throws Exception;
+
+    void addEntryListener(String path, EntryListener listener) throws Exception;
+
+    void removeEntryListener(String path) throws Exception;
+
+    interface ChildEntryListener {
+
+        enum Type {
+            ADDED,
+            REMOVED,
+            UPDATED
+        }
+
+        void childEvent(RemoteConfigurationRegistryClient client, ChildEntryListener.Type type, String path);
+    }
+
+    interface EntryListener {
+        void entryChanged(RemoteConfigurationRegistryClient client, String path, byte[] data);
+    }
+
+    interface EntryACL {
+        String getId();
+        String getType();
+        Object getPermissions();
+        boolean canRead();
+        boolean canWrite();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClientService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClientService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClientService.java
new file mode 100644
index 0000000..77573dd
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/config/client/RemoteConfigurationRegistryClientService.java
@@ -0,0 +1,28 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.services.config.client;
+
+import org.apache.knox.gateway.services.Service;
+import org.apache.knox.gateway.services.security.AliasService;
+
+public interface RemoteConfigurationRegistryClientService extends Service {
+
+    void setAliasService(AliasService aliasService);
+
+    RemoteConfigurationRegistryClient get(String l);
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/knox/gateway/topology/ClusterConfigurationMonitorService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/topology/ClusterConfigurationMonitorService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/ClusterConfigurationMonitorService.java
new file mode 100644
index 0000000..0bfaa5f
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/ClusterConfigurationMonitorService.java
@@ -0,0 +1,43 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology;
+
+import org.apache.knox.gateway.services.Service;
+import org.apache.knox.gateway.topology.discovery.ClusterConfigurationMonitor;
+
+/**
+ * Gateway service for managing cluster configuration monitors.
+ */
+public interface ClusterConfigurationMonitorService extends Service {
+
+    /**
+     *
+     * @param type The type of monitor (e.g., Ambari)
+     *
+     * @return The monitor associated with the specified type, or null if there is no such monitor.
+     */
+    ClusterConfigurationMonitor getMonitor(String type);
+
+
+    /**
+     * Register for configuration change notifications from <em>any</em> of the monitors managed by this service.
+     *
+     * @param listener The listener to register.
+     */
+    void addListener(ClusterConfigurationMonitor.ConfigurationChangeListener listener);
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitor.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitor.java b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitor.java
new file mode 100644
index 0000000..641bad5
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitor.java
@@ -0,0 +1,48 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.discovery;
+
+public interface ClusterConfigurationMonitor {
+
+    /**
+     * Start the monitor.
+     */
+    void start();
+
+    /**
+     * Stop the monitor.
+     */
+    void stop();
+
+    /**
+     *
+     * @param interval The polling interval, in seconds
+     */
+    void setPollingInterval(int interval);
+
+    /**
+     * Register for notifications from the monitor.
+     */
+    void addListener(ConfigurationChangeListener listener);
+
+    /**
+     * Monitor listener interface for receiving notifications that a configuration has changed.
+     */
+    interface ConfigurationChangeListener {
+        void onConfigurationChange(String source, String clusterName);
+    }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java
new file mode 100644
index 0000000..c84e5c9
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/discovery/ClusterConfigurationMonitorProvider.java
@@ -0,0 +1,27 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.discovery;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.security.AliasService;
+
+public interface ClusterConfigurationMonitorProvider {
+
+    String getType();
+
+    ClusterConfigurationMonitor newInstance(GatewayConfig config, AliasService aliasService);
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitor.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitor.java b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitor.java
new file mode 100644
index 0000000..0ce1513
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitor.java
@@ -0,0 +1,24 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.monitor;
+
+public interface RemoteConfigurationMonitor {
+
+    void start() throws Exception;
+
+    void stop() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java
new file mode 100644
index 0000000..cab33f9
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorProvider.java
@@ -0,0 +1,34 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.monitor;
+
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+
+public interface RemoteConfigurationMonitorProvider {
+
+    /**
+     *
+     * @param config        The gateway configuration.
+     * @param clientService The RemoteConfigurationRegistryClientService for accessing the remote configuration.
+     *
+     * @return A RemoteConfigurationMonitor for keeping the local config in sync with the remote config
+     */
+    RemoteConfigurationMonitor newInstance(GatewayConfig config, RemoteConfigurationRegistryClientService clientService);
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-test/src/test/java/org/apache/hadoop/gateway/SimpleDescriptorHandlerFuncTest.java
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/java/org/apache/hadoop/gateway/SimpleDescriptorHandlerFuncTest.java b/gateway-test/src/test/java/org/apache/hadoop/gateway/SimpleDescriptorHandlerFuncTest.java
deleted file mode 100644
index bda8952..0000000
--- a/gateway-test/src/test/java/org/apache/hadoop/gateway/SimpleDescriptorHandlerFuncTest.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.services.GatewayServices;
-import org.apache.hadoop.gateway.services.security.AliasService;
-import org.apache.hadoop.gateway.services.security.KeystoreService;
-import org.apache.hadoop.gateway.services.security.MasterService;
-import org.apache.hadoop.gateway.services.topology.TopologyService;
-import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
-import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryConfig;
-import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType;
-import org.apache.hadoop.gateway.topology.simple.SimpleDescriptor;
-import org.apache.hadoop.gateway.topology.simple.SimpleDescriptorHandler;
-import org.apache.hadoop.test.TestUtils;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.junit.Test;
-
-import java.io.File;
-import java.net.InetSocketAddress;
-import java.security.KeyStore;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.capture;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-public class SimpleDescriptorHandlerFuncTest {
-
-
-  private static final String TEST_PROVIDER_CONFIG =
-      "    <gateway>\n" +
-          "        <provider>\n" +
-          "            <role>authentication</role>\n" +
-          "            <name>ShiroProvider</name>\n" +
-          "            <enabled>true</enabled>\n" +
-          "            <param>\n" +
-          "                <name>sessionTimeout</name>\n" +
-          "                <value>30</value>\n" +
-          "            </param>\n" +
-          "            <param>\n" +
-          "                <name>main.ldapRealm</name>\n" +
-          "                <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm</value>\n" +
-          "            </param>\n" +
-          "            <param>\n" +
-          "                <name>main.ldapContextFactory</name>\n" +
-          "                <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory</value>\n" +
-          "            </param>\n" +
-          "            <param>\n" +
-          "                <name>main.ldapRealm.contextFactory</name>\n" +
-          "                <value>$ldapContextFactory</value>\n" +
-          "            </param>\n" +
-          "            <param>\n" +
-          "                <name>main.ldapRealm.userDnTemplate</name>\n" +
-          "                <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>\n" +
-          "            </param>\n" +
-          "            <param>\n" +
-          "                <name>main.ldapRealm.contextFactory.url</name>\n" +
-          "                <value>ldap://localhost:33389</value>\n" +
-          "            </param>\n" +
-          "            <param>\n" +
-          "                <name>main.ldapRealm.contextFactory.authenticationMechanism</name>\n" +
-          "                <value>simple</value>\n" +
-          "            </param>\n" +
-          "            <param>\n" +
-          "                <name>urls./**</name>\n" +
-          "                <value>authcBasic</value>\n" +
-          "            </param>\n" +
-          "        </provider>\n" +
-          "\n" +
-          "        <provider>\n" +
-          "            <role>identity-assertion</role>\n" +
-          "            <name>Default</name>\n" +
-          "            <enabled>true</enabled>\n" +
-          "        </provider>\n" +
-          "\n" +
-          "        <provider>\n" +
-          "            <role>hostmap</role>\n" +
-          "            <name>static</name>\n" +
-          "            <enabled>true</enabled>\n" +
-          "            <param><name>localhost</name><value>sandbox,sandbox.hortonworks.com</value></param>\n" +
-          "        </provider>\n" +
-          "    </gateway>\n";
-
-
-  /**
-   * KNOX-1136
-   * <p>
-   * Test that a credential store is created, and a encryptQueryString alias is defined, with a password that is not
-   * random (but is derived from the master secret and the topology name).
-   * <p>
-   * N.B. This test depends on the NoOpServiceDiscovery extension being configured in META-INF/services
-   */
-  @Test
-  public void testSimpleDescriptorHandlerQueryStringCredentialAliasCreation() throws Exception {
-
-    final String testMasterSecret = "mysecret";
-    final String discoveryType = "NO_OP";
-    final String clusterName = "dummy";
-
-    final Map<String, List<String>> serviceURLs = new HashMap<>();
-    serviceURLs.put("RESOURCEMANAGER", Collections.singletonList("http://myhost:1234/resource"));
-
-    File testRootDir = TestUtils.createTempDir(getClass().getSimpleName());
-    File testConfDir = new File(testRootDir, "conf");
-    File testProvDir = new File(testConfDir, "shared-providers");
-    File testTopoDir = new File(testConfDir, "topologies");
-    File testDeployDir = new File(testConfDir, "deployments");
-
-    // Write the externalized provider config to a temp file
-    File providerConfig = new File(testProvDir, "ambari-cluster-policy.xml");
-    FileUtils.write(providerConfig, TEST_PROVIDER_CONFIG);
-
-    File topologyFile = null;
-    try {
-      File destDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile();
-
-      // Mock out the simple descriptor
-      SimpleDescriptor testDescriptor = EasyMock.createNiceMock(SimpleDescriptor.class);
-      EasyMock.expect(testDescriptor.getName()).andReturn("mysimpledescriptor").anyTimes();
-      EasyMock.expect(testDescriptor.getDiscoveryAddress()).andReturn(null).anyTimes();
-      EasyMock.expect(testDescriptor.getDiscoveryType()).andReturn(discoveryType).anyTimes();
-      EasyMock.expect(testDescriptor.getDiscoveryUser()).andReturn(null).anyTimes();
-      EasyMock.expect(testDescriptor.getProviderConfig()).andReturn(providerConfig.getAbsolutePath()).anyTimes();
-      EasyMock.expect(testDescriptor.getClusterName()).andReturn(clusterName).anyTimes();
-      List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>();
-      for (String serviceName : serviceURLs.keySet()) {
-        SimpleDescriptor.Service svc = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
-        EasyMock.expect(svc.getName()).andReturn(serviceName).anyTimes();
-        EasyMock.expect(svc.getURLs()).andReturn(serviceURLs.get(serviceName)).anyTimes();
-        EasyMock.expect(svc.getParams()).andReturn(Collections.emptyMap()).anyTimes();
-        EasyMock.replay(svc);
-        serviceMocks.add(svc);
-      }
-      EasyMock.expect(testDescriptor.getServices()).andReturn(serviceMocks).anyTimes();
-      EasyMock.replay(testDescriptor);
-
-      // Try setting up enough of the GatewayServer to support the test...
-      GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
-      InetSocketAddress gatewayAddress = new InetSocketAddress(0);
-      EasyMock.expect(config.getGatewayTopologyDir()).andReturn(testTopoDir.getAbsolutePath()).anyTimes();
-      EasyMock.expect(config.getGatewayDeploymentDir()).andReturn(testDeployDir.getAbsolutePath()).anyTimes();
-      EasyMock.expect(config.getGatewayAddress()).andReturn(gatewayAddress).anyTimes();
-      EasyMock.expect(config.getGatewayPortMappings()).andReturn(Collections.emptyMap()).anyTimes();
-      EasyMock.replay(config);
-
-      // Setup the Gateway Services
-      GatewayServices gatewayServices = EasyMock.createNiceMock(GatewayServices.class);
-
-      // Master Service
-      MasterService ms = EasyMock.createNiceMock(MasterService.class);
-      EasyMock.expect(ms.getMasterSecret()).andReturn(testMasterSecret.toCharArray()).anyTimes();
-      EasyMock.replay(ms);
-      EasyMock.expect(gatewayServices.getService("MasterService")).andReturn(ms).anyTimes();
-
-      // Keystore Service
-      KeystoreService ks = EasyMock.createNiceMock(KeystoreService.class);
-      EasyMock.expect(ks.isCredentialStoreForClusterAvailable(testDescriptor.getName())).andReturn(false).once();
-      ks.createCredentialStoreForCluster(testDescriptor.getName());
-      EasyMock.expectLastCall().once();
-      KeyStore credStore = EasyMock.createNiceMock(KeyStore.class);
-      EasyMock.expect(ks.getCredentialStoreForCluster(testDescriptor.getName())).andReturn(credStore).anyTimes();
-      EasyMock.replay(ks);
-      EasyMock.expect(gatewayServices.getService(GatewayServices.KEYSTORE_SERVICE)).andReturn(ks).anyTimes();
-
-      // Alias Service
-      AliasService as = EasyMock.createNiceMock(AliasService.class);
-      // Captures for validating the alias creation for a generated topology
-      Capture<String> capturedCluster = EasyMock.newCapture();
-      Capture<String> capturedAlias = EasyMock.newCapture();
-      Capture<String> capturedPwd = EasyMock.newCapture();
-      as.addAliasForCluster(capture(capturedCluster), capture(capturedAlias), capture(capturedPwd));
-      EasyMock.expectLastCall().anyTimes();
-      EasyMock.replay(as);
-      EasyMock.expect(gatewayServices.getService(GatewayServices.ALIAS_SERVICE)).andReturn(as).anyTimes();
-
-      // Topology Service
-      TopologyService ts = EasyMock.createNiceMock(TopologyService.class);
-      ts.addTopologyChangeListener(anyObject());
-      EasyMock.expectLastCall().anyTimes();
-      ts.reloadTopologies();
-      EasyMock.expectLastCall().anyTimes();
-      EasyMock.expect(ts.getTopologies()).andReturn(Collections.emptyList()).anyTimes();
-      EasyMock.replay(ts);
-      EasyMock.expect(gatewayServices.getService(GatewayServices.TOPOLOGY_SERVICE)).andReturn(ts).anyTimes();
-
-      EasyMock.replay(gatewayServices);
-
-      // Start a GatewayService with the GatewayServices mock
-      GatewayServer server = GatewayServer.startGateway(config, gatewayServices);
-
-      // Invoke the simple descriptor handler, which will also create the credential store
-      // (because it doesn't exist) and the encryptQueryString alias
-      Map<String, File> files = SimpleDescriptorHandler.handle(testDescriptor,
-                                                               providerConfig.getParentFile(),
-                                                               destDir);
-      topologyFile = files.get("topology");
-
-      // Validate the AliasService interaction
-      assertEquals("Unexpected cluster name for the alias (should be the topology name).",
-                   testDescriptor.getName(), capturedCluster.getValue());
-      assertEquals("Unexpected alias name.", "encryptQueryString", capturedAlias.getValue());
-      assertEquals("Unexpected alias value (should be master secret + topology name.",
-                   testMasterSecret + testDescriptor.getName(), capturedPwd.getValue());
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      fail(e.getMessage());
-    } finally {
-      FileUtils.forceDelete(testRootDir);
-      if (topologyFile != null) {
-        topologyFile.delete();
-      }
-    }
-  }
-
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Test classes for effectively "skipping" service discovery for this test.
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static final class NoOpServiceDiscoveryType implements ServiceDiscoveryType {
-    @Override
-    public String getType() {
-      return NoOpServiceDiscovery.TYPE;
-    }
-
-    @Override
-    public ServiceDiscovery newInstance() {
-      return new NoOpServiceDiscovery();
-    }
-  }
-
-  private static final class NoOpServiceDiscovery implements ServiceDiscovery {
-    static final String TYPE = "NO_OP";
-
-    @Override
-    public String getType() {
-      return TYPE;
-    }
-
-    @Override
-    public Map<String, Cluster> discover(ServiceDiscoveryConfig config) {
-      return Collections.emptyMap();
-    }
-
-    @Override
-    public Cluster discover(ServiceDiscoveryConfig config, String clusterName) {
-      return null;
-    }
-  }
-
-}


Mime
View raw message