You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by lm...@apache.org on 2019/03/02 16:19:39 UTC

[knox] branch master updated: KNOX-1789 - Refactor RemoteAliasService to use service loading (#59)

This is an automated email from the ASF dual-hosted git repository.

lmccay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new df120a7  KNOX-1789 - Refactor RemoteAliasService to use service loading (#59)
df120a7 is described below

commit df120a701f2fbba6324528c7e5a2817e7a02e0da
Author: Kevin Risden <ri...@users.noreply.github.com>
AuthorDate: Sat Mar 2 10:19:34 2019 -0600

    KNOX-1789 - Refactor RemoteAliasService to use service loading (#59)
    
    Signed-off-by: Kevin Risden <kr...@apache.org>
---
 .../gateway/config/impl/GatewayConfigImpl.java     |  16 +-
 .../knox/gateway/services/CLIGatewayServices.java  |  51 +-
 .../gateway/services/DefaultGatewayServices.java   |  40 +-
 .../services/security/impl/RemoteAliasService.java | 556 +++------------------
 ...rvice.java => ZookeeperRemoteAliasService.java} | 395 ++++-----------
 .../impl/ZookeeperRemoteAliasServiceProvider.java  |  36 ++
 ...nox.gateway.security.RemoteAliasServiceProvider |  19 +
 .../security/impl/RemoteAliasServiceTest.java      | 337 +++++++++++++
 .../impl/RemoteAliasServiceTestProvider.java       | 135 +++++
 .../impl/ZookeeperRemoteAliasMonitorTest.java}     |  85 ++--
 .../impl/ZookeeperRemoteAliasServiceTest.java}     |  39 +-
 ...nox.gateway.security.RemoteAliasServiceProvider |  19 +
 .../apache/knox/gateway/config/GatewayConfig.java  |  14 +
 .../security/RemoteAliasServiceProvider.java       |  26 +
 .../org/apache/knox/gateway/GatewayTestConfig.java |  10 +
 15 files changed, 869 insertions(+), 909 deletions(-)

diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index cedf6cf..f68b536 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -228,6 +228,9 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
   static final String DISPATCH_HOST_WHITELIST          = GATEWAY_CONFIG_FILE_PREFIX + ".dispatch.whitelist";
   static final String DISPATCH_HOST_WHITELIST_SERVICES = DISPATCH_HOST_WHITELIST + ".services";
 
+  static final String REMOTE_ALIAS_SERVICE_CONFIG_PREFIX = GATEWAY_CONFIG_FILE_PREFIX + ".remote.alias.service.config.prefix";
+  static final String REMOTE_ALIAS_SERVICE_CONFIG_PREFIX_DEFAULT = GATEWAY_CONFIG_FILE_PREFIX + ".remote.alias.service.config";
+
   private static final List<String> DEFAULT_GLOBAL_RULES_SERVICES = Arrays.asList(
       "NAMENODE", "JOBTRACKER", "WEBHDFS", "WEBHCAT",
       "OOZIE", "WEBHBASE", "HIVE", "RESOURCEMANAGER");
