From 9a32dd16bb216f8bf5ab7eed8d74a992b31a7fdd Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Wed, 14 Apr 2021 11:34:50 +0200 Subject: [PATCH] SEARCH-2802: HttpClientFactory integration with Search Services to support for Shared Secret communication. --- .../solr/lifecycle/SolrCoreLoadListener.java | 4 + .../SecretSharedPropertyCollector.java | 22 +++- .../alfresco-solrclient-lib/pom.xml | 2 +- .../solr/client/SOLRAPIClientFactory.java | 112 +++++++++++------- 4 files changed, 89 insertions(+), 51 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/lifecycle/SolrCoreLoadListener.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/lifecycle/SolrCoreLoadListener.java index fff070f6f..8f637e498 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/lifecycle/SolrCoreLoadListener.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/lifecycle/SolrCoreLoadListener.java @@ -45,6 +45,7 @@ import org.alfresco.solr.SolrInformationServer; import org.alfresco.solr.SolrKeyResourceLoader; import org.alfresco.solr.client.SOLRAPIClient; import org.alfresco.solr.client.SOLRAPIClientFactory; +import org.alfresco.solr.security.SecretSharedPropertyCollector; import org.alfresco.solr.tracker.AclTracker; import org.alfresco.solr.tracker.CascadeTracker; import org.alfresco.solr.tracker.CommitTracker; @@ -113,6 +114,9 @@ public class SolrCoreLoadListener extends AbstractSolrEventListener TrackerRegistry trackerRegistry = admin.getTrackerRegistry(); Properties coreProperties = new CoreDescriptorDecorator(core.getCoreDescriptor()).getProperties(); + + // Add secret shared properties if required, as they are passed as Java Environment Variables + coreProperties = SecretSharedPropertyCollector.completeCoreProperties(coreProperties); SolrResourceLoader loader = core.getLatestSchema().getResourceLoader(); SolrKeyResourceLoader keyResourceLoader = new SolrKeyResourceLoader(loader); diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java index 48503125d..559684572 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/security/SecretSharedPropertyCollector.java @@ -39,6 +39,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.alfresco.httpclient.HttpClientFactory; import org.alfresco.solr.AlfrescoSolrDataModel; import org.alfresco.solr.config.ConfigUtil; import org.apache.solr.core.SolrResourceLoader; @@ -61,9 +62,6 @@ public class SecretSharedPropertyCollector private static String SHARED_SECRET = "alfresco.secureComms.secret"; private static String SHARED_SECRET_HEADER = "alfresco.secureComms.secret.header"; - // Default request header value - private static final String DEFAULT_SHARED_SECRET_HEADER = "X-Alfresco-Search-Secret"; - // Save communication method as static value in order to improve performance private static String commsMethod; @@ -200,8 +198,24 @@ public class SecretSharedPropertyCollector } else { - return DEFAULT_SHARED_SECRET_HEADER; + return HttpClientFactory.DEFAULT_SHAREDSECRET_HEADER; } } + + /** + * Add secret shared properties to original core properties read from "solrcore.properties" + * @param properties Read properties from "solrcore.properties" + * @return when "secret" communication method is configured additional properties are set in original parameter + */ + public static Properties completeCoreProperties(Properties properties) + { + if (isCommsSecretShared()) + { + properties.setProperty(SECURE_COMMS_PROPERTY, getCommsMethod()); + properties.setProperty(SHARED_SECRET, getSecret()); + properties.setProperty(SHARED_SECRET_HEADER, getSecretHeader()); + } + return properties; + } } diff --git a/search-services/alfresco-solrclient-lib/pom.xml b/search-services/alfresco-solrclient-lib/pom.xml index a38cf92e3..360fb21f1 100644 --- a/search-services/alfresco-solrclient-lib/pom.xml +++ b/search-services/alfresco-solrclient-lib/pom.xml @@ -11,7 +11,7 @@ - 11.1 + 11.8 2.12.2 diff --git a/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClientFactory.java b/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClientFactory.java index 98afbac4e..3c081d177 100644 --- a/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClientFactory.java +++ b/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClientFactory.java @@ -52,8 +52,13 @@ public class SOLRAPIClientFactory */ private static Map clientsPerAlfresco = new HashMap<>(); - // encryption related parameters - private String secureCommsType; // "none", "https" + // http communication related parameters + private String secureCommsType; // "none", "https", "secret" + + // http + private String alfrescoHost; + private int alfrescoPort; + private String baseUrl; // ssl private String sslKeyStoreType; @@ -64,19 +69,21 @@ public class SOLRAPIClientFactory private String sslTrustStoreProvider; private String sslTrustStoreLocation; private String sslTrustStorePasswordFileLocation; - private String alfrescoHost; - private int alfrescoPort; private int alfrescoPortSSL; - private String baseUrl; - // http client + // secret shared + private String secret; + private String secretHeader; + + // http client settings private int maxTotalConnections = 40; private int maxHostConnections = 40; private int socketTimeout = 120000; - - public static void close() { - for(SOLRAPIClient client : clientsPerAlfresco.values()) { + public static void close() + { + for (SOLRAPIClient client : clientsPerAlfresco.values()) + { client.close(); } } @@ -131,12 +138,13 @@ public class SOLRAPIClientFactory * @param namespaceDAO allows retrieving and creating Namespace definitions * @return an instance of SOLRAPIClient */ - public SOLRAPIClient getSOLRAPIClient(Properties props, KeyResourceLoader keyResourceLoader, DictionaryService dictionaryService, NamespaceDAO namespaceDAO) + public SOLRAPIClient getSOLRAPIClient(Properties props, KeyResourceLoader keyResourceLoader, + DictionaryService dictionaryService, NamespaceDAO namespaceDAO) { if (Boolean.parseBoolean(System.getProperty("alfresco.test", "false"))) - { - return new SOLRAPIQueueClient(namespaceDAO); + { + return new SOLRAPIQueueClient(namespaceDAO); } alfrescoHost = props.getProperty("alfresco.host", "localhost"); @@ -150,20 +158,25 @@ public class SOLRAPIClientFactory baseUrl = props.getProperty("alfresco.baseUrl", "/alfresco"); // Load SSL settings only when using HTTPs protocol secureCommsType = props.getProperty("alfresco.secureComms", "none"); - if (secureCommsType.equals("https")) + if (SecureCommsType.getType(secureCommsType) == SecureCommsType.HTTPS) { sslKeyStoreType = getProperty(props, "alfresco.encryption.ssl.keystore.type", "JCEKS"); sslKeyStoreProvider = getProperty(props, "alfresco.encryption.ssl.keystore.provider", ""); sslKeyStoreLocation = getProperty(props, "alfresco.encryption.ssl.keystore.location", - "ssl.repo.client.keystore"); + "ssl.repo.client.keystore"); sslKeyStorePasswordFileLocation = getProperty(props, - "alfresco.encryption.ssl.keystore.passwordFileLocation", ""); + "alfresco.encryption.ssl.keystore.passwordFileLocation", ""); sslTrustStoreType = getProperty(props, "alfresco.encryption.ssl.truststore.type", "JCEKS"); sslTrustStoreProvider = getProperty(props, "alfresco.encryption.ssl.truststore.provider", ""); sslTrustStoreLocation = getProperty(props, "alfresco.encryption.ssl.truststore.location", - "ssl.repo.client.truststore"); + "ssl.repo.client.truststore"); sslTrustStorePasswordFileLocation = getProperty(props, - "alfresco.encryption.ssl.truststore.passwordFileLocation", ""); + "alfresco.encryption.ssl.truststore.passwordFileLocation", ""); + } + if (SecureCommsType.getType(secureCommsType) == SecureCommsType.SECRET) + { + secret = getProperty(props, "alfresco.secureComms.secret", ""); + secretHeader = getProperty(props, "alfresco.secureComms.secret.header", ""); } maxTotalConnections = Integer.parseInt(props.getProperty("alfresco.maxTotalConnections", "40")); maxHostConnections = Integer.parseInt(props.getProperty("alfresco.maxHostConnections", "40")); @@ -175,69 +188,76 @@ public class SOLRAPIClientFactory return client; } - + protected AlfrescoHttpClient getRepoClient(KeyResourceLoader keyResourceLoader) { HttpClientFactory httpClientFactory = null; - if (secureCommsType.equals("https")) + if (SecureCommsType.getType(secureCommsType) == SecureCommsType.HTTPS) { KeyStoreParameters keyStoreParameters = new KeyStoreParameters("ssl-keystore", "SSL Key Store", - sslKeyStoreType, sslKeyStoreProvider, sslKeyStorePasswordFileLocation, sslKeyStoreLocation); + sslKeyStoreType, sslKeyStoreProvider, sslKeyStorePasswordFileLocation, sslKeyStoreLocation); KeyStoreParameters trustStoreParameters = new KeyStoreParameters("ssl-truststore", "SSL Trust Store", - sslTrustStoreType, sslTrustStoreProvider, sslTrustStorePasswordFileLocation, sslTrustStoreLocation); + sslTrustStoreType, sslTrustStoreProvider, sslTrustStorePasswordFileLocation, + sslTrustStoreLocation); SSLEncryptionParameters sslEncryptionParameters = new SSLEncryptionParameters(keyStoreParameters, - trustStoreParameters); + trustStoreParameters); httpClientFactory = new HttpClientFactory(SecureCommsType.getType(secureCommsType), sslEncryptionParameters, - keyResourceLoader, null, null, alfrescoHost, alfrescoPort, alfrescoPortSSL, maxTotalConnections, - maxHostConnections, socketTimeout); + keyResourceLoader, null, null, null, null, alfrescoHost, alfrescoPort, alfrescoPortSSL, + maxTotalConnections, maxHostConnections, socketTimeout); } else { - httpClientFactory = new PlainHttpClientFactory(alfrescoHost, alfrescoPort, maxTotalConnections, - maxHostConnections, socketTimeout); + httpClientFactory = new PlainHttpClientFactory(secureCommsType, alfrescoHost, alfrescoPort, + maxTotalConnections, maxHostConnections, socketTimeout); + if (SecureCommsType.getType(secureCommsType) == SecureCommsType.SECRET) + { + httpClientFactory.setSharedSecret(secret); + httpClientFactory.setSharedSecretHeader(secretHeader); + } } AlfrescoHttpClient repoClient = httpClientFactory.getRepoClient(alfrescoHost, alfrescoPortSSL); + repoClient.setBaseUrl(baseUrl); return repoClient; - + } - + /** - * Return property value from system (passed as -D argument). - * If the system property does not exists, return local value from solrcore.properties + * Return property value from system (passed as -D argument). + * If the system property does not exists, return local value from solrcore.properties * If the local property does not exists, return default value * * @param props Local properties file (solrcore.properties) * @param key The property key * @return The value */ - private String getProperty(Properties props, String key, String defaultValue) + private String getProperty(Properties props, String key, String defaultValue) { - String value = System.getProperties().getProperty(key); - if (value == null) - { - value = props.getProperty(key); - } - if (value == null) - { - value = defaultValue; - } - return value; + String value = System.getProperties().getProperty(key); + if (value == null) + { + value = props.getProperty(key); + } + if (value == null) + { + value = defaultValue; + } + return value; } - + /** - * Local class to avoid loading sslEntryptionParameters for plain http connections. + * Local class to avoid loading sslEntryptionParameters for plain http connections. * * @author aborroy - * */ class PlainHttpClientFactory extends HttpClientFactory { - public PlainHttpClientFactory(String host, int port, int maxTotalConnections, int maxHostConnections, int socketTimeout) + public PlainHttpClientFactory(String secureCommsType, String host, int port, int maxTotalConnections, + int maxHostConnections, int socketTimeout) { - setSecureCommsType("none"); + setSecureCommsType(secureCommsType); setHost(host); setPort(port); setMaxTotalConnections(maxTotalConnections);