From commits-return-3750-apmail-knox-commits-archive=knox.apache.org@knox.apache.org Sat Mar 2 16:19:40 2019 Return-Path: X-Original-To: apmail-knox-commits-archive@minotaur.apache.org Delivered-To: apmail-knox-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 44CF018C6C for ; Sat, 2 Mar 2019 16:19:40 +0000 (UTC) Received: (qmail 71714 invoked by uid 500); 2 Mar 2019 16:19:40 -0000 Delivered-To: apmail-knox-commits-archive@knox.apache.org Received: (qmail 71672 invoked by uid 500); 2 Mar 2019 16:19:40 -0000 Mailing-List: contact commits-help@knox.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@knox.apache.org Delivered-To: mailing list commits@knox.apache.org Received: (qmail 71663 invoked by uid 99); 2 Mar 2019 16:19:39 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 02 Mar 2019 16:19:39 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 370B38773A; Sat, 2 Mar 2019 16:19:39 +0000 (UTC) Date: Sat, 02 Mar 2019 16:19:39 +0000 To: "commits@knox.apache.org" Subject: [knox] branch master updated: KNOX-1789 - Refactor RemoteAliasService to use service loading (#59) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <155154357908.31127.8388577955286725636@gitbox.apache.org> From: lmccay@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: knox X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 04a60fb9f1f65007ef702106fd0c80e67fb3d499 X-Git-Newrev: df120a701f2fbba6324528c7e5a2817e7a02e0da X-Git-Rev: df120a701f2fbba6324528c7e5a2817e7a02e0da X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated 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 AuthorDate: Sat Mar 2 10:19:34 2019 -0600 KNOX-1789 - Refactor RemoteAliasService to use service loading (#59) Signed-off-by: Kevin Risden --- .../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 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 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 services = new HashMap<>(); - private CLIMasterService ms; - private DefaultKeystoreService ks; - - public CLIGatewayServices() { - super(); - } @Override public void init(GatewayConfig config, Map 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 services = new HashMap<>(); - private DefaultMasterService ms; - private DefaultKeystoreService ks; - - public DefaultGatewayServices() { - super(); - } @Override public void init(GatewayConfig config, Map 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. *

* 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 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 safe(final List 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 getAliasesForCluster(final String clusterName) - throws AliasServiceException { - + public List getAliasesForCluster(final String clusterName) throws AliasServiceException { List 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 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 options) throws ServiceLifecycleException { + public void init(final GatewayConfig config, final Map 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 remoteAliasServiceConfigs = config.getRemoteAliasServiceConfiguration(); + + if(config.isRemoteAliasServiceEnabled() && remoteAliasServiceConfigs != null) { + String remoteAliasServiceType = remoteAliasServiceConfigs.get(REMOTE_ALIAS_SERVICE_TYPE); + ServiceLoader 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 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. - *

- * This class encapsulates the default AliasService implementation which uses - * local keystore to store the aliases. The order in which Aliases are stored are - *

    - *
  • Local Keystore
  • - *
  • Remote Registry
  • - *
- * - * @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 safe(final List 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 getAliasesForCluster(final String clusterName) - throws AliasServiceException { - + public List getAliasesForCluster(final String clusterName) throws AliasServiceException { List 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 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 options) throws ServiceLifecycleException { + public void init(final GatewayConfig config, final Map 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 aliases = remoteClient - .listChildEntries(PATH_KNOX_ALIAS_STORE_TOPOLOGY); + final List 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 + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.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 + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.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 aliases = remoteAliasService.getAliasesForCluster(expectedClusterName); + List 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 aliases = remoteAliasService.getAliasesForCluster(expectedClusterName); + List 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 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 capturedCluster = EasyMock.newCapture(); + final Capture capturedAlias = EasyMock.newCapture(); + final Capture 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 aliases = remoteAliasService.getAliasesForCluster(expectedClusterName); + List 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 + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.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> aliases = new HashMap<>(); + private GatewayConfig config; + + @Override + public List 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 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 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 + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.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 getRemoteAliasServiceConfiguration() { + return Collections.emptyMap(); + } + + @Override public int getClusterMonitorPollingInterval(String type) { return 600; }