@@ -942,8 +945,17 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
 
   @Override
   public boolean isRemoteAliasServiceEnabled() {
-    final String result = get( REMOTE_ALIAS_SERVICE_ENABLED, Boolean.toString(DEFAULT_REMOTE_ALIAS_SERVICE_ENABLED));
-    return Boolean.parseBoolean(result);
+    return getBoolean( REMOTE_ALIAS_SERVICE_ENABLED, DEFAULT_REMOTE_ALIAS_SERVICE_ENABLED);
+  }
+
+  @Override
+  public String getRemoteAliasServiceConfigurationPrefix() {
+    return get(REMOTE_ALIAS_SERVICE_CONFIG_PREFIX, REMOTE_ALIAS_SERVICE_CONFIG_PREFIX_DEFAULT);
+  }
+
+  @Override
+  public Map<String, String> getRemoteAliasServiceConfiguration() {
+    return getPropsWithPrefix(getRemoteAliasServiceConfigurationPrefix());
   }
 
   @Override
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java
index f889760..fea6ddc 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java
@@ -38,30 +38,14 @@ import java.util.Map;
 
 public class CLIGatewayServices implements GatewayServices {
   private Map<String,Service> services = new HashMap<>();
-  private CLIMasterService ms;
-  private DefaultKeystoreService ks;
-
-  public CLIGatewayServices() {
-    super();
-  }
 
   @Override
   public void init(GatewayConfig config, Map<String,String> options) throws ServiceLifecycleException {
-
-    /* create an instance so that it can be passed to other services */
-    final RemoteAliasService alias = new RemoteAliasService();
-
-    final RemoteConfigurationRegistryClientService registryClientService =
-        RemoteConfigurationRegistryClientServiceFactory.newInstance(config);
-    registryClientService.setAliasService(alias);
-    registryClientService.init(config, options);
-    services.put(REMOTE_REGISTRY_CLIENT_SERVICE, registryClientService);
-
-    ms = new CLIMasterService();
+    CLIMasterService ms = new CLIMasterService();
     ms.init(config, options);
     services.put(MASTER_SERVICE, ms);
 
-    ks = new DefaultKeystoreService();
+    DefaultKeystoreService ks = new DefaultKeystoreService();
     ks.setMasterService(ms);
     ks.init(config, options);
     services.put(KEYSTORE_SERVICE, ks);
@@ -71,15 +55,26 @@ public class CLIGatewayServices implements GatewayServices {
     defaultAlias.init(config, options);
 
     /*
+    Doesn't make sense for this to be set to the remote alias service since the impl could
+    be remote itself. This uses the default alias service in case of ZK digest authentication.
+    IE: If ZK digest auth and using ZK remote alias service, then wouldn't be able to connect
+    to ZK anyway due to the circular dependency.
+     */
+    final RemoteConfigurationRegistryClientService registryClientService =
+        RemoteConfigurationRegistryClientServiceFactory.newInstance(config);
+    registryClientService.setAliasService(defaultAlias);
+    registryClientService.init(config, options);
+    services.put(REMOTE_REGISTRY_CLIENT_SERVICE, registryClientService);
+
+
+    /* create an instance so that it can be passed to other services */
+    final RemoteAliasService alias = new RemoteAliasService(defaultAlias, ms);
+    /*
      * Setup and initialize remote Alias Service.
      * NOTE: registryClientService.init() needs to
      * be called before alias.start();
      */
-    alias.setLocalAliasService(defaultAlias);
-    alias.setMasterService(ms);
-    alias.setRegistryClientService(registryClientService);
     alias.init(config, options);
-    alias.start();
     services.put(ALIAS_SERVICE, alias);
 
     DefaultCryptoService crypto = new DefaultCryptoService();
@@ -95,14 +90,16 @@ public class CLIGatewayServices implements GatewayServices {
 
   @Override
   public void start() throws ServiceLifecycleException {
+    Service ms = services.get(MASTER_SERVICE);
     ms.start();
 
+    Service ks = services.get(KEYSTORE_SERVICE);
     ks.start();
 
-    DefaultAliasService alias = (DefaultAliasService) services.get(ALIAS_SERVICE);
+    Service alias = services.get(ALIAS_SERVICE);
     alias.start();
 
-    DefaultTopologyService tops = (DefaultTopologyService)services.get(TOPOLOGY_SERVICE);
+    Service tops = services.get(TOPOLOGY_SERVICE);
     tops.start();
 
     (services.get(REMOTE_REGISTRY_CLIENT_SERVICE)).start();
@@ -110,14 +107,16 @@ public class CLIGatewayServices implements GatewayServices {
 
   @Override
   public void stop() throws ServiceLifecycleException {
+    Service ms = services.get(MASTER_SERVICE);
     ms.stop();
 
+    Service ks = services.get(KEYSTORE_SERVICE);
     ks.stop();
 
-    DefaultAliasService alias = (DefaultAliasService) services.get(ALIAS_SERVICE);
+    Service alias = services.get(ALIAS_SERVICE);
     alias.stop();
 
-    DefaultTopologyService tops = (DefaultTopologyService)services.get(TOPOLOGY_SERVICE);
+    Service tops = services.get(TOPOLOGY_SERVICE);
     tops.stop();
   }
 
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java
index 1c9204e..9bd669a 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java
@@ -27,6 +27,7 @@ import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistry
 import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
 import org.apache.knox.gateway.services.registry.impl.DefaultServiceDefinitionRegistry;
 import org.apache.knox.gateway.services.metrics.impl.DefaultMetricsService;
+import org.apache.knox.gateway.services.security.KeystoreService;
 import org.apache.knox.gateway.services.security.impl.RemoteAliasService;
 import org.apache.knox.gateway.services.topology.impl.DefaultClusterConfigurationMonitorService;
 import org.apache.knox.gateway.services.topology.impl.DefaultTopologyService;
@@ -48,50 +49,46 @@ import java.util.List;
 import java.util.Map;
 
 public class DefaultGatewayServices implements GatewayServices {
-
   private static GatewayMessages log = MessagesFactory.get( GatewayMessages.class );
 
   private Map<String,Service> services = new HashMap<>();
-  private DefaultMasterService ms;
-  private DefaultKeystoreService ks;
-
-  public DefaultGatewayServices() {
-    super();
-  }
 
   @Override
   public void init(GatewayConfig config, Map<String,String> options) throws ServiceLifecycleException {
-    ms = new DefaultMasterService();
+    DefaultMasterService ms = new DefaultMasterService();
     ms.init(config, options);
     services.put(MASTER_SERVICE, ms);
 
-    ks = new DefaultKeystoreService();
+    DefaultKeystoreService ks = new DefaultKeystoreService();
     ks.setMasterService(ms);
     ks.init(config, options);
     services.put(KEYSTORE_SERVICE, ks);
 
-    /* create an instance so that it can be passed to other services */
-    final RemoteAliasService alias = new RemoteAliasService();
+    final DefaultAliasService defaultAlias = new DefaultAliasService();
+    defaultAlias.setKeystoreService(ks);
+    defaultAlias.setMasterService(ms);
+    defaultAlias.init(config, options);
 
+    /*
+    Doesn't make sense for this to be set to the remote alias service since the impl could
+    be remote itself. This uses the default alias service in case of ZK digest authentication.
+    IE: If ZK digest auth and using ZK remote alias service, then wouldn't be able to connect
+    to ZK anyway due to the circular dependency.
+     */
     final RemoteConfigurationRegistryClientService registryClientService =
         RemoteConfigurationRegistryClientServiceFactory.newInstance(config);
-    registryClientService.setAliasService(alias);
+    registryClientService.setAliasService(defaultAlias);
     registryClientService.init(config, options);
     services.put(REMOTE_REGISTRY_CLIENT_SERVICE, registryClientService);
 
-    final DefaultAliasService defaultAlias = new DefaultAliasService();
-    defaultAlias.setKeystoreService(ks);
-    defaultAlias.setMasterService(ms);
-    defaultAlias.init(config, options);
 
+    /* create an instance so that it can be passed to other services */
+    final RemoteAliasService alias = new RemoteAliasService(defaultAlias, ms);
     /*
      * Setup and initialize remote Alias Service.
      * NOTE: registryClientService.init() needs to
      * be called before alias.start();
      */
-    alias.setLocalAliasService(defaultAlias);
-    alias.setMasterService(ms);
-    alias.setRegistryClientService(registryClientService);
     alias.init(config, options);
     services.put(ALIAS_SERVICE, alias);
 
@@ -152,8 +149,10 @@ public class DefaultGatewayServices implements GatewayServices {
 
   @Override
   public void start() throws ServiceLifecycleException {
+    Service ms = services.get(MASTER_SERVICE);
     ms.start();
 
+    Service ks = services.get(KEYSTORE_SERVICE);
     ks.start();
 
     Service alias = services.get(ALIAS_SERVICE);
@@ -182,8 +181,10 @@ public class DefaultGatewayServices implements GatewayServices {
 
   @Override
   public void stop() throws ServiceLifecycleException {
+    Service ms = services.get(MASTER_SERVICE);
     ms.stop();
 
+    Service ks = services.get(KEYSTORE_SERVICE);
     ks.stop();
 
     (services.get(CLUSTER_CONFIGURATION_MONITOR_SERVICE)).stop();
@@ -231,6 +232,7 @@ public class DefaultGatewayServices implements GatewayServices {
     // setup credential store as appropriate
     String clusterName = context.getTopology().getName();
     try {
+      KeystoreService ks = getService(KEYSTORE_SERVICE);
       if (!ks.isCredentialStoreForClusterAvailable(clusterName)) {
         log.creatingCredentialStoreForCluster(clusterName);
         ks.createCredentialStoreForCluster(clusterName);
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
index bf41432..0509d45 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
@@ -17,34 +17,25 @@
  */
 package org.apache.knox.gateway.services.security.impl;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.knox.gateway.GatewayMessages;
-import org.apache.knox.gateway.GatewayServer;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
-import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.security.RemoteAliasServiceProvider;
 import org.apache.knox.gateway.services.ServiceLifecycleException;
-import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
-import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.AliasServiceException;
-import org.apache.knox.gateway.services.security.EncryptionResult;
 import org.apache.knox.gateway.services.security.MasterService;
 import org.apache.knox.gateway.util.PasswordUtils;
-import org.apache.zookeeper.ZooDefs;
 
-import java.nio.charset.StandardCharsets;
 import java.security.cert.Certificate;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.ServiceLoader;
 
 /**
- * An {@link AliasService} implementation based on
- * remote service registry.
+ * An {@link AliasService} implementation based on remote service registry.
  * <p>
  * This class encapsulates the default AliasService implementation which uses
  * local keystore to store the aliases. The order in which Aliases are stored are
@@ -56,154 +47,20 @@ import java.util.Map;
  * @since 1.1.0
  */
 public class RemoteAliasService implements AliasService {
-
-  public static final String PATH_KNOX = "/knox";
-  public static final String PATH_KNOX_SECURITY = PATH_KNOX + "/security";
-  public static final String PATH_KNOX_ALIAS_STORE_TOPOLOGY =
-      PATH_KNOX_SECURITY + "/topology";
-  public static final String PATH_SEPARATOR = "/";
   public static final String DEFAULT_CLUSTER_NAME = "__gateway";
+  public static final String REMOTE_ALIAS_SERVICE_TYPE = "type";
 
   private static final GatewayMessages LOG = MessagesFactory.get(GatewayMessages.class);
-  // N.B. This is ZooKeeper-specific, and should be abstracted when another registry is supported
-  private static final RemoteConfigurationRegistryClient.EntryACL AUTHENTICATED_USERS_ALL;
-
-  static {
-    AUTHENTICATED_USERS_ALL = new RemoteConfigurationRegistryClient.EntryACL() {
-      @Override
-      public String getId() {
-        return "";
-      }
-
-      @Override
-      public String getType() {
-        return "auth";
-      }
 
-      @Override
-      public Object getPermissions() {
-        return ZooDefs.Perms.ALL;
-      }
+  private final AliasService localAliasService;
+  private final MasterService ms;
 
-      @Override
-      public boolean canRead() {
-        return true;
-      }
-
-      @Override
-      public boolean canWrite() {
-        return true;
-      }
-    };
-  }
-
-  private RemoteConfigurationRegistryClient remoteClient;
-  private ConfigurableEncryptor encryptor;
-  /**
-   * Default alias service
-   */
-  private AliasService localAliasService;
-  private RemoteConfigurationRegistryClientService registryClientService;
-  private MasterService ms;
+  private AliasService remoteAliasServiceImpl;
   private GatewayConfig config;
 
-  /* create an instance */
-  public RemoteAliasService() {
-    super();
-  }
-
-  /**
-   * Build an entry path for the given cluster and alias
-   */
-  private static String buildAliasEntryName(final String clusterName,
-      final String alias) {
-    return buildClusterEntryName(clusterName) + PATH_SEPARATOR + alias;
-  }
-
-  /**
-   * Build an entry path for the given cluster
-   */
-  private static String buildClusterEntryName(final String clusterName) {
-    return PATH_KNOX_ALIAS_STORE_TOPOLOGY + PATH_SEPARATOR + clusterName;
-  }
-
-  /**
-   * Ensure that the given entry path exists.
-   */
-  private static void ensureEntry(final String path,
-      final RemoteConfigurationRegistryClient remoteClient) {
-    if (!remoteClient.entryExists(path)) {
-      remoteClient.createEntry(path);
-    } else {
-      // Validate the ACL
-      List<RemoteConfigurationRegistryClient.EntryACL> entryACLs = remoteClient
-          .getACL(path);
-      for (RemoteConfigurationRegistryClient.EntryACL entryACL : entryACLs) {
-        // N.B. This is ZooKeeper-specific, and should be abstracted when another registry is supported
-        // For now, check for world:anyone with ANY permissions (even read-only)
-        if (entryACL.getType().equals("world") && entryACL.getId()
-            .equals("anyone")) {
-          LOG.suspectWritableRemoteConfigurationEntry(path);
-
-          // If the client is authenticated, but "anyone" can write the content, then the content may not
-          // be trustworthy.
-          if (remoteClient.isAuthenticationConfigured()) {
-            LOG.correctingSuspectWritableRemoteConfigurationEntry(path);
-
-            // Replace the existing ACL with one that permits only authenticated users
-            remoteClient.setACL(path,
-                Collections.singletonList(AUTHENTICATED_USERS_ALL));
-          }
-        }
-      }
-    }
-  }
-
-  /**
-   * Check to make sure all the required entries are properly set up
-   */
-  private static void checkPathsExist(
-      final RemoteConfigurationRegistryClient remoteClient) {
-    ensureEntry(PATH_KNOX, remoteClient);
-    ensureEntry(PATH_KNOX_SECURITY, remoteClient);
-    ensureEntry(PATH_KNOX_ALIAS_STORE_TOPOLOGY, remoteClient);
-    ensureEntry(
-        PATH_KNOX_ALIAS_STORE_TOPOLOGY + PATH_SEPARATOR + DEFAULT_CLUSTER_NAME,
-        remoteClient);
-  }
-
-  /**
-   * Returns an empty list if the given list is null,
-   * else returns the given list.
-   */
-  private static List<String> safe(final List<String> given) {
-    return given == null ? Collections.EMPTY_LIST : given;
-  }
-
-  /**
-   * Set a {@link RemoteConfigurationRegistryClientService} instance
-   * used to talk to remote remote service registry.
-   * @param registryClientService registryClientService to set
-   */
-  public void setRegistryClientService(
-      final RemoteConfigurationRegistryClientService registryClientService) {
-    this.registryClientService = registryClientService;
-  }
-
-  /**
-   * Set a {@link MasterService} instance.
-   * @param ms master service to set
-   */
-  public void setMasterService(final MasterService ms) {
-    this.ms = ms;
-  }
-
-  /**
-   * Set local alias service
-   * @param localAliasService local alias service to set
-   */
-  public void setLocalAliasService(AliasService localAliasService) {
+  public RemoteAliasService(AliasService localAliasService, MasterService ms) {
     this.localAliasService = localAliasService;
+    this.ms = ms;
   }
 
   /**
@@ -214,24 +71,22 @@ public class RemoteAliasService implements AliasService {
    * @return List of all the aliases
    */
   @Override
-  public List<String> getAliasesForCluster(final String clusterName)
-      throws AliasServiceException {
-
+  public List<String> getAliasesForCluster(final String clusterName) throws AliasServiceException {
     List<String> remoteAliases = new ArrayList<>();
 
     /* If we have remote registry configured, query it */
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-      remoteAliases = remoteClient
-          .listChildEntries(buildClusterEntryName(clusterName));
+    if (remoteAliasServiceImpl != null) {
+      remoteAliases = remoteAliasServiceImpl.getAliasesForCluster(clusterName);
     }
 
     List<String> localAliases = localAliasService
         .getAliasesForCluster(clusterName);
 
-    /* merge */
-    for (final String alias : safe(localAliases)) {
-      if (!remoteAliases.contains(alias.toLowerCase(Locale.ROOT))) {
-        remoteAliases.add(alias);
+    if(localAliases != null) {
+      for (final String alias : localAliases) {
+        if (!remoteAliases.contains(alias.toLowerCase(Locale.ROOT))) {
+          remoteAliases.add(alias);
+        }
       }
     }
 
@@ -249,31 +104,14 @@ public class RemoteAliasService implements AliasService {
     /* first add the alias to the local keystore */
     localAliasService.addAliasForCluster(clusterName, alias, value);
 
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-
-      final String aliasEntryPath = buildAliasEntryName(clusterName, alias);
-
-      /* Ensure the entries are properly set up */
-      checkPathsExist(remoteClient);
-      ensureEntry(buildClusterEntryName(clusterName), remoteClient);
-      try {
-        remoteClient.createEntry(aliasEntryPath, encrypt(value));
-      } catch (Exception e) {
-        throw new AliasServiceException(e);
-      }
-
-      if (remoteClient.getEntryData(aliasEntryPath) == null) {
-        throw new IllegalStateException(String.format(Locale.ROOT,
-            "Failed to store alias %s for cluster %s in remote registry", alias,
-            clusterName));
-      }
+    if (remoteAliasServiceImpl != null) {
+      remoteAliasServiceImpl.addAliasForCluster(clusterName, alias, value);
     }
   }
 
   @Override
-  public void removeAliasForCluster(final String clusterName,
-      final String givenAlias) throws AliasServiceException {
-
+  public void removeAliasForCluster(final String clusterName, final String givenAlias)
+      throws AliasServiceException {
     /* convert all alias names to lower case since JDK expects the same behaviour */
     final String alias = givenAlias.toLowerCase(Locale.ROOT);
 
@@ -281,21 +119,8 @@ public class RemoteAliasService implements AliasService {
     localAliasService.removeAliasForCluster(clusterName, alias);
 
     /* If we have remote registry configured, query it */
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-
-      final String aliasEntryPath = buildAliasEntryName(clusterName, alias);
-
-      if (remoteClient.entryExists(aliasEntryPath)) {
-        remoteClient.deleteEntry(aliasEntryPath);
-
-        if (remoteClient.entryExists(aliasEntryPath)) {
-          throw new IllegalStateException(String.format(Locale.ROOT,
-              "Failed to delete alias %s for cluster %s in remote registry",
-              alias, clusterName));
-        }
-      }
-    } else {
-      LOG.missingClientConfigurationForRemoteMonitoring();
+    if (remoteAliasServiceImpl != null) {
+      remoteAliasServiceImpl.removeAliasForCluster(clusterName, alias);
     }
   }
 
@@ -308,39 +133,19 @@ public class RemoteAliasService implements AliasService {
   @Override
   public char[] getPasswordFromAliasForCluster(String clusterName,
       String givenAlias, boolean generate) throws AliasServiceException {
-
     /* convert all alias names to lower case since JDK expects the same behaviour */
     final String alias = givenAlias.toLowerCase(Locale.ROOT);
 
+    /* Generate a new password  */
+    if (generate) {
+      generateAliasForCluster(clusterName, alias);
+    }
+
     char[] password = null;
 
     /* try to get it from remote registry */
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-
-      checkPathsExist(remoteClient);
-      String encrypted = null;
-
-      if(remoteClient.entryExists(buildAliasEntryName(clusterName, alias))) {
-        encrypted = remoteClient
-            .getEntryData(buildAliasEntryName(clusterName, alias));
-      }
-
-      /* Generate a new password */
-      if (encrypted == null) {
-
-        /* Generate a new password  */
-        if (generate) {
-          generateAliasForCluster(clusterName, alias);
-          password = getPasswordFromAliasForCluster(clusterName, alias);
-        }
-
-      } else {
-        try {
-          password = decrypt(encrypted).toCharArray();
-        } catch (final Exception e) {
-          throw new AliasServiceException(e);
-        }
-      }
+    if (remoteAliasServiceImpl != null) {
+      password = remoteAliasServiceImpl.getPasswordFromAliasForCluster(clusterName, alias);
     }
 
     /*
@@ -351,8 +156,7 @@ public class RemoteAliasService implements AliasService {
      */
     if(password == null) {
       /* try to get it from the local keystore, ignore generate flag. */
-      password = localAliasService
-          .getPasswordFromAliasForCluster(clusterName, alias, generate);
+      password = localAliasService.getPasswordFromAliasForCluster(clusterName, alias);
     }
 
     /* found nothing */
@@ -360,11 +164,8 @@ public class RemoteAliasService implements AliasService {
   }
 
   @Override
-  public void generateAliasForCluster(final String clusterName,
-      final String givenAlias) throws AliasServiceException {
-
-    /* convert all alias names to lower case since JDK expects the same behaviour */
-    final String alias = givenAlias.toLowerCase(Locale.ROOT);
+  public void generateAliasForCluster(final String clusterName, final String alias)
+      throws AliasServiceException {
     /* auto-generated password */
     final String passwordString = PasswordUtils.generatePassword(16);
     addAliasForCluster(clusterName, alias, passwordString);
@@ -378,40 +179,22 @@ public class RemoteAliasService implements AliasService {
 
   @Override
   public char[] getGatewayIdentityPassphrase() throws AliasServiceException {
-    char[] passphrase = getPasswordFromAliasForGateway(config.getIdentityKeyPassphraseAlias());
-    if (passphrase == null) {
-      // Fall back to the keystore password if a key-specific password was not explicitly set.
-      passphrase = getGatewayIdentityKeystorePassword();
-    }
-    if (passphrase == null) {
-      // Use the master password if not password was found
-      passphrase = ms.getMasterSecret();
-    }
-    return passphrase;
+    return getPasswordFromAliasForGateway(config.getIdentityKeyPassphraseAlias());
   }
 
   @Override
   public char[] getGatewayIdentityKeystorePassword() throws AliasServiceException {
-    return getKeystorePassword(config.getIdentityKeystorePasswordAlias());
+    return getPasswordFromAliasForGateway(config.getIdentityKeystorePasswordAlias());
   }
 
   @Override
   public char[] getSigningKeyPassphrase() throws AliasServiceException {
-    char[] passphrase = getPasswordFromAliasForGateway(config.getSigningKeyPassphraseAlias());
-    if (passphrase == null) {
-      // Fall back to the keystore password if a key-specific password was not explicitly set.
-      passphrase = getSigningKeystorePassword();
-    }
-    if (passphrase == null) {
-      // Use the master password if not password was found
-      passphrase = ms.getMasterSecret();
-    }
-    return passphrase;
+    return getPasswordFromAliasForGateway(config.getSigningKeyPassphraseAlias());
   }
 
   @Override
   public char[] getSigningKeystorePassword() throws AliasServiceException {
-    return getKeystorePassword(config.getSigningKeystorePasswordAlias());
+    return getPasswordFromAliasForGateway(config.getIdentityKeystorePasswordAlias());
   }
 
   @Override
@@ -428,264 +211,39 @@ public class RemoteAliasService implements AliasService {
   }
 
   @Override
-  public void init(final GatewayConfig config,
-      final Map<String, String> options) throws ServiceLifecycleException {
+  public void init(final GatewayConfig config, final Map<String, String> options)
+      throws ServiceLifecycleException {
     this.config = config;
-
-    /* setup and initialize encryptor for encryption and decryption of passwords */
-    encryptor = new ConfigurableEncryptor(new String(ms.getMasterSecret()));
-    encryptor.init(config);
-
-    /* If we have remote registry configured, query it */
-    final String clientName = config.getRemoteConfigurationMonitorClientName();
-    if (clientName != null) {
-
-      if (registryClientService != null) {
-
-        remoteClient = registryClientService.get(clientName);
-
-      } else {
-        throw new ServiceLifecycleException(
-            "Remote configuration registry not initialized");
+    Map<String, String> remoteAliasServiceConfigs = config.getRemoteAliasServiceConfiguration();
+
+    if(config.isRemoteAliasServiceEnabled() && remoteAliasServiceConfigs != null) {
+      String remoteAliasServiceType = remoteAliasServiceConfigs.get(REMOTE_ALIAS_SERVICE_TYPE);
+      ServiceLoader<RemoteAliasServiceProvider> providers =
+          ServiceLoader.load(RemoteAliasServiceProvider.class);
+      for (RemoteAliasServiceProvider provider : providers) {
+        if(provider.getType().equalsIgnoreCase(remoteAliasServiceType)) {
+          LOG.remoteAliasServiceEnabled();
+          remoteAliasServiceImpl = provider.newInstance(localAliasService, ms);
+          remoteAliasServiceImpl.init(config, options);
+          break;
+        }
       }
-
     } else {
-      LOG.missingClientConfigurationForRemoteMonitoring();
+      LOG.remoteAliasServiceDisabled();
     }
   }
 
   @Override
   public void start() throws ServiceLifecycleException {
-
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-
-      /* ensure that nodes are properly setup */
-      ensureEntries(remoteClient);
-
-      /* Confirm access to the remote aliases directory */
-      final List<String> aliases = remoteClient
-          .listChildEntries(PATH_KNOX_ALIAS_STORE_TOPOLOGY);
-      if (aliases == null) {
-        // Either the entry does not exist, or there is an authentication problem
-        throw new IllegalStateException(
-            "Unable to access remote path: " + PATH_KNOX_ALIAS_STORE_TOPOLOGY);
-      }
-
-      /* Register a listener for aliases entry additions/removals */
-      try {
-        remoteClient.addChildEntryListener(PATH_KNOX_ALIAS_STORE_TOPOLOGY,
-            new RemoteAliasChildListener(this));
-      } catch (final Exception e) {
-        throw new IllegalStateException(
-            "Unable to add listener for path " + PATH_KNOX_ALIAS_STORE_TOPOLOGY,
-            e);
-      }
+    if (remoteAliasServiceImpl != null) {
+      remoteAliasServiceImpl.start();
     }
-
-    if(!config.isRemoteAliasServiceEnabled()) {
-      LOG.remoteAliasServiceDisabled();
-    } else {
-      LOG.remoteAliasServiceEnabled();
-    }
-
   }
 
   @Override
   public void stop() throws ServiceLifecycleException {
-    if(remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-      try {
-        remoteClient.removeEntryListener(PATH_KNOX_ALIAS_STORE_TOPOLOGY);
-      } catch (final Exception e) {
-        LOG.errorRemovingRemoteListener(PATH_KNOX_ALIAS_STORE_TOPOLOGY, e.toString());
-      }
-    }
-  }
-
-  /**
-   * Add the alias to the local keystore.
-   * Most likely this will be called by remote registry watch listener.
-   *
-   * @param clusterName Name of the cluster
-   * @param alias       Alias name to be added
-   * @param value       alias value to be added
-   * @throws AliasServiceException exception on failure adding alias
-   */
-  public void addAliasForClusterLocally(final String clusterName,
-      final String alias, final String value) throws AliasServiceException {
-    localAliasService.addAliasForCluster(clusterName, alias, value);
-  }
-
-  /**
-   * Remove the given alias from local keystore.
-   * Most likely this will be called by remote registry watch listener.
-   *
-   * @param clusterName Name of the cluster
-   * @param alias       Alias name to be removed
-   * @throws AliasServiceException exception on failure removing alias
-   */
-  public void removeAliasForClusterLocally(final String clusterName,
-      final String alias) throws AliasServiceException {
-    LOG.removeAliasLocally(clusterName, alias);
-    localAliasService.removeAliasForCluster(clusterName, alias);
-  }
-
-  /**
-   * Ensure that the nodes are properly set up.
-   */
-  private void ensureEntries(
-      final RemoteConfigurationRegistryClient remoteClient) {
-    ensureEntry(PATH_KNOX, remoteClient);
-    ensureEntry(PATH_KNOX_SECURITY, remoteClient);
-    ensureEntry(PATH_KNOX_ALIAS_STORE_TOPOLOGY, remoteClient);
-    ensureEntry(
-        PATH_KNOX_ALIAS_STORE_TOPOLOGY + PATH_SEPARATOR + DEFAULT_CLUSTER_NAME,
-        remoteClient);
-  }
-
-  private char[] getKeystorePassword(String alias) throws AliasServiceException {
-    char[] passphrase = getPasswordFromAliasForGateway(alias);
-    if (passphrase == null) {
-      passphrase = ms.getMasterSecret();
-    }
-    return passphrase;
-  }
-
-
-  /**
-   * Encrypt the clear text with master password.
-   * @param clear clear text to be encrypted
-   * @return encrypted and base 64 encoded result.
-   * @throws Exception exception on failure
-   */
-  public String encrypt(final String clear) throws Exception {
-
-    final EncryptionResult result = encryptor.encrypt(clear);
-
-    return Base64.encodeBase64String(
-        (Base64.encodeBase64String(result.salt) + "::" + Base64
-            .encodeBase64String(result.iv) + "::" + Base64
-            .encodeBase64String(result.cipher)).getBytes(StandardCharsets.UTF_8));
-  }
-
-  /**
-   * Function to decrypt the encrypted text using master secret.
-   *
-   * @param encoded encoded and encrypted string.
-   * @return decrypted password.
-   * @throws Exception exception on failure
-   */
-  public String decrypt(final String encoded) throws Exception {
-
-    final String line = new String(Base64.decodeBase64(encoded), StandardCharsets.UTF_8);
-    final String[] parts = line.split("::");
-    if(parts.length != 3) {
-      throw new IllegalArgumentException("Data should have 3 parts split by ::");
-    }
-    return new String(encryptor
-        .decrypt(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]),
-            Base64.decodeBase64(parts[2])), StandardCharsets.UTF_8);
-  }
-
-  /**
-   * A listener that listens for changes to the child nodes.
-   */
-  private class RemoteAliasChildListener
-      implements RemoteConfigurationRegistryClient.ChildEntryListener {
-
-    final RemoteAliasService remoteAliasService;
-
-    RemoteAliasChildListener (final RemoteAliasService remoteAliasService ) {
-      this.remoteAliasService = remoteAliasService;
-    }
-
-    @Override
-    public void childEvent(final RemoteConfigurationRegistryClient client,
-        final Type type, final String path) {
-
-      final String subPath = StringUtils.substringAfter(path,
-          PATH_KNOX_ALIAS_STORE_TOPOLOGY + PATH_SEPARATOR);
-      final String[] paths = StringUtils.split(subPath, '/');
-
-      switch (type) {
-      case REMOVED:
-        try {
-          /* remove listener */
-          client.removeEntryListener(path);
-
-          if (GatewayServer.getGatewayServices() != null) {
-            /* remove the alias from local keystore */
-            final AliasService aliasService = GatewayServer.getGatewayServices()
-                .getService(GatewayServices.ALIAS_SERVICE);
-            if (paths.length > 1
-                    && aliasService instanceof RemoteAliasService) {
-              ((RemoteAliasService) aliasService)
-                  .removeAliasForClusterLocally(paths[0], paths[1]);
-            }
-          }
-        } catch (final Exception e) {
-          LOG.errorRemovingAliasLocally(paths[0], paths[1], e.toString());
-        }
-        break;
-
-      case ADDED:
-        /* do not set listeners on cluster name but on respective aliases */
-        if (paths.length > 1) {
-          LOG.addAliasLocally(paths[0], paths[1]);
-          try {
-            client.addEntryListener(path,
-                new RemoteAliasEntryListener(paths[0], paths[1], remoteAliasService));
-          } catch (final Exception e) {
-            LOG.errorRemovingAliasLocally(paths[0], paths[1], e.toString());
-          }
-        } else if (subPath != null) {
-          /* Add a child listener for the cluster */
-          LOG.addRemoteListener(path);
-          try {
-            client.addChildEntryListener(path, new RemoteAliasChildListener(remoteAliasService));
-          } catch (Exception e) {
-            LOG.errorAddingRemoteListener(path, e.toString());
-          }
-        }
-
-        break;
-      }
-    }
-  }
-
-  /**
-   * A listener that listens for changes to node value.
-   */
-  private static class RemoteAliasEntryListener
-      implements RemoteConfigurationRegistryClient.EntryListener {
-
-    final String cluster;
-    final String alias;
-    final RemoteAliasService remoteAliasService;
-
-    RemoteAliasEntryListener(final String cluster, final String alias, final RemoteAliasService remoteAliasService) {
-      this.cluster = cluster;
-      this.alias = alias;
-      this.remoteAliasService = remoteAliasService;
-    }
-
-    @Override
-    public void entryChanged(final RemoteConfigurationRegistryClient client,
-        final String path, final byte[] data) {
-
-      if (GatewayServer.getGatewayServices() != null) {
-        final AliasService aliasService = GatewayServer.getGatewayServices()
-            .getService(GatewayServices.ALIAS_SERVICE);
-
-        if (aliasService instanceof RemoteAliasService) {
-          try {
-            ((RemoteAliasService) aliasService).addAliasForClusterLocally(cluster, alias,
-                remoteAliasService.decrypt(new String(data, StandardCharsets.UTF_8)));
-          } catch (final Exception e) {
-            /* log and move on */
-            LOG.errorAddingAliasLocally(cluster, alias, e.toString());
-          }
-        }
-      }
+    if(remoteAliasServiceImpl != null) {
+      remoteAliasServiceImpl.stop();
     }
   }
 }
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasService.java
similarity index 58%
copy from gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
copy to gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasService.java
index bf41432..2758114 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasService.java
@@ -20,10 +20,8 @@ package org.apache.knox.gateway.services.security.impl;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.knox.gateway.GatewayMessages;
-import org.apache.knox.gateway.GatewayServer;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
-import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceLifecycleException;
 import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
 import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
@@ -42,74 +40,63 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
+import static org.apache.knox.gateway.services.security.impl.RemoteAliasService.DEFAULT_CLUSTER_NAME;
+
 /**
- * An {@link AliasService} implementation based on
- * remote service registry.
- * <p>
- * This class encapsulates the default AliasService implementation which uses
- * local keystore to store the aliases. The order in which Aliases are stored are
- * <ul>
- * <li>Local Keystore</li>
- * <li>Remote Registry</li>
- * </ul>
- *
- * @since 1.1.0
+ * An {@link AliasService} implementation based on zookeeper remote service registry.
  */
-public class RemoteAliasService implements AliasService {
+public class ZookeeperRemoteAliasService implements AliasService {
+  public static final String TYPE = "zookeeper";
 
   public static final String PATH_KNOX = "/knox";
   public static final String PATH_KNOX_SECURITY = PATH_KNOX + "/security";
   public static final String PATH_KNOX_ALIAS_STORE_TOPOLOGY =
       PATH_KNOX_SECURITY + "/topology";
   public static final String PATH_SEPARATOR = "/";
-  public static final String DEFAULT_CLUSTER_NAME = "__gateway";
 
   private static final GatewayMessages LOG = MessagesFactory.get(GatewayMessages.class);
   // N.B. This is ZooKeeper-specific, and should be abstracted when another registry is supported
-  private static final RemoteConfigurationRegistryClient.EntryACL AUTHENTICATED_USERS_ALL;
+  private static final RemoteConfigurationRegistryClient.EntryACL AUTHENTICATED_USERS_ALL =
+      new RemoteConfigurationRegistryClient.EntryACL() {
+        @Override
+        public String getId() {
+          return "";
+        }
 
-  static {
-    AUTHENTICATED_USERS_ALL = new RemoteConfigurationRegistryClient.EntryACL() {
-      @Override
-      public String getId() {
-        return "";
-      }
+        @Override
+        public String getType() {
+          return "auth";
+        }
 
-      @Override
-      public String getType() {
-        return "auth";
-      }
+        @Override
+        public Object getPermissions() {
+          return ZooDefs.Perms.ALL;
+        }
 
-      @Override
-      public Object getPermissions() {
-        return ZooDefs.Perms.ALL;
-      }
+        @Override
+        public boolean canRead() {
+          return true;
+        }
 
-      @Override
-      public boolean canRead() {
-        return true;
-      }
+        @Override
+        public boolean canWrite() {
+          return true;
+        }
+      };
 
-      @Override
-      public boolean canWrite() {
-        return true;
-      }
-    };
-  }
+  private final AliasService localAliasService;
+  private final MasterService ms;
+  private final RemoteConfigurationRegistryClientService remoteConfigurationRegistryClientService;
 
   private RemoteConfigurationRegistryClient remoteClient;
   private ConfigurableEncryptor encryptor;
-  /**
-   * Default alias service
-   */
-  private AliasService localAliasService;
-  private RemoteConfigurationRegistryClientService registryClientService;
-  private MasterService ms;
   private GatewayConfig config;
 
-  /* create an instance */
-  public RemoteAliasService() {
-    super();
+  ZookeeperRemoteAliasService(AliasService localAliasService, MasterService ms,
+      RemoteConfigurationRegistryClientService remoteConfigurationRegistryClientService) {
+    this.localAliasService = localAliasService;
+    this.ms = ms;
+    this.remoteConfigurationRegistryClientService = remoteConfigurationRegistryClientService;
   }
 
   /**
@@ -173,40 +160,6 @@ public class RemoteAliasService implements AliasService {
   }
 
   /**
-   * Returns an empty list if the given list is null,
-   * else returns the given list.
-   */
-  private static List<String> safe(final List<String> given) {
-    return given == null ? Collections.EMPTY_LIST : given;
-  }
-
-  /**
-   * Set a {@link RemoteConfigurationRegistryClientService} instance
-   * used to talk to remote remote service registry.
-   * @param registryClientService registryClientService to set
-   */
-  public void setRegistryClientService(
-      final RemoteConfigurationRegistryClientService registryClientService) {
-    this.registryClientService = registryClientService;
-  }
-
-  /**
-   * Set a {@link MasterService} instance.
-   * @param ms master service to set
-   */
-  public void setMasterService(final MasterService ms) {
-    this.ms = ms;
-  }
-
-  /**
-   * Set local alias service
-   * @param localAliasService local alias service to set
-   */
-  public void setLocalAliasService(AliasService localAliasService) {
-    this.localAliasService = localAliasService;
-  }
-
-  /**
    * Get a list of all aliases for a given cluster.
    * Remote aliases are preferred over local.
    *
@@ -214,43 +167,23 @@ public class RemoteAliasService implements AliasService {
    * @return List of all the aliases
    */
   @Override
-  public List<String> getAliasesForCluster(final String clusterName)
-      throws AliasServiceException {
-
+  public List<String> getAliasesForCluster(final String clusterName) throws AliasServiceException {
     List<String> remoteAliases = new ArrayList<>();
 
     /* If we have remote registry configured, query it */
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
+    if (remoteClient != null) {
       remoteAliases = remoteClient
           .listChildEntries(buildClusterEntryName(clusterName));
     }
 
-    List<String> localAliases = localAliasService
-        .getAliasesForCluster(clusterName);
-
-    /* merge */
-    for (final String alias : safe(localAliases)) {
-      if (!remoteAliases.contains(alias.toLowerCase(Locale.ROOT))) {
-        remoteAliases.add(alias);
-      }
-    }
-
     return remoteAliases;
   }
 
   @Override
   public void addAliasForCluster(final String clusterName,
-      final String givenAlias, final String value)
+      final String alias, final String value)
       throws AliasServiceException {
-
-    /* convert all alias names to lower case since JDK expects the same behaviour */
-    final String alias = givenAlias.toLowerCase(Locale.ROOT);
-
-    /* first add the alias to the local keystore */
-    localAliasService.addAliasForCluster(clusterName, alias, value);
-
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-
+    if (remoteClient != null) {
       final String aliasEntryPath = buildAliasEntryName(clusterName, alias);
 
       /* Ensure the entries are properly set up */
@@ -271,18 +204,10 @@ public class RemoteAliasService implements AliasService {
   }
 
   @Override
-  public void removeAliasForCluster(final String clusterName,
-      final String givenAlias) throws AliasServiceException {
-
-    /* convert all alias names to lower case since JDK expects the same behaviour */
-    final String alias = givenAlias.toLowerCase(Locale.ROOT);
-
-    /* first remove it from the local keystore */
-    localAliasService.removeAliasForCluster(clusterName, alias);
-
+  public void removeAliasForCluster(final String clusterName, final String alias)
+      throws AliasServiceException {
     /* If we have remote registry configured, query it */
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-
+    if (remoteClient != null) {
       final String aliasEntryPath = buildAliasEntryName(clusterName, alias);
 
       if (remoteClient.entryExists(aliasEntryPath)) {
@@ -294,8 +219,6 @@ public class RemoteAliasService implements AliasService {
               alias, clusterName));
         }
       }
-    } else {
-      LOG.missingClientConfigurationForRemoteMonitoring();
     }
   }
 
@@ -315,8 +238,7 @@ public class RemoteAliasService implements AliasService {
     char[] password = null;
 
     /* try to get it from remote registry */
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
-
+    if (remoteClient != null) {
       checkPathsExist(remoteClient);
       String encrypted = null;
 
@@ -343,28 +265,13 @@ public class RemoteAliasService implements AliasService {
       }
     }
 
-    /*
-     * If
-     * 1. Remote registry not configured or
-     * 2. Password not found for given alias in remote registry,
-     * Then try local keystore
-     */
-    if(password == null) {
-      /* try to get it from the local keystore, ignore generate flag. */
-      password = localAliasService
-          .getPasswordFromAliasForCluster(clusterName, alias, generate);
-    }
-
     /* found nothing */
     return password;
   }
 
   @Override
-  public void generateAliasForCluster(final String clusterName,
-      final String givenAlias) throws AliasServiceException {
-
-    /* convert all alias names to lower case since JDK expects the same behaviour */
-    final String alias = givenAlias.toLowerCase(Locale.ROOT);
+  public void generateAliasForCluster(final String clusterName, final String alias)
+      throws AliasServiceException {
     /* auto-generated password */
     final String passwordString = PasswordUtils.generatePassword(16);
     addAliasForCluster(clusterName, alias, passwordString);
@@ -378,93 +285,50 @@ public class RemoteAliasService implements AliasService {
 
   @Override
   public char[] getGatewayIdentityPassphrase() throws AliasServiceException {
-    char[] passphrase = getPasswordFromAliasForGateway(config.getIdentityKeyPassphraseAlias());
-    if (passphrase == null) {
-      // Fall back to the keystore password if a key-specific password was not explicitly set.
-      passphrase = getGatewayIdentityKeystorePassword();
-    }
-    if (passphrase == null) {
-      // Use the master password if not password was found
-      passphrase = ms.getMasterSecret();
-    }
-    return passphrase;
+    return getPasswordFromAliasForGateway(config.getIdentityKeyPassphraseAlias());
   }
 
   @Override
   public char[] getGatewayIdentityKeystorePassword() throws AliasServiceException {
-    return getKeystorePassword(config.getIdentityKeystorePasswordAlias());
+    return getPasswordFromAliasForGateway(config.getIdentityKeystorePasswordAlias());
   }
 
   @Override
   public char[] getSigningKeyPassphrase() throws AliasServiceException {
-    char[] passphrase = getPasswordFromAliasForGateway(config.getSigningKeyPassphraseAlias());
-    if (passphrase == null) {
-      // Fall back to the keystore password if a key-specific password was not explicitly set.
-      passphrase = getSigningKeystorePassword();
-    }
-    if (passphrase == null) {
-      // Use the master password if not password was found
-      passphrase = ms.getMasterSecret();
-    }
-    return passphrase;
+    return getPasswordFromAliasForGateway(config.getSigningKeyPassphraseAlias());
   }
 
   @Override
   public char[] getSigningKeystorePassword() throws AliasServiceException {
-    return getKeystorePassword(config.getSigningKeystorePasswordAlias());
+    return getPasswordFromAliasForGateway(config.getSigningKeystorePasswordAlias());
   }
 
   @Override
-  public void generateAliasForGateway(final String alias)
-      throws AliasServiceException {
+  public void generateAliasForGateway(final String alias) throws AliasServiceException {
     generateAliasForCluster(DEFAULT_CLUSTER_NAME, alias);
   }
 
   @Override
   public Certificate getCertificateForGateway(final String alias)
       throws AliasServiceException {
-    /* We don't store certs in remote registry so we just delegate certs to keystore (DefaultAliasService.getCertificateForGateway) */
-    return localAliasService.getCertificateForGateway(alias);
+    throw new AliasServiceException(new UnsupportedOperationException());
   }
 
   @Override
-  public void init(final GatewayConfig config,
-      final Map<String, String> options) throws ServiceLifecycleException {
+  public void init(final GatewayConfig config, final Map<String, String> options)
+      throws ServiceLifecycleException {
     this.config = config;
 
-    /* setup and initialize encryptor for encryption and decryption of passwords */
-    encryptor = new ConfigurableEncryptor(new String(ms.getMasterSecret()));
-    encryptor.init(config);
-
     /* If we have remote registry configured, query it */
     final String clientName = config.getRemoteConfigurationMonitorClientName();
-    if (clientName != null) {
-
-      if (registryClientService != null) {
-
-        remoteClient = registryClientService.get(clientName);
-
-      } else {
-        throw new ServiceLifecycleException(
-            "Remote configuration registry not initialized");
-      }
-
-    } else {
-      LOG.missingClientConfigurationForRemoteMonitoring();
-    }
-  }
-
-  @Override
-  public void start() throws ServiceLifecycleException {
-
-    if (remoteClient != null && config.isRemoteAliasServiceEnabled()) {
+    if (clientName != null && remoteConfigurationRegistryClientService != null) {
+      remoteClient = remoteConfigurationRegistryClientService.get(clientName);
 
       /* ensure that nodes are properly setup */
       ensureEntries(remoteClient);
 
       /* Confirm access to the remote aliases directory */
-      final List<String> aliases = remoteClient
-          .listChildEntries(PATH_KNOX_ALIAS_STORE_TOPOLOGY);
+      final List<String> aliases = remoteClient.listChildEntries(PATH_KNOX_ALIAS_STORE_TOPOLOGY);
       if (aliases == null) {
         // Either the entry does not exist, or there is an authentication problem
         throw new IllegalStateException(
@@ -480,19 +344,22 @@ public class RemoteAliasService implements AliasService {
             "Unable to add listener for path " + PATH_KNOX_ALIAS_STORE_TOPOLOGY,
             e);
       }
-    }
 
-    if(!config.isRemoteAliasServiceEnabled()) {
-      LOG.remoteAliasServiceDisabled();
+      encryptor = new ConfigurableEncryptor(new String(ms.getMasterSecret()));
+      encryptor.init(config);
     } else {
-      LOG.remoteAliasServiceEnabled();
+      LOG.missingClientConfigurationForRemoteMonitoring();
     }
+  }
+
+  @Override
+  public void start() throws ServiceLifecycleException {
 
   }
 
   @Override
   public void stop() throws ServiceLifecycleException {
-    if(remoteClient != null && config.isRemoteAliasServiceEnabled()) {
+    if(remoteClient != null) {
       try {
         remoteClient.removeEntryListener(PATH_KNOX_ALIAS_STORE_TOPOLOGY);
       } catch (final Exception e) {
@@ -502,69 +369,18 @@ public class RemoteAliasService implements AliasService {
   }
 
   /**
-   * Add the alias to the local keystore.
-   * Most likely this will be called by remote registry watch listener.
-   *
-   * @param clusterName Name of the cluster
-   * @param alias       Alias name to be added
-   * @param value       alias value to be added
-   * @throws AliasServiceException exception on failure adding alias
-   */
-  public void addAliasForClusterLocally(final String clusterName,
-      final String alias, final String value) throws AliasServiceException {
-    localAliasService.addAliasForCluster(clusterName, alias, value);
-  }
-
-  /**
-   * Remove the given alias from local keystore.
-   * Most likely this will be called by remote registry watch listener.
-   *
-   * @param clusterName Name of the cluster
-   * @param alias       Alias name to be removed
-   * @throws AliasServiceException exception on failure removing alias
-   */
-  public void removeAliasForClusterLocally(final String clusterName,
-      final String alias) throws AliasServiceException {
-    LOG.removeAliasLocally(clusterName, alias);
-    localAliasService.removeAliasForCluster(clusterName, alias);
-  }
-
-  /**
-   * Ensure that the nodes are properly set up.
-   */
-  private void ensureEntries(
-      final RemoteConfigurationRegistryClient remoteClient) {
-    ensureEntry(PATH_KNOX, remoteClient);
-    ensureEntry(PATH_KNOX_SECURITY, remoteClient);
-    ensureEntry(PATH_KNOX_ALIAS_STORE_TOPOLOGY, remoteClient);
-    ensureEntry(
-        PATH_KNOX_ALIAS_STORE_TOPOLOGY + PATH_SEPARATOR + DEFAULT_CLUSTER_NAME,
-        remoteClient);
-  }
-
-  private char[] getKeystorePassword(String alias) throws AliasServiceException {
-    char[] passphrase = getPasswordFromAliasForGateway(alias);
-    if (passphrase == null) {
-      passphrase = ms.getMasterSecret();
-    }
-    return passphrase;
-  }
-
-
-  /**
    * Encrypt the clear text with master password.
    * @param clear clear text to be encrypted
    * @return encrypted and base 64 encoded result.
    * @throws Exception exception on failure
    */
-  public String encrypt(final String clear) throws Exception {
-
+  String encrypt(final String clear) throws Exception {
     final EncryptionResult result = encryptor.encrypt(clear);
 
     return Base64.encodeBase64String(
-        (Base64.encodeBase64String(result.salt) + "::" + Base64
-            .encodeBase64String(result.iv) + "::" + Base64
-            .encodeBase64String(result.cipher)).getBytes(StandardCharsets.UTF_8));
+        (Base64.encodeBase64String(result.salt) + "::" +
+             Base64.encodeBase64String(result.iv) + "::" +
+             Base64.encodeBase64String(result.cipher)).getBytes(StandardCharsets.UTF_8));
   }
 
   /**
@@ -574,16 +390,29 @@ public class RemoteAliasService implements AliasService {
    * @return decrypted password.
    * @throws Exception exception on failure
    */
-  public String decrypt(final String encoded) throws Exception {
-
+  String decrypt(final String encoded) throws Exception {
     final String line = new String(Base64.decodeBase64(encoded), StandardCharsets.UTF_8);
     final String[] parts = line.split("::");
     if(parts.length != 3) {
       throw new IllegalArgumentException("Data should have 3 parts split by ::");
     }
-    return new String(encryptor
-        .decrypt(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]),
-            Base64.decodeBase64(parts[2])), StandardCharsets.UTF_8);
+    return new String(encryptor.decrypt(
+        Base64.decodeBase64(parts[0]),
+        Base64.decodeBase64(parts[1]),
+        Base64.decodeBase64(parts[2])), StandardCharsets.UTF_8);
+  }
+
+  /**
+   * Ensure that the nodes are properly set up.
+   */
+  private void ensureEntries(
+      final RemoteConfigurationRegistryClient remoteClient) {
+    ensureEntry(PATH_KNOX, remoteClient);
+    ensureEntry(PATH_KNOX_SECURITY, remoteClient);
+    ensureEntry(PATH_KNOX_ALIAS_STORE_TOPOLOGY, remoteClient);
+    ensureEntry(
+        PATH_KNOX_ALIAS_STORE_TOPOLOGY + PATH_SEPARATOR + DEFAULT_CLUSTER_NAME,
+        remoteClient);
   }
 
   /**
@@ -592,9 +421,9 @@ public class RemoteAliasService implements AliasService {
   private class RemoteAliasChildListener
       implements RemoteConfigurationRegistryClient.ChildEntryListener {
 
-    final RemoteAliasService remoteAliasService;
+    final ZookeeperRemoteAliasService remoteAliasService;
 
-    RemoteAliasChildListener (final RemoteAliasService remoteAliasService ) {
+    RemoteAliasChildListener (final ZookeeperRemoteAliasService remoteAliasService ) {
       this.remoteAliasService = remoteAliasService;
     }
 
@@ -611,16 +440,8 @@ public class RemoteAliasService implements AliasService {
         try {
           /* remove listener */
           client.removeEntryListener(path);
-
-          if (GatewayServer.getGatewayServices() != null) {
-            /* remove the alias from local keystore */
-            final AliasService aliasService = GatewayServer.getGatewayServices()
-                .getService(GatewayServices.ALIAS_SERVICE);
-            if (paths.length > 1
-                    && aliasService instanceof RemoteAliasService) {
-              ((RemoteAliasService) aliasService)
-                  .removeAliasForClusterLocally(paths[0], paths[1]);
-            }
+          if (paths.length > 1) {
+            localAliasService.removeAliasForCluster(paths[0], paths[1]);
           }
         } catch (final Exception e) {
           LOG.errorRemovingAliasLocally(paths[0], paths[1], e.toString());
@@ -633,7 +454,8 @@ public class RemoteAliasService implements AliasService {
           LOG.addAliasLocally(paths[0], paths[1]);
           try {
             client.addEntryListener(path,
-                new RemoteAliasEntryListener(paths[0], paths[1], remoteAliasService));
+                new RemoteAliasEntryListener(paths[0], paths[1],
+                    remoteAliasService, localAliasService));
           } catch (final Exception e) {
             LOG.errorRemovingAliasLocally(paths[0], paths[1], e.toString());
           }
@@ -655,36 +477,31 @@ public class RemoteAliasService implements AliasService {
   /**
    * A listener that listens for changes to node value.
    */
-  private static class RemoteAliasEntryListener
+  private class RemoteAliasEntryListener
       implements RemoteConfigurationRegistryClient.EntryListener {
-
     final String cluster;
     final String alias;
-    final RemoteAliasService remoteAliasService;
+    final AliasService remoteAliasService;
+    final AliasService localAliasService;
 
-    RemoteAliasEntryListener(final String cluster, final String alias, final RemoteAliasService remoteAliasService) {
+    RemoteAliasEntryListener(final String cluster, final String alias,
+                             final AliasService remoteAliasService,
+                             final AliasService localAliasService) {
       this.cluster = cluster;
       this.alias = alias;
       this.remoteAliasService = remoteAliasService;
+      this.localAliasService = localAliasService;
     }
 
     @Override
     public void entryChanged(final RemoteConfigurationRegistryClient client,
         final String path, final byte[] data) {
-
-      if (GatewayServer.getGatewayServices() != null) {
-        final AliasService aliasService = GatewayServer.getGatewayServices()
-            .getService(GatewayServices.ALIAS_SERVICE);
-
-        if (aliasService instanceof RemoteAliasService) {
-          try {
-            ((RemoteAliasService) aliasService).addAliasForClusterLocally(cluster, alias,
-                remoteAliasService.decrypt(new String(data, StandardCharsets.UTF_8)));
-          } catch (final Exception e) {
-            /* log and move on */
-            LOG.errorAddingAliasLocally(cluster, alias, e.toString());
-          }
-        }
+      try {
+        localAliasService.addAliasForCluster(cluster, alias,
+            decrypt(new String(data, StandardCharsets.UTF_8)));
+      } catch (final Exception e) {
+        /* log and move on */
+        LOG.errorAddingAliasLocally(cluster, alias, e.toString());
       }
     }
   }
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasServiceProvider.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasServiceProvider.java
new file mode 100644
index 0000000..5fc37b5
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasServiceProvider.java
@@ -0,0 +1,36 @@
+/*
+ * 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.security.impl;
+
+import org.apache.knox.gateway.security.RemoteAliasServiceProvider;
+import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientServiceProvider;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.MasterService;
+
+public class ZookeeperRemoteAliasServiceProvider implements RemoteAliasServiceProvider {
+  @Override
+  public String getType() {
+    return ZookeeperRemoteAliasService.TYPE;
+  }
+
+  @Override
+  public AliasService newInstance(AliasService localAliasService, MasterService ms) {
+    return new ZookeeperRemoteAliasService(localAliasService, ms,
+        new ZooKeeperClientServiceProvider().newInstance());
+  }
+}
diff --git a/gateway-server/src/main/resources/META-INF/services/org.apache.knox.gateway.security.RemoteAliasServiceProvider b/gateway-server/src/main/resources/META-INF/services/org.apache.knox.gateway.security.RemoteAliasServiceProvider
new file mode 100644
index 0000000..1713bff
--- /dev/null
+++ b/gateway-server/src/main/resources/META-INF/services/org.apache.knox.gateway.security.RemoteAliasServiceProvider
@@ -0,0 +1,19 @@
+##########################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##########################################################################
+
+org.apache.knox.gateway.services.security.impl.ZookeeperRemoteAliasServiceProvider
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/RemoteAliasServiceTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/RemoteAliasServiceTest.java
new file mode 100644
index 0000000..a285c14
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/RemoteAliasServiceTest.java
@@ -0,0 +1,337 @@
+/*
+ * 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.security.impl;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.knox.gateway.services.security.impl.RemoteAliasService.REMOTE_ALIAS_SERVICE_TYPE;
+import static org.easymock.EasyMock.capture;
+
+/**
+ * Test for {@link RemoteAliasService}
+ */
+public class RemoteAliasServiceTest {
+  @Rule
+  public final TemporaryFolder testFolder = new TemporaryFolder();
+
+  @Test
+  public void testNoRemoteAlias() throws Exception {
+    GatewayConfig gc = EasyMock.createNiceMock(GatewayConfig.class);
+    EasyMock.expect(gc.isRemoteAliasServiceEnabled())
+        .andReturn(false).anyTimes();
+    String keystoreDir = testFolder.newFolder().getAbsolutePath();
+    EasyMock.expect(gc.getGatewayKeystoreDir()).andReturn(keystoreDir).anyTimes();
+
+    EasyMock.replay(gc);
+
+    final String expectedClusterName = "sandbox";
+    final String expectedAlias = "knox.test.alias";
+    final String expectedPassword = "dummyPassword";
+
+    final String expectedClusterNameDev = "development";
+    final String expectedAliasDev = "knox.test.alias.dev";
+    final String expectedPasswordDev = "otherDummyPassword";
+
+    final DefaultMasterService ms = EasyMock
+        .createNiceMock(DefaultMasterService.class);
+    EasyMock.expect(ms.getMasterSecret()).andReturn("knox".toCharArray())
+        .anyTimes();
+    EasyMock.replay(ms);
+
+    DefaultKeystoreService ks = new DefaultKeystoreService();
+    ks.setMasterService(ms);
+    ks.init(gc, Collections.emptyMap());
+
+    DefaultAliasService defaultAlias = new DefaultAliasService();
+    defaultAlias.setKeystoreService(ks);
+    defaultAlias.setMasterService(ms);
+    defaultAlias.init(gc, Collections.emptyMap());
+
+    final RemoteAliasService remoteAliasService = new RemoteAliasService(defaultAlias, ms);
+    remoteAliasService.init(gc, Collections.emptyMap());
+    remoteAliasService.start();
+
+    /* Put */
+    remoteAliasService.addAliasForCluster(expectedClusterName, expectedAlias,
+        expectedPassword);
+    remoteAliasService.addAliasForCluster(expectedClusterNameDev, expectedAliasDev,
+        expectedPasswordDev);
+
+    /* GET all Aliases */
+    List<String> aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+    List<String> aliasesDev = remoteAliasService
+        .getAliasesForCluster(expectedClusterNameDev);
+
+    Assert.assertEquals(aliases.size(), 1);
+    Assert.assertEquals(aliasesDev.size(), 1);
+
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(expectedAlias));
+    Assert.assertTrue("Expected alias 'knox.test.alias.dev' not found ",
+        aliasesDev.contains(expectedAliasDev));
+
+    final char[] result = remoteAliasService
+        .getPasswordFromAliasForCluster(expectedClusterName, expectedAlias);
+    final char[] result1 = remoteAliasService
+        .getPasswordFromAliasForCluster(expectedClusterNameDev,
+            expectedAliasDev);
+
+    Assert.assertEquals(expectedPassword, new String(result));
+    Assert.assertEquals(expectedPasswordDev, new String(result1));
+
+    /* Remove */
+    remoteAliasService.removeAliasForCluster(expectedClusterNameDev, expectedAliasDev);
+
+    /* Make sure expectedAliasDev is removed*/
+    aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+    aliasesDev = remoteAliasService.getAliasesForCluster(expectedClusterNameDev);
+
+    Assert.assertEquals(aliasesDev.size(), 0);
+    Assert.assertFalse("Expected alias 'knox.test.alias.dev' to be removed but found.",
+        aliasesDev.contains(expectedAliasDev));
+
+    Assert.assertEquals(aliases.size(), 1);
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(expectedAlias));
+
+    /* Test auto-generate password for alias */
+    final String testAutoGeneratedpasswordAlias = "knox.test.alias.auto";
+
+    final char[] autoGeneratedPassword = remoteAliasService
+        .getPasswordFromAliasForCluster(expectedClusterName,
+            testAutoGeneratedpasswordAlias, true);
+    aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+
+    Assert.assertNotNull(autoGeneratedPassword);
+    Assert.assertEquals(aliases.size(), 2);
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(testAutoGeneratedpasswordAlias));
+  }
+
+  @Test
+  public void testNoRemoteAliasNoConfigs() throws Exception {
+    GatewayConfig gc = EasyMock.createNiceMock(GatewayConfig.class);
+    EasyMock.expect(gc.isRemoteAliasServiceEnabled())
+        .andReturn(true).anyTimes();
+    String keystoreDir = testFolder.newFolder().getAbsolutePath();
+    EasyMock.expect(gc.getGatewayKeystoreDir()).andReturn(keystoreDir).anyTimes();
+
+    EasyMock.replay(gc);
+
+    final String expectedClusterName = "sandbox";
+    final String expectedAlias = "knox.test.alias";
+    final String expectedPassword = "dummyPassword";
+
+    final String expectedClusterNameDev = "development";
+    final String expectedAliasDev = "knox.test.alias.dev";
+    final String expectedPasswordDev = "otherDummyPassword";
+
+    final DefaultMasterService ms = EasyMock
+                                        .createNiceMock(DefaultMasterService.class);
+    EasyMock.expect(ms.getMasterSecret()).andReturn("knox".toCharArray())
+        .anyTimes();
+    EasyMock.replay(ms);
+
+    DefaultKeystoreService ks = new DefaultKeystoreService();
+    ks.setMasterService(ms);
+    ks.init(gc, Collections.emptyMap());
+
+    DefaultAliasService defaultAlias = new DefaultAliasService();
+    defaultAlias.setKeystoreService(ks);
+    defaultAlias.setMasterService(ms);
+    defaultAlias.init(gc, Collections.emptyMap());
+
+    final RemoteAliasService remoteAliasService = new RemoteAliasService(defaultAlias, ms);
+    remoteAliasService.init(gc, Collections.emptyMap());
+    remoteAliasService.start();
+
+    /* Put */
+    remoteAliasService.addAliasForCluster(expectedClusterName, expectedAlias,
+        expectedPassword);
+    remoteAliasService.addAliasForCluster(expectedClusterNameDev, expectedAliasDev,
+        expectedPasswordDev);
+
+    /* GET all Aliases */
+    List<String> aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+    List<String> aliasesDev = remoteAliasService
+                                  .getAliasesForCluster(expectedClusterNameDev);
+
+    Assert.assertEquals(aliases.size(), 1);
+    Assert.assertEquals(aliasesDev.size(), 1);
+
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(expectedAlias));
+    Assert.assertTrue("Expected alias 'knox.test.alias.dev' not found ",
+        aliasesDev.contains(expectedAliasDev));
+
+    final char[] result = remoteAliasService
+                              .getPasswordFromAliasForCluster(expectedClusterName, expectedAlias);
+    final char[] result1 = remoteAliasService
+                               .getPasswordFromAliasForCluster(expectedClusterNameDev,
+                                   expectedAliasDev);
+
+    Assert.assertEquals(expectedPassword, new String(result));
+    Assert.assertEquals(expectedPasswordDev, new String(result1));
+
+    /* Remove */
+    remoteAliasService.removeAliasForCluster(expectedClusterNameDev, expectedAliasDev);
+
+    /* Make sure expectedAliasDev is removed*/
+    aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+    aliasesDev = remoteAliasService.getAliasesForCluster(expectedClusterNameDev);
+
+    Assert.assertEquals(aliasesDev.size(), 0);
+    Assert.assertFalse("Expected alias 'knox.test.alias.dev' to be removed but found.",
+        aliasesDev.contains(expectedAliasDev));
+
+    Assert.assertEquals(aliases.size(), 1);
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(expectedAlias));
+
+    /* Test auto-generate password for alias */
+    final String testAutoGeneratedpasswordAlias = "knox.test.alias.auto";
+
+    final char[] autoGeneratedPassword = remoteAliasService
+                                             .getPasswordFromAliasForCluster(expectedClusterName,
+                                                 testAutoGeneratedpasswordAlias, true);
+    aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+
+    Assert.assertNotNull(autoGeneratedPassword);
+    Assert.assertEquals(aliases.size(), 2);
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(testAutoGeneratedpasswordAlias));
+  }
+
+  @Test
+  public void testRemoteAliasServiceLoading() throws Exception {
+    Map<String, String> remoteAliasConfigs = new HashMap<>();
+    remoteAliasConfigs.put(REMOTE_ALIAS_SERVICE_TYPE, "test");
+
+    GatewayConfig gc = EasyMock.createNiceMock(GatewayConfig.class);
+    EasyMock.expect(gc.isRemoteAliasServiceEnabled()).andReturn(true).anyTimes();
+    EasyMock.expect(gc.getRemoteAliasServiceConfiguration()).andReturn(remoteAliasConfigs).anyTimes();
+    EasyMock.replay(gc);
+
+    final String expectedClusterName = "sandbox";
+    final String expectedAlias = "knox.test.alias";
+    final String expectedPassword = "dummyPassword";
+
+    final String expectedClusterNameDev = "development";
+    final String expectedAliasDev = "knox.test.alias.dev";
+    final String expectedPasswordDev = "otherDummyPassword";
+
+    final DefaultMasterService ms = EasyMock
+                                        .createNiceMock(DefaultMasterService.class);
+    EasyMock.expect(ms.getMasterSecret()).andReturn("knox".toCharArray())
+        .anyTimes();
+    EasyMock.replay(ms);
+
+    // Mock Alias Service
+    final DefaultAliasService defaultAlias = EasyMock
+                                                 .createNiceMock(DefaultAliasService.class);
+    // Captures for validating the alias creation for a generated topology
+    final Capture<String> capturedCluster = EasyMock.newCapture();
+    final Capture<String> capturedAlias = EasyMock.newCapture();
+    final Capture<String> capturedPwd = EasyMock.newCapture();
+
+    defaultAlias
+        .addAliasForCluster(capture(capturedCluster), capture(capturedAlias),
+            capture(capturedPwd));
+    EasyMock.expectLastCall().anyTimes();
+
+    /* defaultAlias.getAliasesForCluster() never returns null */
+    EasyMock.expect(defaultAlias.getAliasesForCluster(expectedClusterName))
+        .andReturn(new ArrayList<>()).anyTimes();
+    EasyMock.expect(defaultAlias.getAliasesForCluster(expectedClusterNameDev))
+        .andReturn(new ArrayList<>()).anyTimes();
+
+    EasyMock.replay(defaultAlias);
+
+    final RemoteAliasService remoteAliasService = new RemoteAliasService(defaultAlias, ms);
+    remoteAliasService.init(gc, Collections.emptyMap());
+    remoteAliasService.start();
+
+    /* Put */
+    remoteAliasService.addAliasForCluster(expectedClusterName, expectedAlias,
+        expectedPassword);
+    remoteAliasService.addAliasForCluster(expectedClusterNameDev, expectedAliasDev,
+        expectedPasswordDev);
+
+    /* GET all Aliases */
+    List<String> aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+    List<String> aliasesDev = remoteAliasService
+                                  .getAliasesForCluster(expectedClusterNameDev);
+
+    Assert.assertEquals(aliases.size(), 1);
+    Assert.assertEquals(aliasesDev.size(), 1);
+
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(expectedAlias));
+    Assert.assertTrue("Expected alias 'knox.test.alias.dev' not found ",
+        aliasesDev.contains(expectedAliasDev));
+
+    final char[] result = remoteAliasService
+                              .getPasswordFromAliasForCluster(expectedClusterName, expectedAlias);
+    final char[] result1 = remoteAliasService
+                               .getPasswordFromAliasForCluster(expectedClusterNameDev,
+                                   expectedAliasDev);
+
+    Assert.assertEquals(expectedPassword, new String(result));
+    Assert.assertEquals(expectedPasswordDev, new String(result1));
+
+    /* Remove */
+    remoteAliasService.removeAliasForCluster(expectedClusterNameDev, expectedAliasDev);
+
+    /* Make sure expectedAliasDev is removed*/
+    aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+    aliasesDev = remoteAliasService.getAliasesForCluster(expectedClusterNameDev);
+
+    Assert.assertEquals(aliasesDev.size(), 0);
+    Assert.assertFalse("Expected alias 'knox.test.alias.dev' to be removed but found.",
+        aliasesDev.contains(expectedAliasDev));
+
+    Assert.assertEquals(aliases.size(), 1);
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(expectedAlias));
+
+    /* Test auto-generate password for alias */
+    final String testAutoGeneratedpasswordAlias = "knox.test.alias.auto";
+
+    final char[] autoGeneratedPassword = remoteAliasService
+                                             .getPasswordFromAliasForCluster(expectedClusterName,
+                                                 testAutoGeneratedpasswordAlias, true);
+    aliases = remoteAliasService.getAliasesForCluster(expectedClusterName);
+
+    Assert.assertNotNull(autoGeneratedPassword);
+    Assert.assertEquals(aliases.size(), 2);
+    Assert.assertTrue("Expected alias 'knox.test.alias' not found ",
+        aliases.contains(testAutoGeneratedpasswordAlias));
+  }
+}
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/RemoteAliasServiceTestProvider.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/RemoteAliasServiceTestProvider.java
new file mode 100644
index 0000000..75f73cb
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/RemoteAliasServiceTestProvider.java
@@ -0,0 +1,135 @@
+/*
+ * 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.security.impl;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.security.RemoteAliasServiceProvider;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.AliasServiceException;
+import org.apache.knox.gateway.services.security.MasterService;
+import org.apache.knox.gateway.util.PasswordUtils;
+
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RemoteAliasServiceTestProvider implements RemoteAliasServiceProvider {
+  @Override
+  public String getType() {
+    return "test";
+  }
+
+  @Override
+  public AliasService newInstance(AliasService localAliasService, MasterService masterService) {
+    return new TestAliasService();
+  }
+
+  private class TestAliasService implements AliasService {
+    private final Map<String, Map<String, String>> aliases = new HashMap<>();
+    private GatewayConfig config;
+
+    @Override
+    public List<String> getAliasesForCluster(String clusterName) {
+      return new ArrayList<>(aliases.getOrDefault(clusterName, Collections.emptyMap()).keySet());
+    }
+
+    @Override
+    public void addAliasForCluster(String clusterName, String alias, String value) {
+      if(!aliases.containsKey(clusterName)) {
+        aliases.put(clusterName, new HashMap<>());
+      }
+      aliases.get(clusterName).put(alias, value);
+    }
+
+    @Override
+    public void removeAliasForCluster(String clusterName, String alias) {
+      aliases.getOrDefault(clusterName, new HashMap<>()).remove(alias);
+    }
+
+    @Override
+    public char[] getPasswordFromAliasForCluster(String clusterName, String alias) {
+      return aliases.getOrDefault(clusterName, new HashMap<>()).get(alias).toCharArray();
+    }
+
+    @Override
+    public char[] getPasswordFromAliasForCluster(String clusterName, String alias, boolean generate) {
+      if(generate) {
+        generateAliasForCluster(clusterName, alias);
+      }
+      return getPasswordFromAliasForCluster(clusterName, alias);
+    }
+
+    @Override
+    public void generateAliasForCluster(String clusterName, String alias) {
+      addAliasForCluster(clusterName, alias, PasswordUtils.generatePassword(16));
+    }
+
+    @Override
+    public char[] getPasswordFromAliasForGateway(String alias) {
+      return getPasswordFromAliasForCluster(RemoteAliasService.DEFAULT_CLUSTER_NAME, alias);
+    }
+
+    @Override
+    public char[] getGatewayIdentityPassphrase() {
+      return getPasswordFromAliasForGateway(config.getIdentityKeyPassphraseAlias());
+    }
+
+    @Override
+    public char[] getGatewayIdentityKeystorePassword() {
+      return getPasswordFromAliasForGateway(config.getIdentityKeystorePasswordAlias());
+    }
+
+    @Override
+    public char[] getSigningKeyPassphrase() {
+      return getPasswordFromAliasForGateway(config.getSigningKeyPassphraseAlias());
+    }
+
+    @Override
+    public char[] getSigningKeystorePassword() {
+      return getPasswordFromAliasForGateway(config.getSigningKeystorePasswordAlias());
+    }
+
+    @Override
+    public void generateAliasForGateway(String alias) {
+      generateAliasForCluster(RemoteAliasService.DEFAULT_CLUSTER_NAME, alias);
+    }
+
+    @Override
+    public Certificate getCertificateForGateway(String alias) throws AliasServiceException {
+      throw new AliasServiceException(new UnsupportedOperationException());
+    }
+
+    @Override
+    public void init(GatewayConfig config, Map<String, String> options) {
+      this.config = config;
+    }
+
+    @Override
+    public void start() {
+
+    }
+
+    @Override
+    public void stop() {
+
+    }
+  }
+}
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/security/impl/RemoteAliasMonitorTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasMonitorTest.java
similarity index 77%
rename from gateway-server/src/test/java/org/apache/knox/gateway/security/impl/RemoteAliasMonitorTest.java
rename to gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasMonitorTest.java
index 5e97f4b..7c47eec 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/security/impl/RemoteAliasMonitorTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasMonitorTest.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.knox.gateway.security.impl;
+package org.apache.knox.gateway.services.security.impl;
 
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
@@ -26,9 +26,6 @@ import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientService;
 import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientServiceProvider;
 import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
-import org.apache.knox.gateway.services.security.impl.DefaultAliasService;
-import org.apache.knox.gateway.services.security.impl.DefaultMasterService;
-import org.apache.knox.gateway.services.security.impl.RemoteAliasService;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.data.ACL;
@@ -52,26 +49,23 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 /**
- * Test the listener/monitor service for
- * remote alias service.
+ * Test the listener/monitor service for {@link ZookeeperRemoteAliasService}.
  */
-public class RemoteAliasMonitorTest {
+public class ZookeeperRemoteAliasMonitorTest {
+  private static final String configMonitorName = "remoteConfigMonitorClient";
+  private static final String expectedClusterName = "sandbox";
+  private static final String expectedAlias = "knox.test.alias";
+  private static final String expectedPassword = "dummyPassword";
+  private static final String expectedClusterNameDev = "development";
+  private static final String expectedAliasDev = "knox.test.alias.dev";
+  private static final String expectedPasswordDev = "otherDummyPassword";
+
+  private static final String preferRemoteAlias = "prefer.remote.alias";
+  private static final String preferRemoteAliasEncryptedPassword = "QmgrK2JBRlE1MUU9OjpIYzZlVUttKzdaWkFOSjlYZVVyVzNRPT06Om5kdTQ3WTJ1by9vSHprZUZHcjBqVG5TaGxsMFVUdUNyN0EvUlZDV1ZHQUU9";
+  private static final String preferRemoteAliasClearPassword = "ApacheKnoxPassword123";
 
   private static TestingCluster zkNodes;
-
   private static CuratorFramework client;
-  private static String configMonitorName = "remoteConfigMonitorClient";
-  private static String expectedClusterName = "sandbox";
-  private static String expectedAlias = "knox.test.alias";
-  private static String expectedPassword = "dummyPassword";
-  private static String expectedClusterNameDev = "development";
-  private static String expectedAliasDev = "knox.test.alias.dev";
-  private static String expectedPasswordDev = "otherDummyPassword";
-
-  private static String preferRemoteAlias = "prefer.remote.alias";
-  private static String preferRemoteAliasEncryptedPassword = "QmgrK2JBRlE1MUU9OjpIYzZlVUttKzdaWkFOSjlYZVVyVzNRPT06Om5kdTQ3WTJ1by9vSHprZUZHcjBqVG5TaGxsMFVUdUNyN0EvUlZDV1ZHQUU9";
-  private static String preferRemoteAliasClearPassword = "ApacheKnoxPassword123";
-  private GatewayConfig gc;
 
   @BeforeClass
   public static void setupSuite() throws Exception {
@@ -106,34 +100,34 @@ public class RemoteAliasMonitorTest {
 
     client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
         .withACL(acls).forPath(
-        RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + RemoteAliasService.
+        ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + ZookeeperRemoteAliasService.
             PATH_SEPARATOR + expectedClusterName);
 
     assertNotNull("Failed to create node:"
-        + RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
-        + RemoteAliasService.
+        + ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
+        + ZookeeperRemoteAliasService.
         PATH_SEPARATOR + expectedClusterName, client.checkExists().forPath(
-        RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + RemoteAliasService.
+        ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + ZookeeperRemoteAliasService.
             PATH_SEPARATOR + expectedClusterName));
 
     client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
         .withACL(acls).forPath(
-        RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + RemoteAliasService.
+        ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + ZookeeperRemoteAliasService.
             PATH_SEPARATOR + expectedClusterNameDev);
 
     assertNotNull("Failed to create node:"
-        + RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
-        + RemoteAliasService.
+        + ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
+        + ZookeeperRemoteAliasService.
         PATH_SEPARATOR + expectedClusterNameDev, client.checkExists().forPath(
-        RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + RemoteAliasService.
+        ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY + ZookeeperRemoteAliasService.
             PATH_SEPARATOR + expectedClusterNameDev));
 
     /* Start Zookeeper with an existing alias */
     client.create().withMode(CreateMode.PERSISTENT).
-        forPath(RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
-                + RemoteAliasService.
+        forPath(ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
+                + ZookeeperRemoteAliasService.
                 PATH_SEPARATOR + expectedClusterName
-                + RemoteAliasService.PATH_SEPARATOR + preferRemoteAlias,
+                + ZookeeperRemoteAliasService.PATH_SEPARATOR + preferRemoteAlias,
             preferRemoteAliasEncryptedPassword.getBytes(StandardCharsets.UTF_8));
   }
 
@@ -142,7 +136,7 @@ public class RemoteAliasMonitorTest {
     // Clean up the ZK nodes, and close the client
     if (client != null) {
       client.delete().deletingChildrenIfNeeded()
-          .forPath(RemoteAliasService.PATH_KNOX_SECURITY);
+          .forPath(ZookeeperRemoteAliasService.PATH_KNOX_SECURITY);
       client.close();
     }
 
@@ -154,7 +148,7 @@ public class RemoteAliasMonitorTest {
   public void testListener() throws Exception {
 
     // Setup the base GatewayConfig mock
-    gc = EasyMock.createNiceMock(GatewayConfig.class);
+    GatewayConfig gc = EasyMock.createNiceMock(GatewayConfig.class);
     EasyMock.expect(gc.getRemoteRegistryConfigurationNames())
         .andReturn(Collections.singletonList(configMonitorName)).anyTimes();
 
@@ -204,17 +198,13 @@ public class RemoteAliasMonitorTest {
         .anyTimes();
     EasyMock.replay(ms);
 
-    final RemoteAliasService zkAlias = new RemoteAliasService();
-
     final RemoteConfigurationRegistryClientService clientService = (new ZooKeeperClientServiceProvider())
         .newInstance();
-    clientService.setAliasService(zkAlias);
+    clientService.setAliasService(defaultAlias);
     clientService.init(gc, Collections.emptyMap());
 
-    /* init */
-    zkAlias.setLocalAliasService(defaultAlias);
-    zkAlias.setRegistryClientService(clientService);
-    zkAlias.setMasterService(ms);
+    final ZookeeperRemoteAliasService zkAlias = new ZookeeperRemoteAliasService(defaultAlias,
+        ms, clientService);
     zkAlias.init(gc, Collections.emptyMap());
     zkAlias.start();
 
@@ -227,21 +217,20 @@ public class RemoteAliasMonitorTest {
     Assert.assertEquals(aliases.size(), 1);
     Assert.assertEquals(aliasesDev.size(), 0);
 
-
     /* Create an alias in Zookeeper externally */
     client.create().withMode(CreateMode.PERSISTENT).
-        forPath(RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
-                + RemoteAliasService.
+        forPath(ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
+                + ZookeeperRemoteAliasService.
                 PATH_SEPARATOR + expectedClusterName
-                + RemoteAliasService.PATH_SEPARATOR + expectedAlias,
+                + ZookeeperRemoteAliasService.PATH_SEPARATOR + expectedAlias,
             zkAlias.encrypt(expectedPassword).getBytes(StandardCharsets.UTF_8));
 
     /* Create an alias in Zookeeper externally */
     client.create().withMode(CreateMode.PERSISTENT).
-        forPath(RemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
-                + RemoteAliasService.
+        forPath(ZookeeperRemoteAliasService.PATH_KNOX_ALIAS_STORE_TOPOLOGY
+                + ZookeeperRemoteAliasService.
                 PATH_SEPARATOR + expectedClusterNameDev
-                + RemoteAliasService.PATH_SEPARATOR + expectedAliasDev,
+                + ZookeeperRemoteAliasService.PATH_SEPARATOR + expectedAliasDev,
             zkAlias.encrypt(expectedPasswordDev).getBytes(StandardCharsets.UTF_8));
 
     /* Try */
@@ -269,7 +258,5 @@ public class RemoteAliasMonitorTest {
     Assert.assertEquals(preferRemoteAliasClearPassword, new String(prefAliasResult));
 
     zkAlias.stop();
-
   }
-
 }
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/security/impl/RemoteAliasServiceTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasServiceTest.java
similarity index 89%
rename from gateway-server/src/test/java/org/apache/knox/gateway/security/impl/RemoteAliasServiceTest.java
rename to gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasServiceTest.java
index e1429b5..c30715e 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/security/impl/RemoteAliasServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/ZookeeperRemoteAliasServiceTest.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.knox.gateway.security.impl;
+package org.apache.knox.gateway.services.security.impl;
 
 import org.apache.curator.test.InstanceSpec;
 import org.apache.curator.test.TestingCluster;
@@ -24,9 +24,6 @@ import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientService;
 import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientServiceProvider;
 import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
 import org.apache.knox.gateway.services.security.AliasService;
-import org.apache.knox.gateway.services.security.impl.DefaultAliasService;
-import org.apache.knox.gateway.services.security.impl.DefaultMasterService;
-import org.apache.knox.gateway.services.security.impl.RemoteAliasService;
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.junit.AfterClass;
@@ -44,20 +41,15 @@ import java.util.Map;
 import static org.easymock.EasyMock.capture;
 
 /**
- * Test for {@link RemoteAliasService} backed by Zookeeper.
+ * Test for {@link ZookeeperRemoteAliasService} backed by Zookeeper.
  */
-public class RemoteAliasServiceTest {
-
-  private static final String configMonitorName = "remoteConfigMonitorClient";
+public class ZookeeperRemoteAliasServiceTest {
   private static TestingCluster zkNodes;
   private static GatewayConfig gc;
 
-  public RemoteAliasServiceTest() {
-    super();
-  }
-
   @BeforeClass
   public static void setupSuite() throws Exception {
+    String configMonitorName = "remoteConfigMonitorClient";
 
     configureAndStartZKCluster();
 
@@ -149,17 +141,13 @@ public class RemoteAliasServiceTest {
         .anyTimes();
     EasyMock.replay(ms);
 
-    final RemoteAliasService zkAlias = new RemoteAliasService();
-
     RemoteConfigurationRegistryClientService clientService = (new ZooKeeperClientServiceProvider())
         .newInstance();
-    clientService.setAliasService(zkAlias);
+    clientService.setAliasService(defaultAlias);
     clientService.init(gc, Collections.emptyMap());
 
-    /* init */
-    zkAlias.setLocalAliasService(defaultAlias);
-    zkAlias.setRegistryClientService(clientService);
-    zkAlias.setMasterService(ms);
+    final ZookeeperRemoteAliasService zkAlias = new ZookeeperRemoteAliasService(defaultAlias, ms,
+        clientService);
     zkAlias.init(gc, Collections.emptyMap());
     zkAlias.start();
 
@@ -222,7 +210,6 @@ public class RemoteAliasServiceTest {
 
   @Test
   public void testEncryptDecrypt() throws Exception {
-
     final String testPassword = "ApacheKnoxPassword123";
 
     final AliasService defaultAlias = EasyMock
@@ -235,11 +222,13 @@ public class RemoteAliasServiceTest {
         .anyTimes();
     EasyMock.replay(ms);
 
-    final RemoteAliasService zkAlias = new RemoteAliasService();
-    zkAlias.setLocalAliasService(defaultAlias);
-    zkAlias.setRegistryClientService(
-        (new ZooKeeperClientServiceProvider()).newInstance());
-    zkAlias.setMasterService(ms);
+    RemoteConfigurationRegistryClientService clientService = (new ZooKeeperClientServiceProvider())
+                                                                 .newInstance();
+    clientService.setAliasService(defaultAlias);
+    clientService.init(gc, Collections.emptyMap());
+
+    final ZookeeperRemoteAliasService zkAlias = new ZookeeperRemoteAliasService(defaultAlias, ms,
+        clientService);
     zkAlias.init(gc, Collections.emptyMap());
 
     final String encrypted = zkAlias.encrypt(testPassword);
diff --git a/gateway-server/src/test/resources/META-INF/services/org.apache.knox.gateway.security.RemoteAliasServiceProvider b/gateway-server/src/test/resources/META-INF/services/org.apache.knox.gateway.security.RemoteAliasServiceProvider
new file mode 100644
index 0000000..6651917
--- /dev/null
+++ b/gateway-server/src/test/resources/META-INF/services/org.apache.knox.gateway.security.RemoteAliasServiceProvider
@@ -0,0 +1,19 @@
+##########################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##########################################################################
+
+org.apache.knox.gateway.services.security.impl.RemoteAliasServiceTestProvider
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index 93f17ac..9a4e6e9 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -476,6 +476,20 @@ public interface GatewayConfig {
   boolean isRemoteAliasServiceEnabled();
 
   /**
+   * Returns prefix for the remote alias service configuration
+   *
+   * @return the prefix for the remote alias service configuration
+   */
+  String getRemoteAliasServiceConfigurationPrefix();
+
+  /**
+   * Uses result of getRemoteAliasServiceConfigurationPrefix to return configurations
+   *
+   * @return Map of configurations that apply to the remote alias service
+   */
+  Map<String, String> getRemoteAliasServiceConfiguration();
+
+  /**
    * Get the list of those topology names which should be treated as read-only, regardless of their actual read-write
    * status.
    *
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/security/RemoteAliasServiceProvider.java b/gateway-spi/src/main/java/org/apache/knox/gateway/security/RemoteAliasServiceProvider.java
new file mode 100644
index 0000000..6980a56
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/security/RemoteAliasServiceProvider.java
@@ -0,0 +1,26 @@
+/*
+ * 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.security;
+
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.MasterService;
+
+public interface RemoteAliasServiceProvider {
+  String getType();
+
+  AliasService newInstance(AliasService localAliasService, MasterService masterService);
+}
diff --git a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index 35b0ce9..3f376f3 100644
--- a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++ b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -653,6 +653,16 @@ public class GatewayTestConfig extends Configuration implements GatewayConfig {
   }
 
   @Override
+  public String getRemoteAliasServiceConfigurationPrefix() {
+    return null;
+  }
+
+  @Override
+  public Map<String, String> getRemoteAliasServiceConfiguration() {
+    return Collections.emptyMap();
+  }
+
+  @Override
   public int getClusterMonitorPollingInterval(String type) {
     return 600;
   }