You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/12/14 21:13:33 UTC

[46/49] knox git commit: KNOX-998 - Merge from trunk 0.14.0 code

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistry.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistry.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistry.java
deleted file mode 100644
index f3e7dbd..0000000
--- a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistry.java
+++ /dev/null
@@ -1,139 +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.service.config.remote.config;
-
-import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
-
-import javax.xml.bind.annotation.XmlElement;
-
-class RemoteConfigurationRegistry implements RemoteConfigurationRegistryConfig {
-
-    private String name;
-    private String type;
-    private String connectionString;
-    private String namespace;
-    private String authType;
-    private String principal;
-    private String credentialAlias;
-    private String keyTab;
-    private boolean useKeyTab;
-    private boolean useTicketCache;
-
-    RemoteConfigurationRegistry() {
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public void setRegistryType(String type) {
-        this.type = type;
-    }
-
-    public void setConnectionString(String connectionString) {
-        this.connectionString = connectionString;
-    }
-
-    public void setNamespace(String namespace) {
-        this.namespace = namespace;
-    }
-
-    public void setAuthType(String authType) {
-        this.authType = authType;
-    }
-
-    public void setPrincipal(String principal) {
-        this.principal = principal;
-    }
-
-    public void setCredentialAlias(String alias) {
-        this.credentialAlias = alias;
-    }
-
-    public void setUseTicketCache(boolean useTicketCache) {
-        this.useTicketCache = useTicketCache;
-    }
-
-    public void setUseKeytab(boolean useKeytab) {
-        this.useKeyTab = useKeytab;
-    }
-
-    public void setKeytab(String keytab) {
-        this.keyTab = keytab;
-    }
-
-    @XmlElement(name="name")
-    public String getName() {
-        return name;
-    }
-
-    @XmlElement(name="type")
-    public String getRegistryType() {
-        return type;
-    }
-
-    @XmlElement(name="auth-type")
-    public String getAuthType() {
-        return authType;
-    }
-
-    @XmlElement(name="principal")
-    public String getPrincipal() {
-        return principal;
-    }
-
-    @XmlElement(name="credential-alias")
-    public String getCredentialAlias() {
-        return credentialAlias;
-    }
-
-    @Override
-    @XmlElement(name="address")
-    public String getConnectionString() {
-        return connectionString;
-    }
-
-    @Override
-    @XmlElement(name="namespace")
-    public String getNamespace() {
-        return namespace;
-    }
-
-    @Override
-    @XmlElement(name="use-ticket-cache")
-    public boolean isUseTicketCache() {
-        return useTicketCache;
-    }
-
-    @Override
-    @XmlElement(name="use-key-tab")
-    public boolean isUseKeyTab() {
-        return useKeyTab;
-    }
-
-    @Override
-    @XmlElement(name="keytab")
-    public String getKeytab() {
-        return keyTab;
-    }
-
-    @Override
-    public boolean isSecureRegistry() {
-        return (getAuthType() != null);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/CuratorClientService.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/CuratorClientService.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/CuratorClientService.java
deleted file mode 100644
index f9b5ab3..0000000
--- a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/CuratorClientService.java
+++ /dev/null
@@ -1,464 +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.service.config.remote.zk;
-
-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.framework.recipes.cache.ChildData;
-import org.apache.curator.framework.recipes.cache.NodeCache;
-import org.apache.curator.framework.recipes.cache.NodeCacheListener;
-import org.apache.curator.framework.recipes.cache.PathChildrenCache;
-import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
-import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
-import org.apache.curator.retry.ExponentialBackoffRetry;
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationMessages;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient.EntryListener;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient;
-import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
-import org.apache.hadoop.gateway.service.config.remote.config.RemoteConfigurationRegistriesAccessor;
-import org.apache.hadoop.gateway.services.ServiceLifecycleException;
-import org.apache.hadoop.gateway.services.security.AliasService;
-import org.apache.zookeeper.ZooDefs;
-import org.apache.zookeeper.client.ZooKeeperSaslClient;
-import org.apache.zookeeper.data.ACL;
-import org.apache.zookeeper.data.Id;
-import org.apache.zookeeper.data.Stat;
-
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * RemoteConfigurationRegistryClientService implementation that employs the Curator ZooKeeper client framework.
- */
-class CuratorClientService implements ZooKeeperClientService {
-
-    private static final String LOGIN_CONTEXT_NAME_PROPERTY = ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY;
-
-    private static final String DEFAULT_LOGIN_CONTEXT_NAME = "Client";
-
-    private static final RemoteConfigurationMessages log =
-                                                        MessagesFactory.get(RemoteConfigurationMessages.class);
-
-    private Map<String, RemoteConfigurationRegistryClient> clients = new HashMap<>();
-
-    private AliasService aliasService = null;
-
-
-    @Override
-    public void init(GatewayConfig config, Map<String, String> options) throws ServiceLifecycleException {
-
-        List<RemoteConfigurationRegistryConfig> registryConfigs = new ArrayList<>();
-
-        // Load the remote registry configurations
-        registryConfigs.addAll(RemoteConfigurationRegistriesAccessor.getRemoteRegistryConfigurations(config));
-
-        // Configure registry authentication
-        RemoteConfigurationRegistryJAASConfig.configure(registryConfigs, aliasService);
-
-        if (registryConfigs.size() > 1) {
-            // Warn about current limit on number of supported client configurations
-            log.multipleRemoteRegistryConfigurations();
-        }
-
-        // Create the clients
-        for (RemoteConfigurationRegistryConfig registryConfig : registryConfigs) {
-            if (TYPE.equalsIgnoreCase(registryConfig.getRegistryType())) {
-                RemoteConfigurationRegistryClient registryClient = createClient(registryConfig);
-                clients.put(registryConfig.getName(), registryClient);
-            }
-        }
-    }
-
-    @Override
-    public void setAliasService(AliasService aliasService) {
-        this.aliasService = aliasService;
-    }
-
-    @Override
-    public void start() throws ServiceLifecycleException {
-    }
-
-    @Override
-    public void stop() throws ServiceLifecycleException {
-    }
-
-    @Override
-    public RemoteConfigurationRegistryClient get(String name) {
-        return clients.get(name);
-    }
-
-
-    private RemoteConfigurationRegistryClient createClient(RemoteConfigurationRegistryConfig config) {
-        ACLProvider aclProvider;
-        if (config.isSecureRegistry()) {
-            configureSasl(config);
-            aclProvider = new SASLOwnerACLProvider();
-        } else {
-            // Clear SASL system property
-            System.clearProperty(LOGIN_CONTEXT_NAME_PROPERTY);
-            aclProvider = new DefaultACLProvider();
-        }
-
-        CuratorFramework client = CuratorFrameworkFactory.builder()
-                                                         .connectString(config.getConnectionString())
-                                                         .retryPolicy(new ExponentialBackoffRetry(1000, 3))
-                                                         .aclProvider(aclProvider)
-                                                         .build();
-        client.start();
-
-        return (new ClientAdapter(client, config));
-    }
-
-
-    private void configureSasl(RemoteConfigurationRegistryConfig config) {
-        String registryName = config.getName();
-        if (registryName == null) {
-            registryName = DEFAULT_LOGIN_CONTEXT_NAME;
-        }
-        System.setProperty(LOGIN_CONTEXT_NAME_PROPERTY, registryName);
-    }
-
-
-    private static final class ClientAdapter implements RemoteConfigurationRegistryClient {
-
-        private static final String DEFAULT_ENCODING = "UTF-8";
-
-        private CuratorFramework delegate;
-
-        private RemoteConfigurationRegistryConfig config;
-
-        private Map<String, NodeCache> entryNodeCaches = new HashMap<>();
-
-        ClientAdapter(CuratorFramework delegate, RemoteConfigurationRegistryConfig config) {
-            this.delegate = delegate;
-            this.config = config;
-        }
-
-        @Override
-        public String getAddress() {
-            return config.getConnectionString();
-        }
-
-        @Override
-        public boolean isAuthenticationConfigured() {
-            return config.isSecureRegistry();
-        }
-
-        @Override
-        public boolean entryExists(String path) {
-            Stat s = null;
-            try {
-                s = delegate.checkExists().forPath(path);
-            } catch (Exception e) {
-                // Ignore
-            }
-            return (s != null);
-        }
-
-        @Override
-        public List<RemoteConfigurationRegistryClient.EntryACL> getACL(String path) {
-            List<RemoteConfigurationRegistryClient.EntryACL> acl = new ArrayList<>();
-            try {
-                List<ACL> zkACL = delegate.getACL().forPath(path);
-                if (zkACL != null) {
-                    for (ACL aclEntry : zkACL) {
-                        RemoteConfigurationRegistryClient.EntryACL entryACL = new ZooKeeperACLAdapter(aclEntry);
-                        acl.add(entryACL);
-                    }
-                }
-            } catch (Exception e) {
-                log.errorHandlingRemoteConfigACL(path, e);
-            }
-            return acl;
-        }
-
-        @Override
-        public void setACL(String path, List<EntryACL> entryACLs) {
-            // Translate the abstract ACLs into ZooKeeper ACLs
-            List<ACL> delegateACLs = new ArrayList<>();
-            for (EntryACL entryACL : entryACLs) {
-                String scheme = entryACL.getType();
-                String id = entryACL.getId();
-                int permissions = 0;
-                if (entryACL.canWrite()) {
-                    permissions = ZooDefs.Perms.ALL;
-                } else if (entryACL.canRead()){
-                    permissions = ZooDefs.Perms.READ;
-                }
-                delegateACLs.add(new ACL(permissions, new Id(scheme, id)));
-            }
-
-            try {
-                // Set the ACLs for the path
-                delegate.setACL().withACL(delegateACLs).forPath(path);
-            } catch (Exception e) {
-                log.errorSettingEntryACL(path, e);
-            }
-        }
-
-        @Override
-        public List<String> listChildEntries(String path) {
-            List<String> result = null;
-            try {
-                result = delegate.getChildren().forPath(path);
-            } catch (Exception e) {
-                log.errorInteractingWithRemoteConfigRegistry(e);
-            }
-            return result;
-        }
-
-        @Override
-        public void addChildEntryListener(String path, ChildEntryListener listener) throws Exception {
-            PathChildrenCache childCache = new PathChildrenCache(delegate, path, false);
-            childCache.getListenable().addListener(new ChildEntryListenerAdapter(this, listener));
-            childCache.start();
-        }
-
-        @Override
-        public void addEntryListener(String path, EntryListener listener) throws Exception {
-            NodeCache nodeCache = new NodeCache(delegate, path);
-            nodeCache.getListenable().addListener(new EntryListenerAdapter(this, nodeCache, listener));
-            nodeCache.start();
-            entryNodeCaches.put(path, nodeCache);
-        }
-
-        @Override
-        public void removeEntryListener(String path) throws Exception {
-            NodeCache nodeCache = entryNodeCaches.remove(path);
-            if (nodeCache != null) {
-                nodeCache.close();
-            }
-        }
-
-        @Override
-        public String getEntryData(String path) {
-            return getEntryData(path, DEFAULT_ENCODING);
-        }
-
-        @Override
-        public String getEntryData(String path, String encoding) {
-            String result = null;
-            try {
-                byte[] data = delegate.getData().forPath(path);
-                if (data != null) {
-                    result = new String(data, Charset.forName(encoding));
-                }
-            } catch (Exception e) {
-                log.errorInteractingWithRemoteConfigRegistry(e);
-            }
-            return result;
-        }
-
-        @Override
-        public void createEntry(String path) {
-            try {
-                if (delegate.checkExists().forPath(path) == null) {
-                    delegate.create().forPath(path);
-                }
-            } catch (Exception e) {
-                log.errorInteractingWithRemoteConfigRegistry(e);
-            }
-        }
-
-        @Override
-        public void createEntry(String path, String data) {
-            createEntry(path, data, DEFAULT_ENCODING);
-        }
-
-        @Override
-        public void createEntry(String path, String data, String encoding) {
-            try {
-                createEntry(path);
-                setEntryData(path, data, encoding);
-            } catch (Exception e) {
-                log.errorInteractingWithRemoteConfigRegistry(e);
-            }
-        }
-
-        @Override
-        public int setEntryData(String path, String data) {
-            return setEntryData(path, data, DEFAULT_ENCODING);
-        }
-
-        @Override
-        public int setEntryData(String path, String data, String encoding) {
-            int version = 0;
-            try {
-                Stat s = delegate.setData().forPath(path, data.getBytes(Charset.forName(encoding)));
-                if (s != null) {
-                    version = s.getVersion();
-                }
-            } catch (Exception e) {
-                log.errorInteractingWithRemoteConfigRegistry(e);
-            }
-            return version;
-        }
-
-        @Override
-        public void deleteEntry(String path) {
-            try {
-                delegate.delete().forPath(path);
-            } catch (Exception e) {
-                log.errorInteractingWithRemoteConfigRegistry(e);
-            }
-        }
-    }
-
-    /**
-     * SASL ACLProvider
-     */
-    private static class SASLOwnerACLProvider implements ACLProvider {
-
-        private final List<ACL> saslACL;
-
-        private SASLOwnerACLProvider() {
-            this.saslACL = ZooDefs.Ids.CREATOR_ALL_ACL; // All permissions for any authenticated user
-        }
-
-        @Override
-        public List<ACL> getDefaultAcl() {
-            return saslACL;
-        }
-
-        @Override
-        public List<ACL> getAclForPath(String path) {
-            return getDefaultAcl();
-        }
-    }
-
-
-    private static final class ChildEntryListenerAdapter implements PathChildrenCacheListener {
-
-        private RemoteConfigurationRegistryClient client;
-        private ChildEntryListener delegate;
-
-        ChildEntryListenerAdapter(RemoteConfigurationRegistryClient client, ChildEntryListener delegate) {
-            this.client = client;
-            this.delegate = delegate;
-        }
-
-        @Override
-        public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent)
-                throws Exception {
-            ChildData childData = pathChildrenCacheEvent.getData();
-            if (childData != null) {
-                ChildEntryListener.Type eventType = adaptType(pathChildrenCacheEvent.getType());
-                if (eventType != null) {
-                    delegate.childEvent(client, eventType, childData.getPath());
-                }
-            }
-        }
-
-        private ChildEntryListener.Type adaptType(PathChildrenCacheEvent.Type type) {
-            ChildEntryListener.Type adapted = null;
-
-            switch(type) {
-                case CHILD_ADDED:
-                    adapted = ChildEntryListener.Type.ADDED;
-                    break;
-                case CHILD_REMOVED:
-                    adapted = ChildEntryListener.Type.REMOVED;
-                    break;
-                case CHILD_UPDATED:
-                    adapted = ChildEntryListener.Type.UPDATED;
-                    break;
-            }
-
-            return adapted;
-        }
-    }
-
-    private static final class EntryListenerAdapter implements NodeCacheListener {
-
-        private RemoteConfigurationRegistryClient client;
-        private EntryListener delegate;
-        private NodeCache nodeCache;
-
-        EntryListenerAdapter(RemoteConfigurationRegistryClient client, NodeCache nodeCache, EntryListener delegate) {
-            this.client = client;
-            this.nodeCache = nodeCache;
-            this.delegate = delegate;
-        }
-
-        @Override
-        public void nodeChanged() throws Exception {
-            String path = null;
-            byte[] data = null;
-
-            ChildData cd = nodeCache.getCurrentData();
-            if (cd != null) {
-                path = cd.getPath();
-                data = cd.getData();
-            }
-
-            if (path != null) {
-                delegate.entryChanged(client, path, data);
-            }
-        }
-    }
-
-    /**
-     * ACL adapter
-     */
-    private static final class ZooKeeperACLAdapter implements RemoteConfigurationRegistryClient.EntryACL {
-        private String type;
-        private String id;
-        private int permissions;
-
-        ZooKeeperACLAdapter(ACL acl) {
-            this.permissions = acl.getPerms();
-            this.type = acl.getId().getScheme();
-            this.id = acl.getId().getId();
-        }
-
-        @Override
-        public String getId() {
-            return id;
-        }
-
-        @Override
-        public String getType() {
-            return type;
-        }
-
-        @Override
-        public Object getPermissions() {
-            return permissions;
-        }
-
-        @Override
-        public boolean canRead() {
-            return (permissions >= ZooDefs.Perms.READ);
-        }
-
-        @Override
-        public boolean canWrite() {
-            return (permissions >= ZooDefs.Perms.WRITE);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java
deleted file mode 100644
index 0b5a693..0000000
--- a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java
+++ /dev/null
@@ -1,179 +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.service.config.remote.zk;
-
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationMessages;
-import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
-import org.apache.hadoop.gateway.services.security.AliasService;
-import org.apache.hadoop.gateway.services.security.AliasServiceException;
-
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.Configuration;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Configuration decorator that adds SASL JAAS configuration to whatever JAAS config is already applied.
- */
-class RemoteConfigurationRegistryJAASConfig extends Configuration {
-
-    // Underlying SASL mechanisms supported
-    enum SASLMechanism {
-        Unsupported,
-        Kerberos,
-        Digest
-    }
-
-    static final Map<String, String> digestLoginModules = new HashMap<>();
-    static {
-        digestLoginModules.put("ZOOKEEPER", "org.apache.zookeeper.server.auth.DigestLoginModule");
-    }
-
-    private static final RemoteConfigurationMessages log = MessagesFactory.get(RemoteConfigurationMessages.class);
-
-    // Cache the current JAAS configuration
-    private Configuration delegate = Configuration.getConfiguration();
-
-    private AliasService aliasService;
-
-    private Map<String, AppConfigurationEntry[]> contextEntries =  new HashMap<>();
-
-    static RemoteConfigurationRegistryJAASConfig configure(List<RemoteConfigurationRegistryConfig> configs, AliasService aliasService) {
-        return new RemoteConfigurationRegistryJAASConfig(configs, aliasService);
-    }
-
-    private RemoteConfigurationRegistryJAASConfig(List<RemoteConfigurationRegistryConfig> configs, AliasService aliasService) {
-        this.aliasService = aliasService;
-
-        // Populate context entries
-        List<AppConfigurationEntry> appConfigEntries = new ArrayList<>();
-        for (RemoteConfigurationRegistryConfig config : configs) {
-            if (config.isSecureRegistry()) {
-                contextEntries.put(config.getName(), createEntries(config));
-            }
-        }
-
-        // If there is at least one context entry, then set this as the client configuration
-        if (!contextEntries.isEmpty()) {
-            // TODO: PJZ: ZooKeeper 3.6.0 will have per-client JAAS Configuration support; Upgrade ASAP!!
-            // For now, set this as the static JAAS configuration
-            Configuration.setConfiguration(this);
-        }
-    }
-
-    @Override
-    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-        AppConfigurationEntry[] result = null;
-
-        // First, try the delegate's context entries
-        result = delegate.getAppConfigurationEntry(name);
-        if (result == null || result.length < 1) {
-            // Try our additional context entries
-            result = contextEntries.get(name);
-        }
-
-        return result;
-    }
-
-    private AppConfigurationEntry[] createEntries(RemoteConfigurationRegistryConfig config) {
-        AppConfigurationEntry[] result = null;
-
-        AppConfigurationEntry entry = createEntry(config);
-        if (entry != null) {
-            // Only supporting a single app config entry per configuration/context
-            result = new AppConfigurationEntry[1];
-            result[0] = createEntry(config);
-        } else {
-            result = new AppConfigurationEntry[0];
-        }
-        return result;
-    }
-
-    private AppConfigurationEntry createEntry(RemoteConfigurationRegistryConfig config) {
-        AppConfigurationEntry entry = null;
-
-        Map<String, String> opts = new HashMap<>();
-        SASLMechanism saslMechanism = getSASLMechanism(config.getAuthType());
-        switch (saslMechanism) {
-            case Digest:
-                // Digest auth options
-                opts.put("username", config.getPrincipal());
-
-                char[] credential = null;
-                if (aliasService != null) {
-                    try {
-                        credential = aliasService.getPasswordFromAliasForGateway(config.getCredentialAlias());
-                    } catch (AliasServiceException e) {
-                        log.unresolvedCredentialAlias(config.getCredentialAlias());
-                    }
-                } else {
-                    throw new IllegalArgumentException("The AliasService is required to resolve credential aliases.");
-                }
-
-                if (credential != null) {
-                    opts.put("password", new String(credential));
-                }
-                break;
-            case Kerberos:
-                opts.put("isUseTicketCache", String.valueOf(config.isUseTicketCache()));
-                opts.put("isUseKeyTab", String.valueOf(config.isUseKeyTab()));
-                opts.put("keyTab", config.getKeytab());
-                opts.put("principal", config.getPrincipal());
-        }
-
-        if (!opts.isEmpty()) {
-            entry = new AppConfigurationEntry(getLoginModuleName(config.getRegistryType(), saslMechanism),
-                                              AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
-                                              opts);
-        }
-
-        return entry;
-    }
-
-    private static String getLoginModuleName(String registryType, SASLMechanism saslMechanism) {
-        String loginModuleName = null;
-
-        switch (saslMechanism) {
-            case Kerberos:
-                if (System.getProperty("java.vendor").contains("IBM")) {
-                    loginModuleName = "com.ibm.security.auth.module.Krb5LoginModule";
-                } else {
-                    loginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
-                }
-                break;
-            case Digest:
-                loginModuleName = digestLoginModules.get(registryType.toUpperCase());
-        }
-        return loginModuleName;
-    }
-
-    private static SASLMechanism getSASLMechanism(String authType) {
-        SASLMechanism result = SASLMechanism.Unsupported;
-        for (SASLMechanism at : SASLMechanism.values()) {
-            if (at.name().equalsIgnoreCase(authType)) {
-                result = at;
-                break;
-            }
-        }
-        return result;
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientService.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientService.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientService.java
deleted file mode 100644
index c4add4a..0000000
--- a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientService.java
+++ /dev/null
@@ -1,25 +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.service.config.remote.zk;
-
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService;
-
-public interface ZooKeeperClientService extends RemoteConfigurationRegistryClientService {
-
-    String TYPE = "ZooKeeper";
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientServiceProvider.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientServiceProvider.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientServiceProvider.java
deleted file mode 100644
index f30d3da..0000000
--- a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/zk/ZooKeeperClientServiceProvider.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.service.config.remote.zk;
-
-import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceProvider;
-
-
-public class ZooKeeperClientServiceProvider implements RemoteConfigurationRegistryClientServiceProvider {
-
-    @Override
-    public String getType() {
-        return ZooKeeperClientService.TYPE;
-    }
-
-    @Override
-    public ZooKeeperClientService newInstance() {
-        return new CuratorClientService();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationMessages.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationMessages.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationMessages.java
new file mode 100644
index 0000000..057c8c5
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationMessages.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <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;
+
+import org.apache.knox.gateway.i18n.messages.Message;
+import org.apache.knox.gateway.i18n.messages.MessageLevel;
+import org.apache.knox.gateway.i18n.messages.Messages;
+import org.apache.knox.gateway.i18n.messages.StackTrace;
+
+
+/**
+ *
+ */
+@Messages(logger="org.apache.knox.gateway.service.config.remote")
+public interface RemoteConfigurationMessages {
+
+    @Message(level = MessageLevel.WARN,
+             text = "Multiple remote configuration registries are not currently supported if any of them requires authentication.")
+    void multipleRemoteRegistryConfigurations();
+
+    @Message(level = MessageLevel.ERROR, text = "Failed to resolve the credential alias {0}")
+    void unresolvedCredentialAlias(final String alias);
+
+    @Message(level = MessageLevel.ERROR, text = "An error occurred interacting with the remote configuration registry : {0}")
+    void errorInteractingWithRemoteConfigRegistry(@StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+    @Message(level = MessageLevel.ERROR, text = "An error occurred handling the ACL for remote configuration {0} : {1}")
+    void errorHandlingRemoteConfigACL(final String path,
+                                      @StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+    @Message(level = MessageLevel.ERROR, text = "An error occurred setting the ACL for remote configuration {0} : {1}")
+    void errorSettingEntryACL(final String path,
+                              @StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java
new file mode 100644
index 0000000..f1719b6
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java
@@ -0,0 +1,41 @@
+/**
+ * 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;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+
+import java.util.ServiceLoader;
+
+public class RemoteConfigurationRegistryClientServiceFactory {
+
+    public static RemoteConfigurationRegistryClientService newInstance(GatewayConfig config) {
+        RemoteConfigurationRegistryClientService rcs = null;
+
+        ServiceLoader<RemoteConfigurationRegistryClientServiceProvider> providers =
+                                             ServiceLoader.load(RemoteConfigurationRegistryClientServiceProvider.class);
+        for (RemoteConfigurationRegistryClientServiceProvider provider : providers) {
+            rcs = provider.newInstance();
+            if (rcs != null) {
+                break;
+            }
+        }
+
+        return rcs;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.java
new file mode 100644
index 0000000..8f69e47
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.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.service.config.remote;
+
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+
+public interface RemoteConfigurationRegistryClientServiceProvider {
+
+    String getType();
+
+    RemoteConfigurationRegistryClientService newInstance();
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryConfig.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryConfig.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryConfig.java
new file mode 100644
index 0000000..cbebad7
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/RemoteConfigurationRegistryConfig.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.service.config.remote;
+
+public interface RemoteConfigurationRegistryConfig {
+
+    String getName();
+
+    String getRegistryType();
+
+    String getConnectionString();
+
+    String getNamespace();
+
+    boolean isSecureRegistry();
+
+    String getAuthType(); // digest, kerberos, etc...
+
+    String getPrincipal();
+
+    String getCredentialAlias();
+
+    String getKeytab();
+
+    boolean isUseTicketCache();
+
+    boolean isUseKeyTab();
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java
new file mode 100644
index 0000000..0b2f248
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java
@@ -0,0 +1,104 @@
+/**
+ * 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.config;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A set of RemoteConfigurationRegistry configurations based on a set of property name-value pairs.
+ */
+class DefaultRemoteConfigurationRegistries extends RemoteConfigurationRegistries {
+
+    private static final String PROPERTY_DELIM       = ";";
+    private static final String PROPERTY_VALUE_DELIM = "=";
+
+    private List<RemoteConfigurationRegistry> configuredRegistries = new ArrayList<>();
+
+    /**
+     * Derive the remote registry configurations from the specified GatewayConfig.
+     *
+     * @param gc The source GatewayConfig
+     */
+    DefaultRemoteConfigurationRegistries(GatewayConfig gc) {
+        List<String> configRegistryNames = gc.getRemoteRegistryConfigurationNames();
+        for (String configRegistryName : configRegistryNames) {
+            configuredRegistries.add(extractConfigForRegistry(gc, configRegistryName));
+        }
+    }
+
+    /**
+     * Extract the configuration for the specified registry configuration name.
+     *
+     * @param gc           The GatewayConfig from which to extract the registry config.
+     * @param registryName The name of the registry config.
+     *
+     * @return The resulting RemoteConfigurationRegistry object, or null.
+     */
+    private static RemoteConfigurationRegistry extractConfigForRegistry(GatewayConfig gc, String registryName) {
+        RemoteConfigurationRegistry result = new RemoteConfigurationRegistry();
+
+        result.setName(registryName);
+
+        Map<String, String> properties = parsePropertyValue(gc.getRemoteRegistryConfiguration(registryName));
+
+        result.setRegistryType(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE));
+        result.setConnectionString(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS));
+        result.setNamespace(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_NAMESPACE));
+        result.setAuthType(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_AUTH_TYPE));
+        result.setPrincipal(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_PRINCIPAL));
+        result.setCredentialAlias(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_CREDENTIAL_ALIAS));
+        result.setKeytab(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_KEYTAB));
+        result.setUseKeytab(Boolean.valueOf(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_USE_KEYTAB)));
+        result.setUseTicketCache(Boolean.valueOf(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_USE_TICKET_CACHE)));
+
+        return result;
+    }
+
+    /**
+     * Parse the specified registry config properties String.
+     *
+     * @param value The property value content from GatewayConfig.
+     *
+     * @return A Map of the parsed properties and their respective values.
+     */
+    private static Map<String, String> parsePropertyValue(final String value) {
+        Map<String, String> result = new HashMap<>();
+
+        if (value != null) {
+            String[] props = value.split(PROPERTY_DELIM);
+            for (String prop : props) {
+                String[] split = prop.split(PROPERTY_VALUE_DELIM);
+                String propName  = split[0];
+                String propValue = (split.length > 1) ? split[1] : null;
+                result.put(propName, propValue);
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    List<RemoteConfigurationRegistry> getRegistryConfigurations() {
+        return configuredRegistries;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistries.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistries.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistries.java
new file mode 100644
index 0000000..16434aa
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistries.java
@@ -0,0 +1,33 @@
+/**
+ * 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.config;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
+import java.util.List;
+
+@XmlRootElement(name="remote-configuration-registries")
+class RemoteConfigurationRegistries {
+
+    private List<RemoteConfigurationRegistry> registryConfigurations = new ArrayList<>();
+
+    @XmlElement(name="remote-configuration-registry")
+    List<RemoteConfigurationRegistry> getRegistryConfigurations() {
+        return registryConfigurations;
+    }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesAccessor.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesAccessor.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesAccessor.java
new file mode 100644
index 0000000..c32816e
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesAccessor.java
@@ -0,0 +1,60 @@
+/**
+ * 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.config;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RemoteConfigurationRegistriesAccessor {
+
+    // System property for specifying a reference to an XML configuration external to the gateway config
+    private static final String XML_CONFIG_REFERENCE_SYSTEM_PROPERTY_NAME =
+                                                                "org.apache.knox.gateway.remote.registry.config.file";
+
+
+    public static List<RemoteConfigurationRegistryConfig> getRemoteRegistryConfigurations(GatewayConfig gatewayConfig) {
+        List<RemoteConfigurationRegistryConfig> result = new ArrayList<>();
+
+        boolean useReferencedFile = false;
+
+        // First check for the system property pointing to a valid XML config for the remote registries
+        String remoteConfigRegistryConfigFilename = System.getProperty(XML_CONFIG_REFERENCE_SYSTEM_PROPERTY_NAME);
+        if (remoteConfigRegistryConfigFilename != null) {
+            File remoteConfigRegistryConfigFile = new File(remoteConfigRegistryConfigFilename);
+            if (remoteConfigRegistryConfigFile.exists()) {
+                useReferencedFile = true;
+                // Parse the file, and build the registry config set
+                result.addAll(RemoteConfigurationRegistriesParser.getConfig(remoteConfigRegistryConfigFilename));
+            }
+        }
+
+        // If the system property was not set to a valid reference to another config file, then try to derive the
+        // registry configurations from the gateway config.
+        if (!useReferencedFile) {
+            RemoteConfigurationRegistries remoteConfigRegistries =
+                                                            new DefaultRemoteConfigurationRegistries(gatewayConfig);
+            result.addAll(remoteConfigRegistries.getRegistryConfigurations());
+        }
+
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesParser.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesParser.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesParser.java
new file mode 100644
index 0000000..f6347f8
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistriesParser.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.service.config.remote.config;
+
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+class RemoteConfigurationRegistriesParser {
+
+    static List<RemoteConfigurationRegistryConfig> getConfig(String configFilename) {
+        List<RemoteConfigurationRegistryConfig> result = new ArrayList<>();
+
+        File file = new File(configFilename);
+
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(RemoteConfigurationRegistries.class);
+            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
+            RemoteConfigurationRegistries parsedContent = (RemoteConfigurationRegistries) jaxbUnmarshaller.unmarshal(file);
+            if (parsedContent != null) {
+                result.addAll(parsedContent.getRegistryConfigurations());
+            }
+        } catch (JAXBException e) {
+            e.printStackTrace();
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistry.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistry.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistry.java
new file mode 100644
index 0000000..1fdbd9e
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/config/RemoteConfigurationRegistry.java
@@ -0,0 +1,139 @@
+/**
+ * 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.config;
+
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
+
+import javax.xml.bind.annotation.XmlElement;
+
+class RemoteConfigurationRegistry implements RemoteConfigurationRegistryConfig {
+
+    private String name;
+    private String type;
+    private String connectionString;
+    private String namespace;
+    private String authType;
+    private String principal;
+    private String credentialAlias;
+    private String keyTab;
+    private boolean useKeyTab;
+    private boolean useTicketCache;
+
+    RemoteConfigurationRegistry() {
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setRegistryType(String type) {
+        this.type = type;
+    }
+
+    public void setConnectionString(String connectionString) {
+        this.connectionString = connectionString;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    public void setAuthType(String authType) {
+        this.authType = authType;
+    }
+
+    public void setPrincipal(String principal) {
+        this.principal = principal;
+    }
+
+    public void setCredentialAlias(String alias) {
+        this.credentialAlias = alias;
+    }
+
+    public void setUseTicketCache(boolean useTicketCache) {
+        this.useTicketCache = useTicketCache;
+    }
+
+    public void setUseKeytab(boolean useKeytab) {
+        this.useKeyTab = useKeytab;
+    }
+
+    public void setKeytab(String keytab) {
+        this.keyTab = keytab;
+    }
+
+    @XmlElement(name="name")
+    public String getName() {
+        return name;
+    }
+
+    @XmlElement(name="type")
+    public String getRegistryType() {
+        return type;
+    }
+
+    @XmlElement(name="auth-type")
+    public String getAuthType() {
+        return authType;
+    }
+
+    @XmlElement(name="principal")
+    public String getPrincipal() {
+        return principal;
+    }
+
+    @XmlElement(name="credential-alias")
+    public String getCredentialAlias() {
+        return credentialAlias;
+    }
+
+    @Override
+    @XmlElement(name="address")
+    public String getConnectionString() {
+        return connectionString;
+    }
+
+    @Override
+    @XmlElement(name="namespace")
+    public String getNamespace() {
+        return namespace;
+    }
+
+    @Override
+    @XmlElement(name="use-ticket-cache")
+    public boolean isUseTicketCache() {
+        return useTicketCache;
+    }
+
+    @Override
+    @XmlElement(name="use-key-tab")
+    public boolean isUseKeyTab() {
+        return useKeyTab;
+    }
+
+    @Override
+    @XmlElement(name="keytab")
+    public String getKeytab() {
+        return keyTab;
+    }
+
+    @Override
+    public boolean isSecureRegistry() {
+        return (getAuthType() != null);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/CuratorClientService.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/CuratorClientService.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/CuratorClientService.java
new file mode 100644
index 0000000..b97a2c6
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/CuratorClientService.java
@@ -0,0 +1,464 @@
+/**
+ * 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.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.framework.recipes.cache.ChildData;
+import org.apache.curator.framework.recipes.cache.NodeCache;
+import org.apache.curator.framework.recipes.cache.NodeCacheListener;
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationMessages;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.EntryListener;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
+import org.apache.knox.gateway.service.config.remote.config.RemoteConfigurationRegistriesAccessor;
+import org.apache.knox.gateway.services.ServiceLifecycleException;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+import org.apache.zookeeper.data.Stat;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * RemoteConfigurationRegistryClientService implementation that employs the Curator ZooKeeper client framework.
+ */
+class CuratorClientService implements ZooKeeperClientService {
+
+    private static final String LOGIN_CONTEXT_NAME_PROPERTY = ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY;
+
+    private static final String DEFAULT_LOGIN_CONTEXT_NAME = "Client";
+
+    private static final RemoteConfigurationMessages log =
+                                                        MessagesFactory.get(RemoteConfigurationMessages.class);
+
+    private Map<String, RemoteConfigurationRegistryClient> clients = new HashMap<>();
+
+    private AliasService aliasService = null;
+
+
+    @Override
+    public void init(GatewayConfig config, Map<String, String> options) throws ServiceLifecycleException {
+
+        List<RemoteConfigurationRegistryConfig> registryConfigs = new ArrayList<>();
+
+        // Load the remote registry configurations
+        registryConfigs.addAll(RemoteConfigurationRegistriesAccessor.getRemoteRegistryConfigurations(config));
+
+        // Configure registry authentication
+        RemoteConfigurationRegistryJAASConfig.configure(registryConfigs, aliasService);
+
+        if (registryConfigs.size() > 1) {
+            // Warn about current limit on number of supported client configurations
+            log.multipleRemoteRegistryConfigurations();
+        }
+
+        // Create the clients
+        for (RemoteConfigurationRegistryConfig registryConfig : registryConfigs) {
+            if (TYPE.equalsIgnoreCase(registryConfig.getRegistryType())) {
+                RemoteConfigurationRegistryClient registryClient = createClient(registryConfig);
+                clients.put(registryConfig.getName(), registryClient);
+            }
+        }
+    }
+
+    @Override
+    public void setAliasService(AliasService aliasService) {
+        this.aliasService = aliasService;
+    }
+
+    @Override
+    public void start() throws ServiceLifecycleException {
+    }
+
+    @Override
+    public void stop() throws ServiceLifecycleException {
+    }
+
+    @Override
+    public RemoteConfigurationRegistryClient get(String name) {
+        return clients.get(name);
+    }
+
+
+    private RemoteConfigurationRegistryClient createClient(RemoteConfigurationRegistryConfig config) {
+        ACLProvider aclProvider;
+        if (config.isSecureRegistry()) {
+            configureSasl(config);
+            aclProvider = new SASLOwnerACLProvider();
+        } else {
+            // Clear SASL system property
+            System.clearProperty(LOGIN_CONTEXT_NAME_PROPERTY);
+            aclProvider = new DefaultACLProvider();
+        }
+
+        CuratorFramework client = CuratorFrameworkFactory.builder()
+                                                         .connectString(config.getConnectionString())
+                                                         .retryPolicy(new ExponentialBackoffRetry(1000, 3))
+                                                         .aclProvider(aclProvider)
+                                                         .build();
+        client.start();
+
+        return (new ClientAdapter(client, config));
+    }
+
+
+    private void configureSasl(RemoteConfigurationRegistryConfig config) {
+        String registryName = config.getName();
+        if (registryName == null) {
+            registryName = DEFAULT_LOGIN_CONTEXT_NAME;
+        }
+        System.setProperty(LOGIN_CONTEXT_NAME_PROPERTY, registryName);
+    }
+
+
+    private static final class ClientAdapter implements RemoteConfigurationRegistryClient {
+
+        private static final String DEFAULT_ENCODING = "UTF-8";
+
+        private CuratorFramework delegate;
+
+        private RemoteConfigurationRegistryConfig config;
+
+        private Map<String, NodeCache> entryNodeCaches = new HashMap<>();
+
+        ClientAdapter(CuratorFramework delegate, RemoteConfigurationRegistryConfig config) {
+            this.delegate = delegate;
+            this.config = config;
+        }
+
+        @Override
+        public String getAddress() {
+            return config.getConnectionString();
+        }
+
+        @Override
+        public boolean isAuthenticationConfigured() {
+            return config.isSecureRegistry();
+        }
+
+        @Override
+        public boolean entryExists(String path) {
+            Stat s = null;
+            try {
+                s = delegate.checkExists().forPath(path);
+            } catch (Exception e) {
+                // Ignore
+            }
+            return (s != null);
+        }
+
+        @Override
+        public List<RemoteConfigurationRegistryClient.EntryACL> getACL(String path) {
+            List<RemoteConfigurationRegistryClient.EntryACL> acl = new ArrayList<>();
+            try {
+                List<ACL> zkACL = delegate.getACL().forPath(path);
+                if (zkACL != null) {
+                    for (ACL aclEntry : zkACL) {
+                        RemoteConfigurationRegistryClient.EntryACL entryACL = new ZooKeeperACLAdapter(aclEntry);
+                        acl.add(entryACL);
+                    }
+                }
+            } catch (Exception e) {
+                log.errorHandlingRemoteConfigACL(path, e);
+            }
+            return acl;
+        }
+
+        @Override
+        public void setACL(String path, List<EntryACL> entryACLs) {
+            // Translate the abstract ACLs into ZooKeeper ACLs
+            List<ACL> delegateACLs = new ArrayList<>();
+            for (EntryACL entryACL : entryACLs) {
+                String scheme = entryACL.getType();
+                String id = entryACL.getId();
+                int permissions = 0;
+                if (entryACL.canWrite()) {
+                    permissions = ZooDefs.Perms.ALL;
+                } else if (entryACL.canRead()){
+                    permissions = ZooDefs.Perms.READ;
+                }
+                delegateACLs.add(new ACL(permissions, new Id(scheme, id)));
+            }
+
+            try {
+                // Set the ACLs for the path
+                delegate.setACL().withACL(delegateACLs).forPath(path);
+            } catch (Exception e) {
+                log.errorSettingEntryACL(path, e);
+            }
+        }
+
+        @Override
+        public List<String> listChildEntries(String path) {
+            List<String> result = null;
+            try {
+                result = delegate.getChildren().forPath(path);
+            } catch (Exception e) {
+                log.errorInteractingWithRemoteConfigRegistry(e);
+            }
+            return result;
+        }
+
+        @Override
+        public void addChildEntryListener(String path, ChildEntryListener listener) throws Exception {
+            PathChildrenCache childCache = new PathChildrenCache(delegate, path, false);
+            childCache.getListenable().addListener(new ChildEntryListenerAdapter(this, listener));
+            childCache.start();
+        }
+
+        @Override
+        public void addEntryListener(String path, EntryListener listener) throws Exception {
+            NodeCache nodeCache = new NodeCache(delegate, path);
+            nodeCache.getListenable().addListener(new EntryListenerAdapter(this, nodeCache, listener));
+            nodeCache.start();
+            entryNodeCaches.put(path, nodeCache);
+        }
+
+        @Override
+        public void removeEntryListener(String path) throws Exception {
+            NodeCache nodeCache = entryNodeCaches.remove(path);
+            if (nodeCache != null) {
+                nodeCache.close();
+            }
+        }
+
+        @Override
+        public String getEntryData(String path) {
+            return getEntryData(path, DEFAULT_ENCODING);
+        }
+
+        @Override
+        public String getEntryData(String path, String encoding) {
+            String result = null;
+            try {
+                byte[] data = delegate.getData().forPath(path);
+                if (data != null) {
+                    result = new String(data, Charset.forName(encoding));
+                }
+            } catch (Exception e) {
+                log.errorInteractingWithRemoteConfigRegistry(e);
+            }
+            return result;
+        }
+
+        @Override
+        public void createEntry(String path) {
+            try {
+                if (delegate.checkExists().forPath(path) == null) {
+                    delegate.create().forPath(path);
+                }
+            } catch (Exception e) {
+                log.errorInteractingWithRemoteConfigRegistry(e);
+            }
+        }
+
+        @Override
+        public void createEntry(String path, String data) {
+            createEntry(path, data, DEFAULT_ENCODING);
+        }
+
+        @Override
+        public void createEntry(String path, String data, String encoding) {
+            try {
+                createEntry(path);
+                setEntryData(path, data, encoding);
+            } catch (Exception e) {
+                log.errorInteractingWithRemoteConfigRegistry(e);
+            }
+        }
+
+        @Override
+        public int setEntryData(String path, String data) {
+            return setEntryData(path, data, DEFAULT_ENCODING);
+        }
+
+        @Override
+        public int setEntryData(String path, String data, String encoding) {
+            int version = 0;
+            try {
+                Stat s = delegate.setData().forPath(path, data.getBytes(Charset.forName(encoding)));
+                if (s != null) {
+                    version = s.getVersion();
+                }
+            } catch (Exception e) {
+                log.errorInteractingWithRemoteConfigRegistry(e);
+            }
+            return version;
+        }
+
+        @Override
+        public void deleteEntry(String path) {
+            try {
+                delegate.delete().forPath(path);
+            } catch (Exception e) {
+                log.errorInteractingWithRemoteConfigRegistry(e);
+            }
+        }
+    }
+
+    /**
+     * SASL ACLProvider
+     */
+    private static class SASLOwnerACLProvider implements ACLProvider {
+
+        private final List<ACL> saslACL;
+
+        private SASLOwnerACLProvider() {
+            this.saslACL = ZooDefs.Ids.CREATOR_ALL_ACL; // All permissions for any authenticated user
+        }
+
+        @Override
+        public List<ACL> getDefaultAcl() {
+            return saslACL;
+        }
+
+        @Override
+        public List<ACL> getAclForPath(String path) {
+            return getDefaultAcl();
+        }
+    }
+
+
+    private static final class ChildEntryListenerAdapter implements PathChildrenCacheListener {
+
+        private RemoteConfigurationRegistryClient client;
+        private ChildEntryListener delegate;
+
+        ChildEntryListenerAdapter(RemoteConfigurationRegistryClient client, ChildEntryListener delegate) {
+            this.client = client;
+            this.delegate = delegate;
+        }
+
+        @Override
+        public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent)
+                throws Exception {
+            ChildData childData = pathChildrenCacheEvent.getData();
+            if (childData != null) {
+                ChildEntryListener.Type eventType = adaptType(pathChildrenCacheEvent.getType());
+                if (eventType != null) {
+                    delegate.childEvent(client, eventType, childData.getPath());
+                }
+            }
+        }
+
+        private ChildEntryListener.Type adaptType(PathChildrenCacheEvent.Type type) {
+            ChildEntryListener.Type adapted = null;
+
+            switch(type) {
+                case CHILD_ADDED:
+                    adapted = ChildEntryListener.Type.ADDED;
+                    break;
+                case CHILD_REMOVED:
+                    adapted = ChildEntryListener.Type.REMOVED;
+                    break;
+                case CHILD_UPDATED:
+                    adapted = ChildEntryListener.Type.UPDATED;
+                    break;
+            }
+
+            return adapted;
+        }
+    }
+
+    private static final class EntryListenerAdapter implements NodeCacheListener {
+
+        private RemoteConfigurationRegistryClient client;
+        private EntryListener delegate;
+        private NodeCache nodeCache;
+
+        EntryListenerAdapter(RemoteConfigurationRegistryClient client, NodeCache nodeCache, EntryListener delegate) {
+            this.client = client;
+            this.nodeCache = nodeCache;
+            this.delegate = delegate;
+        }
+
+        @Override
+        public void nodeChanged() throws Exception {
+            String path = null;
+            byte[] data = null;
+
+            ChildData cd = nodeCache.getCurrentData();
+            if (cd != null) {
+                path = cd.getPath();
+                data = cd.getData();
+            }
+
+            if (path != null) {
+                delegate.entryChanged(client, path, data);
+            }
+        }
+    }
+
+    /**
+     * ACL adapter
+     */
+    private static final class ZooKeeperACLAdapter implements RemoteConfigurationRegistryClient.EntryACL {
+        private String type;
+        private String id;
+        private int permissions;
+
+        ZooKeeperACLAdapter(ACL acl) {
+            this.permissions = acl.getPerms();
+            this.type = acl.getId().getScheme();
+            this.id = acl.getId().getId();
+        }
+
+        @Override
+        public String getId() {
+            return id;
+        }
+
+        @Override
+        public String getType() {
+            return type;
+        }
+
+        @Override
+        public Object getPermissions() {
+            return permissions;
+        }
+
+        @Override
+        public boolean canRead() {
+            return (permissions >= ZooDefs.Perms.READ);
+        }
+
+        @Override
+        public boolean canWrite() {
+            return (permissions >= ZooDefs.Perms.WRITE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java
new file mode 100644
index 0000000..f75634b
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/RemoteConfigurationRegistryJAASConfig.java
@@ -0,0 +1,179 @@
+/**
+ * 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.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationMessages;
+import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.AliasServiceException;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Configuration decorator that adds SASL JAAS configuration to whatever JAAS config is already applied.
+ */
+class RemoteConfigurationRegistryJAASConfig extends Configuration {
+
+    // Underlying SASL mechanisms supported
+    enum SASLMechanism {
+        Unsupported,
+        Kerberos,
+        Digest
+    }
+
+    static final Map<String, String> digestLoginModules = new HashMap<>();
+    static {
+        digestLoginModules.put("ZOOKEEPER", "org.apache.zookeeper.server.auth.DigestLoginModule");
+    }
+
+    private static final RemoteConfigurationMessages log = MessagesFactory.get(RemoteConfigurationMessages.class);
+
+    // Cache the current JAAS configuration
+    private Configuration delegate = Configuration.getConfiguration();
+
+    private AliasService aliasService;
+
+    private Map<String, AppConfigurationEntry[]> contextEntries =  new HashMap<>();
+
+    static RemoteConfigurationRegistryJAASConfig configure(List<RemoteConfigurationRegistryConfig> configs, AliasService aliasService) {
+        return new RemoteConfigurationRegistryJAASConfig(configs, aliasService);
+    }
+
+    private RemoteConfigurationRegistryJAASConfig(List<RemoteConfigurationRegistryConfig> configs, AliasService aliasService) {
+        this.aliasService = aliasService;
+
+        // Populate context entries
+        List<AppConfigurationEntry> appConfigEntries = new ArrayList<>();
+        for (RemoteConfigurationRegistryConfig config : configs) {
+            if (config.isSecureRegistry()) {
+                contextEntries.put(config.getName(), createEntries(config));
+            }
+        }
+
+        // If there is at least one context entry, then set this as the client configuration
+        if (!contextEntries.isEmpty()) {
+            // TODO: PJZ: ZooKeeper 3.6.0 will have per-client JAAS Configuration support; Upgrade ASAP!!
+            // For now, set this as the static JAAS configuration
+            Configuration.setConfiguration(this);
+        }
+    }
+
+    @Override
+    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+        AppConfigurationEntry[] result = null;
+
+        // First, try the delegate's context entries
+        result = delegate.getAppConfigurationEntry(name);
+        if (result == null || result.length < 1) {
+            // Try our additional context entries
+            result = contextEntries.get(name);
+        }
+
+        return result;
+    }
+
+    private AppConfigurationEntry[] createEntries(RemoteConfigurationRegistryConfig config) {
+        AppConfigurationEntry[] result = null;
+
+        AppConfigurationEntry entry = createEntry(config);
+        if (entry != null) {
+            // Only supporting a single app config entry per configuration/context
+            result = new AppConfigurationEntry[1];
+            result[0] = createEntry(config);
+        } else {
+            result = new AppConfigurationEntry[0];
+        }
+        return result;
+    }
+
+    private AppConfigurationEntry createEntry(RemoteConfigurationRegistryConfig config) {
+        AppConfigurationEntry entry = null;
+
+        Map<String, String> opts = new HashMap<>();
+        SASLMechanism saslMechanism = getSASLMechanism(config.getAuthType());
+        switch (saslMechanism) {
+            case Digest:
+                // Digest auth options
+                opts.put("username", config.getPrincipal());
+
+                char[] credential = null;
+                if (aliasService != null) {
+                    try {
+                        credential = aliasService.getPasswordFromAliasForGateway(config.getCredentialAlias());
+                    } catch (AliasServiceException e) {
+                        log.unresolvedCredentialAlias(config.getCredentialAlias());
+                    }
+                } else {
+                    throw new IllegalArgumentException("The AliasService is required to resolve credential aliases.");
+                }
+
+                if (credential != null) {
+                    opts.put("password", new String(credential));
+                }
+                break;
+            case Kerberos:
+                opts.put("isUseTicketCache", String.valueOf(config.isUseTicketCache()));
+                opts.put("isUseKeyTab", String.valueOf(config.isUseKeyTab()));
+                opts.put("keyTab", config.getKeytab());
+                opts.put("principal", config.getPrincipal());
+        }
+
+        if (!opts.isEmpty()) {
+            entry = new AppConfigurationEntry(getLoginModuleName(config.getRegistryType(), saslMechanism),
+                                              AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                                              opts);
+        }
+
+        return entry;
+    }
+
+    private static String getLoginModuleName(String registryType, SASLMechanism saslMechanism) {
+        String loginModuleName = null;
+
+        switch (saslMechanism) {
+            case Kerberos:
+                if (System.getProperty("java.vendor").contains("IBM")) {
+                    loginModuleName = "com.ibm.security.auth.module.Krb5LoginModule";
+                } else {
+                    loginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
+                }
+                break;
+            case Digest:
+                loginModuleName = digestLoginModules.get(registryType.toUpperCase());
+        }
+        return loginModuleName;
+    }
+
+    private static SASLMechanism getSASLMechanism(String authType) {
+        SASLMechanism result = SASLMechanism.Unsupported;
+        for (SASLMechanism at : SASLMechanism.values()) {
+            if (at.name().equalsIgnoreCase(authType)) {
+                result = at;
+                break;
+            }
+        }
+        return result;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/ZooKeeperClientService.java
----------------------------------------------------------------------
diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/ZooKeeperClientService.java b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/ZooKeeperClientService.java
new file mode 100644
index 0000000..17c93e0
--- /dev/null
+++ b/gateway-service-remoteconfig/src/main/java/org/apache/knox/gateway/service/config/remote/zk/ZooKeeperClientService.java
@@ -0,0 +1,25 @@
+/**
+ * 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.services.config.client.RemoteConfigurationRegistryClientService;
+
+public interface ZooKeeperClientService extends RemoteConfigurationRegistryClientService {
+
+    String TYPE = "ZooKeeper";
+
+}