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;
}