diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java index 5a7b4b52f48..94fdde9db84 100644 --- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java +++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java @@ -39,7 +39,7 @@ public class Geo3dShapeWGS84ModelRectRelationTest extends ShapeRectRelationTestC factory.planetModel = planetModel; this.ctx = factory.newSpatialContext(); this.maxRadius = 178; - ((Geo3dShapeFactory)ctx.getShapeFactory()).setCircleAccuracy(1e-6); + ((Geo3dShapeFactory)ctx.getShapeFactory()).setCircleAccuracy(1e-12); } @Test diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 72ea677605a..95a2bb7b6ad 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -80,6 +80,9 @@ New Features * SOLR-12139: The "eq" (equals) function query now works with string fields, string literals, and perhaps anything. (Andrey Kudryavtsev, David Smiley) + +* SOLR-10783: Add support for Hadoop Credential Provider as SSL/TLS store password source. + (Mano Kovacs via Mark Miller) Bug Fixes ---------------------- diff --git a/solr/bin/solr b/solr/bin/solr index 75e311e25fc..fd41acc3376 100755 --- a/solr/bin/solr +++ b/solr/bin/solr @@ -163,6 +163,11 @@ fi SOLR_URL_SCHEME=http SOLR_JETTY_CONFIG=() SOLR_SSL_OPTS="" + +if [ -n "$SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH" ]; then + SOLR_SSL_OPTS+=" -Dhadoop.security.credential.provider.path=$SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH" +fi + if [ -z "$SOLR_SSL_ENABLED" ]; then if [ -n "$SOLR_SSL_KEY_STORE" ]; then SOLR_SSL_ENABLED="true" # implicitly from earlier behaviour @@ -172,6 +177,7 @@ if [ -z "$SOLR_SSL_ENABLED" ]; then fi if [ "$SOLR_SSL_ENABLED" == "true" ]; then SOLR_JETTY_CONFIG+=("--module=https") + SOLR_JETTY_CONFIG+=("--lib=$DEFAULT_SERVER_DIR/solr-webapp/webapp/WEB-INF/lib/*") SOLR_URL_SCHEME=https if [ -n "$SOLR_SSL_KEY_STORE" ]; then SOLR_SSL_OPTS+=" -Dsolr.jetty.keystore=$SOLR_SSL_KEY_STORE" diff --git a/solr/bin/solr.cmd b/solr/bin/solr.cmd index 54e3f7da811..0aaeb1018f6 100644 --- a/solr/bin/solr.cmd +++ b/solr/bin/solr.cmd @@ -38,11 +38,17 @@ REM command line args IF "%SOLR_INCLUDE%"=="" set "SOLR_INCLUDE=%SOLR_TIP%\bin\solr.in.cmd" IF EXIST "%SOLR_INCLUDE%" CALL "%SOLR_INCLUDE%" +set "DEFAULT_SERVER_DIR=%SOLR_TIP%\server" + REM Select HTTP OR HTTPS related configurations set SOLR_URL_SCHEME=http set "SOLR_JETTY_CONFIG=--module=http" set "SOLR_SSL_OPTS= " +IF DEFINED SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH ( + set "SOLR_SSL_OPTS=!SOLR_SSL_OPTS! -Dhadoop.security.credential.provider.path=%SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH%" +) + IF NOT DEFINED SOLR_SSL_ENABLED ( IF DEFINED SOLR_SSL_KEY_STORE ( set "SOLR_SSL_ENABLED=true" @@ -50,8 +56,9 @@ IF NOT DEFINED SOLR_SSL_ENABLED ( set "SOLR_SSL_ENABLED=false" ) ) + IF "%SOLR_SSL_ENABLED%"=="true" ( - set "SOLR_JETTY_CONFIG=--module=https" + set "SOLR_JETTY_CONFIG=--lib="%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*" --module=https" set SOLR_URL_SCHEME=https IF DEFINED SOLR_SSL_KEY_STORE ( set "SOLR_SSL_OPTS=!SOLR_SSL_OPTS! -Dsolr.jetty.keystore=%SOLR_SSL_KEY_STORE%" @@ -182,8 +189,6 @@ IF !JAVA_MAJOR_VERSION! LSS 8 ( goto err ) -set "DEFAULT_SERVER_DIR=%SOLR_TIP%\server" - set FIRST_ARG=%1 IF [%1]==[] goto usage @@ -1008,7 +1013,7 @@ IF "%SCRIPT_CMD%"=="stop" ( set found_it=1 @echo Stopping Solr process %%N running on port %SOLR_PORT% IF "%STOP_PORT%"=="" set /A STOP_PORT=%SOLR_PORT% - 1000 - "%JAVA%" %SOLR_SSL_OPTS% -Djetty.home="%SOLR_SERVER_DIR%" -jar "%SOLR_SERVER_DIR%\start.jar" "%SOLR_JETTY_CONFIG%" STOP.PORT=!STOP_PORT! STOP.KEY=%STOP_KEY% --stop + "%JAVA%" %SOLR_SSL_OPTS% -Djetty.home="%SOLR_SERVER_DIR%" -jar "%SOLR_SERVER_DIR%\start.jar" %SOLR_JETTY_CONFIG% STOP.PORT=!STOP_PORT! STOP.KEY=%STOP_KEY% --stop del "%SOLR_TIP%"\bin\solr-%SOLR_PORT%.port timeout /T 5 REM Kill it if it is still running after the graceful shutdown @@ -1260,7 +1265,7 @@ IF "%FG%"=="1" ( -Dlog4j.configurationFile="%LOG4J_CONFIG%" -DSTOP.PORT=!STOP_PORT! -DSTOP.KEY=%STOP_KEY% ^ -Dsolr.solr.home="%SOLR_HOME%" -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%" ^ -Djetty.host=%SOLR_JETTY_HOST% -Djetty.port=%SOLR_PORT% -Djetty.home="%SOLR_SERVER_DIR%" ^ - -Djava.io.tmpdir="%SOLR_SERVER_DIR%\tmp" -jar start.jar "%SOLR_JETTY_CONFIG%" "%SOLR_JETTY_ADDL_CONFIG%" + -Djava.io.tmpdir="%SOLR_SERVER_DIR%\tmp" -jar start.jar %SOLR_JETTY_CONFIG% "%SOLR_JETTY_ADDL_CONFIG%" ) ELSE ( START /B "Solr-%SOLR_PORT%" /D "%SOLR_SERVER_DIR%" ^ "%JAVA%" %SERVEROPT% %SOLR_JAVA_MEM% %START_OPTS% ^ @@ -1268,7 +1273,7 @@ IF "%FG%"=="1" ( -Dsolr.log.muteconsole ^ -Dsolr.solr.home="%SOLR_HOME%" -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%" ^ -Djetty.host=%SOLR_JETTY_HOST% -Djetty.port=%SOLR_PORT% -Djetty.home="%SOLR_SERVER_DIR%" ^ - -Djava.io.tmpdir="%SOLR_SERVER_DIR%\tmp" -jar start.jar "%SOLR_JETTY_CONFIG%" "%SOLR_JETTY_ADDL_CONFIG%" > "!SOLR_LOGS_DIR!\solr-%SOLR_PORT%-console.log" + -Djava.io.tmpdir="%SOLR_SERVER_DIR%\tmp" -jar start.jar %SOLR_JETTY_CONFIG% "%SOLR_JETTY_ADDL_CONFIG%" > "!SOLR_LOGS_DIR!\solr-%SOLR_PORT%-console.log" echo %SOLR_PORT%>"%SOLR_TIP%"\bin\solr-%SOLR_PORT%.port REM now wait to see Solr come online ... diff --git a/solr/bin/solr.in.cmd b/solr/bin/solr.in.cmd index 0962510fe4b..a1771ad2458 100644 --- a/solr/bin/solr.in.cmd +++ b/solr/bin/solr.in.cmd @@ -119,6 +119,17 @@ REM set SOLR_SSL_CLIENT_TRUST_STORE= REM set SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD= REM set SOLR_SSL_CLIENT_TRUST_STORE_TYPE= +REM Sets path of Hadoop credential provider (hadoop.security.credential.provider.path property) and +REM enables usage of credential store. +REM Credential provider should store the following keys: +REM * solr.jetty.keystore.password +REM * solr.jetty.truststore.password +REM Set the two below if you want to set specific store passwords for HTTP client +REM * javax.net.ssl.keyStorePassword +REM * javax.net.ssl.trustStorePassword +REM More info: https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/CredentialProviderAPI.html +REM set SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH=localjceks://file/home/solr/hadoop-credential-provider.jceks + REM Settings for authentication REM Please configure only one of SOLR_AUTHENTICATION_CLIENT_BUILDER or SOLR_AUTH_TYPE parameters REM set SOLR_AUTHENTICATION_CLIENT_BUILDER=org.apache.solr.client.solrj.impl.PreemptiveBasicAuthClientBuilderFactory diff --git a/solr/bin/solr.in.sh b/solr/bin/solr.in.sh index 685882ade18..7cf6a8438cd 100644 --- a/solr/bin/solr.in.sh +++ b/solr/bin/solr.in.sh @@ -136,6 +136,17 @@ #SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD= #SOLR_SSL_CLIENT_TRUST_STORE_TYPE= +# Sets path of Hadoop credential provider (hadoop.security.credential.provider.path property) and +# enables usage of credential store. +# Credential provider should store the following keys: +# * solr.jetty.keystore.password +# * solr.jetty.truststore.password +# Set the two below if you want to set specific store passwords for HTTP client +# * javax.net.ssl.keyStorePassword +# * javax.net.ssl.trustStorePassword +# More info: https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/CredentialProviderAPI.html +#SOLR_HADOOP_CREDENTIAL_PROVIDER_PATH=localjceks://file/home/solr/hadoop-credential-provider.jceks + # Settings for authentication # Please configure only one of SOLR_AUTHENTICATION_CLIENT_BUILDER or SOLR_AUTH_TYPE parameters #SOLR_AUTHENTICATION_CLIENT_BUILDER="org.apache.solr.client.solrj.impl.PreemptiveBasicAuthClientBuilderFactory" diff --git a/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurations.java b/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurations.java index bfa518659bf..148167de006 100644 --- a/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurations.java +++ b/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurations.java @@ -18,7 +18,7 @@ package org.apache.solr.util.configuration; import java.lang.invoke.MethodHandles; -import java.util.Map; +import java.util.List; import org.apache.solr.common.StringUtils; import org.slf4j.Logger; @@ -28,48 +28,94 @@ import org.slf4j.LoggerFactory; * Dedicated object to handle Solr configurations */ public class SSLConfigurations { - private final Map envVars; - + public static final String DEFAULT_STORE_PASSWORD = "secret"; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - public static class SysProps { - public static final String SSL_KEY_STORE_PASSWORD = "javax.net.ssl.keyStorePassword"; - public static final String SSL_TRUST_STORE_PASSWORD = "javax.net.ssl.trustStorePassword"; - } + protected final List credentialProviders; - public static class EnvVars { - public static final String SOLR_SSL_CLIENT_KEY_STORE_PASSWORD = "SOLR_SSL_CLIENT_KEY_STORE_PASSWORD"; - public static final String SOLR_SSL_KEY_STORE_PASSWORD = "SOLR_SSL_KEY_STORE_PASSWORD"; - public static final String SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD = "SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD"; - public static final String SOLR_SSL_TRUST_STORE_PASSWORD = "SOLR_SSL_TRUST_STORE_PASSWORD"; + public static class SysProps { + public static final String SSL_KEY_STORE_PASSWORD = "solr.jetty.keystore.password"; + public static final String SSL_TRUST_STORE_PASSWORD = "solr.jetty.truststore.password"; + public static final String SSL_CLIENT_KEY_STORE_PASSWORD = "javax.net.ssl.keyStorePassword"; + public static final String SSL_CLIENT_TRUST_STORE_PASSWORD = "javax.net.ssl.trustStorePassword"; } /** - * @param envVars Map of environment variables to use + * @param sslCredentialProviderFactory Credential provider factory to use for providers */ - public SSLConfigurations(Map envVars) { - this.envVars = envVars; + public SSLConfigurations(SSLCredentialProviderFactory sslCredentialProviderFactory) { + credentialProviders = sslCredentialProviderFactory.getProviders(); } - /** Initiates javax.net.ssl.* system properties from the proper sources. */ + /** + * @param credentialProviders Explicit list of credential providers to use + */ + public SSLConfigurations(List credentialProviders) { + this.credentialProviders = credentialProviders; + } + + /** + * Initiates javax.net.ssl.* system properties from the proper sources. + */ public void init() { - String clientKeystorePassword = envVars.get(EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD); - String keystorePassword = envVars.get(EnvVars.SOLR_SSL_KEY_STORE_PASSWORD); + String clientKeystorePassword = getClientKeyStorePassword(); + String keystorePassword = getKeyStorePassword(); - String clientTruststorePassword = envVars.get(EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD); - String truststorePassword = envVars.get(EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD); + String clientTruststorePassword = getClientTrustStorePassword(); + String truststorePassword = getTrustStorePassword(); - if (isEmpty(System.getProperty(SysProps.SSL_KEY_STORE_PASSWORD)) + if (isEmpty(System.getProperty(SysProps.SSL_CLIENT_KEY_STORE_PASSWORD)) && !(isEmpty(clientKeystorePassword) && isEmpty(keystorePassword))) { - log.debug("Setting {} based on env var", SysProps.SSL_KEY_STORE_PASSWORD); - System.setProperty(SysProps.SSL_KEY_STORE_PASSWORD, clientKeystorePassword != null ? clientKeystorePassword : keystorePassword); + log.info("Setting {}", SysProps.SSL_CLIENT_KEY_STORE_PASSWORD); + System.setProperty(SysProps.SSL_CLIENT_KEY_STORE_PASSWORD, clientKeystorePassword != null ? clientKeystorePassword : keystorePassword); } - if (isEmpty(System.getProperty(SysProps.SSL_TRUST_STORE_PASSWORD)) + if (isEmpty(System.getProperty(SysProps.SSL_CLIENT_TRUST_STORE_PASSWORD)) && !(isEmpty(clientTruststorePassword) && isEmpty(truststorePassword))) { - log.debug("Setting {} based on env var", SysProps.SSL_TRUST_STORE_PASSWORD); - System.setProperty(SysProps.SSL_TRUST_STORE_PASSWORD, clientTruststorePassword != null ? clientTruststorePassword : truststorePassword); + log.info("Setting {}", SysProps.SSL_CLIENT_TRUST_STORE_PASSWORD); + System.setProperty(SysProps.SSL_CLIENT_TRUST_STORE_PASSWORD, clientTruststorePassword != null ? clientTruststorePassword : truststorePassword); } + + } + + /** + * @return password for keystore used for SSL connections + */ + public String getKeyStorePassword() { + String keyStorePassword = getPassword(SSLCredentialProvider.CredentialType.SSL_KEY_STORE_PASSWORD); + return keyStorePassword; + } + + /** + * @return password for truststore used for SSL connections + */ + public String getTrustStorePassword() { + String trustStorePassword = getPassword(SSLCredentialProvider.CredentialType.SSL_TRUST_STORE_PASSWORD); + return trustStorePassword; + } + + /** + * @return password for keystore used for SSL client connections + */ + public String getClientKeyStorePassword() { + String keyStorePassword = getPassword(SSLCredentialProvider.CredentialType.SSL_CLIENT_KEY_STORE_PASSWORD); + return keyStorePassword; + } + + /** + * @return password for truststore used for SSL client connections + */ + public String getClientTrustStorePassword() { + String trustStorePassword = getPassword(SSLCredentialProvider.CredentialType.SSL_CLIENT_TRUST_STORE_PASSWORD); + return trustStorePassword; + } + + protected String getPassword(SSLCredentialProvider.CredentialType type) { + for(SSLCredentialProvider provider: credentialProviders){ + String credential = provider.getCredential(type); + if(credential != null) return credential; + } + return null; } private boolean isEmpty(String str) { diff --git a/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurationsFactory.java b/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurationsFactory.java index 1da7c019dcf..80571ef2763 100644 --- a/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurationsFactory.java +++ b/solr/core/src/java/org/apache/solr/util/configuration/SSLConfigurationsFactory.java @@ -39,7 +39,7 @@ public class SSLConfigurationsFactory { } private static SSLConfigurations getInstance() { - return new SSLConfigurations(System.getenv()); + return new SSLConfigurations(new SSLCredentialProviderFactory()); } @VisibleForTesting diff --git a/solr/core/src/java/org/apache/solr/util/configuration/SSLCredentialProvider.java b/solr/core/src/java/org/apache/solr/util/configuration/SSLCredentialProvider.java new file mode 100644 index 00000000000..f714d28659d --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/configuration/SSLCredentialProvider.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.solr.util.configuration; + +/** + * Interface for different source of SSL configurations. + */ +public interface SSLCredentialProvider { + enum CredentialType { + SSL_KEY_STORE_PASSWORD, + SSL_TRUST_STORE_PASSWORD, + SSL_CLIENT_KEY_STORE_PASSWORD, + SSL_CLIENT_TRUST_STORE_PASSWORD + } + + /** + * @return Credential for the given credential type + */ + String getCredential(CredentialType type); + +} diff --git a/solr/core/src/java/org/apache/solr/util/configuration/SSLCredentialProviderFactory.java b/solr/core/src/java/org/apache/solr/util/configuration/SSLCredentialProviderFactory.java new file mode 100644 index 00000000000..1fcfd965ff6 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/configuration/SSLCredentialProviderFactory.java @@ -0,0 +1,93 @@ +/* + * 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.solr.util.configuration; + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import com.google.common.collect.ImmutableMap; +import org.apache.solr.util.configuration.providers.EnvSSLCredentialProvider; +import org.apache.solr.util.configuration.providers.HadoopSSLCredentialProvider; +import org.apache.solr.util.configuration.providers.SysPropSSLCredentialProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class responsible to build SSL credential providers + */ +public class SSLCredentialProviderFactory { + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static final String DEFAULT_PROVIDER_CHAIN = "env;sysprop"; + public static final String PROVIDER_CHAIN_KEY = "solr.ssl.credential.provider.chain"; + + private final static ImmutableMap defaultProviders = ImmutableMap.of( + "env", EnvSSLCredentialProvider.class, + "sysprop", SysPropSSLCredentialProvider.class, + "hadoop", HadoopSSLCredentialProvider.class + ); + + private String providerChain; + + public SSLCredentialProviderFactory() { + this.providerChain = System.getProperty(PROVIDER_CHAIN_KEY, DEFAULT_PROVIDER_CHAIN); + } + + public SSLCredentialProviderFactory(String providerChain) { + this.providerChain = providerChain; + } + + public List getProviders() { + ArrayList providers = new ArrayList<>(); + log.info(String.format(Locale.ROOT, "Processing SSL Credential Provider chain: %s", providerChain)); + String classPrefix = "class://"; + for (String provider : providerChain.split(";")) { + if (defaultProviders.containsKey(provider)) { + providers.add(getDefaultProvider(defaultProviders.get(provider))); + } else if (provider.startsWith(classPrefix)) { + providers.add(getProviderByClassName(provider.substring(classPrefix.length()))); + } else { + throw new RuntimeException("Unable to parse credential provider: " + provider); + } + } + return providers; + } + + private SSLCredentialProvider getProviderByClassName(String clazzName) { + try { + return (SSLCredentialProvider) Class.forName(clazzName).getConstructor().newInstance(); + } catch (InstantiationException | ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + String msg = String.format(Locale.ROOT, "Could not instantiate %s credential provider", clazzName); + log.error(msg); + throw new RuntimeException(msg, e); + } + } + + private SSLCredentialProvider getDefaultProvider(Class aClass) { + try { + return (SSLCredentialProvider) aClass.getConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + String msg = String.format(Locale.ROOT, "Could not instantiate %s credential provider", aClass.getName()); + log.error(msg); + throw new RuntimeException(msg, e); + } + } + +} diff --git a/solr/core/src/java/org/apache/solr/util/configuration/providers/AbstractSSLCredentialProvider.java b/solr/core/src/java/org/apache/solr/util/configuration/providers/AbstractSSLCredentialProvider.java new file mode 100644 index 00000000000..98251547e91 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/configuration/providers/AbstractSSLCredentialProvider.java @@ -0,0 +1,56 @@ +/* + * 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.solr.util.configuration.providers; + +import java.util.EnumMap; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import org.apache.solr.util.configuration.SSLCredentialProvider; + +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_CLIENT_KEY_STORE_PASSWORD; +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_CLIENT_TRUST_STORE_PASSWORD; +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_KEY_STORE_PASSWORD; +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_TRUST_STORE_PASSWORD; + +/** + * Abstract provider with default implementation + */ +abstract public class AbstractSSLCredentialProvider implements SSLCredentialProvider { + public static final EnumMap DEFAULT_CREDENTIAL_KEY_MAP = Maps.newEnumMap(ImmutableMap.of( + SSL_KEY_STORE_PASSWORD, "solr.jetty.keystore.password", + SSL_TRUST_STORE_PASSWORD, "solr.jetty.truststore.password", + SSL_CLIENT_KEY_STORE_PASSWORD, "javax.net.ssl.keyStorePassword", + SSL_CLIENT_TRUST_STORE_PASSWORD, "javax.net.ssl.trustStorePassword" + )); + private final EnumMap credentialKeyMap; + + public AbstractSSLCredentialProvider() { + credentialKeyMap = getCredentialKeyMap(); + } + + abstract protected String getCredential(String key); + + abstract protected EnumMap getCredentialKeyMap(); + + @Override + public String getCredential(CredentialType type) { + return getCredential(credentialKeyMap.get(type)); + } + +} diff --git a/solr/core/src/java/org/apache/solr/util/configuration/providers/EnvSSLCredentialProvider.java b/solr/core/src/java/org/apache/solr/util/configuration/providers/EnvSSLCredentialProvider.java new file mode 100644 index 00000000000..6641cfeee2f --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/configuration/providers/EnvSSLCredentialProvider.java @@ -0,0 +1,72 @@ +/* + * 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.solr.util.configuration.providers; + +import java.util.EnumMap; +import java.util.Map; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_CLIENT_KEY_STORE_PASSWORD; +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_CLIENT_TRUST_STORE_PASSWORD; +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_KEY_STORE_PASSWORD; +import static org.apache.solr.util.configuration.SSLCredentialProvider.CredentialType.SSL_TRUST_STORE_PASSWORD; + + +/** + * Environment variable based SSL configuration provider + */ +public class EnvSSLCredentialProvider extends AbstractSSLCredentialProvider { + + public static class EnvVars { + public static final String SOLR_SSL_CLIENT_KEY_STORE_PASSWORD = "SOLR_SSL_CLIENT_KEY_STORE_PASSWORD"; + public static final String SOLR_SSL_KEY_STORE_PASSWORD = "SOLR_SSL_KEY_STORE_PASSWORD"; + public static final String SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD = "SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD"; + public static final String SOLR_SSL_TRUST_STORE_PASSWORD = "SOLR_SSL_TRUST_STORE_PASSWORD"; + } + + private Map envVars; + + public EnvSSLCredentialProvider() { + this.envVars = System.getenv(); + } + + protected EnumMap getCredentialKeyMap() { + return Maps.newEnumMap(ImmutableMap.of( + SSL_KEY_STORE_PASSWORD, EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, + SSL_TRUST_STORE_PASSWORD, EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, + SSL_CLIENT_KEY_STORE_PASSWORD, EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, + SSL_CLIENT_TRUST_STORE_PASSWORD, EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD + )); + } + + protected String getCredential(String envKey) { + if (envVars.containsKey(envKey)) { + return envVars.get(envKey); + } else { + return null; + } + } + + @VisibleForTesting + public void setEnvVars(Map envVars) { + this.envVars = envVars; + } +} diff --git a/solr/core/src/java/org/apache/solr/util/configuration/providers/HadoopSSLCredentialProvider.java b/solr/core/src/java/org/apache/solr/util/configuration/providers/HadoopSSLCredentialProvider.java new file mode 100644 index 00000000000..37eb4324652 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/configuration/providers/HadoopSSLCredentialProvider.java @@ -0,0 +1,66 @@ +/* + * 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.solr.util.configuration.providers; + +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.util.EnumMap; + +import org.apache.hadoop.conf.Configuration; +import org.apache.solr.common.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.hadoop.security.alias.CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH; + +/** + * System property based SSL configuration provider + */ +public class HadoopSSLCredentialProvider extends AbstractSSLCredentialProvider { + + private Configuration hadoopConfigurationProvider; + + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + public HadoopSSLCredentialProvider() { + this(new Configuration()); + } + + public HadoopSSLCredentialProvider(Configuration hadoopConfigurationProvider) { + if (StringUtils.isEmpty(System.getProperty(CREDENTIAL_PROVIDER_PATH))) { + throw new RuntimeException("Cannot initialize Hadoop configuration provider without credential provider path. Use " + CREDENTIAL_PROVIDER_PATH + " system property to configure."); + } + this.hadoopConfigurationProvider = hadoopConfigurationProvider; + hadoopConfigurationProvider.set(CREDENTIAL_PROVIDER_PATH, System.getProperty(CREDENTIAL_PROVIDER_PATH)); + } + + @Override + protected EnumMap getCredentialKeyMap() { + return DEFAULT_CREDENTIAL_KEY_MAP; + } + + protected String getCredential(String keystoreKey) { + try { + char[] password = hadoopConfigurationProvider.getPassword(keystoreKey); + return password == null ? null : String.valueOf(password); + } catch (IOException e) { + log.error("Could not read password from Hadoop Credential Store: " + keystoreKey, e); + return null; + } + } +} diff --git a/solr/core/src/java/org/apache/solr/util/configuration/providers/SysPropSSLCredentialProvider.java b/solr/core/src/java/org/apache/solr/util/configuration/providers/SysPropSSLCredentialProvider.java new file mode 100644 index 00000000000..0a15a6927d7 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/configuration/providers/SysPropSSLCredentialProvider.java @@ -0,0 +1,38 @@ +/* + * 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.solr.util.configuration.providers; + +import java.util.EnumMap; + +/** + * System property based SSL configuration provider + */ +public class SysPropSSLCredentialProvider extends AbstractSSLCredentialProvider { + @Override + protected EnumMap getCredentialKeyMap() { + return DEFAULT_CREDENTIAL_KEY_MAP; + } + + protected String getCredential(String syspropKey) { + if (System.getProperty(syspropKey) != null) { + return System.getProperty(syspropKey); + } else { + return null; + } + } +} diff --git a/solr/core/src/java/org/apache/solr/util/configuration/providers/package-info.java b/solr/core/src/java/org/apache/solr/util/configuration/providers/package-info.java new file mode 100644 index 00000000000..7b5e8f85236 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/configuration/providers/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** + * TODO + */ +package org.apache.solr.util.configuration.providers; + + diff --git a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java index f6d0a383fc6..0f9221c6af8 100644 --- a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java +++ b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformerDistrib.java @@ -114,6 +114,7 @@ public class TestSubQueryTransformerDistrib extends SolrCloudTestCase { "rows","" + peopleMultiplier, "depts.q","{!terms f=dept_id_s v=$row.dept_ss_dv "+((random1.nextBoolean() ? "" : "separator=,"))+"}", "depts.fl","text_t"+(differentUniqueId?",id:notid":""), + "depts.sort", "dept_id_i desc", "depts.indent","true", "depts.collection","departments", differentUniqueId ? "depts.distrib.singlePass":"notnecessary","true", diff --git a/solr/core/src/test/org/apache/solr/util/configuration/SSLConfigurationsTest.java b/solr/core/src/test/org/apache/solr/util/configuration/SSLConfigurationsTest.java index a1d4696489a..29ad4b806a2 100644 --- a/solr/core/src/test/org/apache/solr/util/configuration/SSLConfigurationsTest.java +++ b/solr/core/src/test/org/apache/solr/util/configuration/SSLConfigurationsTest.java @@ -17,17 +17,27 @@ package org.apache.solr.util.configuration; +import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.apache.hadoop.conf.Configuration; import org.apache.lucene.util.TestRuleRestoreSystemProperties; +import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.util.configuration.providers.EnvSSLCredentialProvider; +import org.apache.solr.util.configuration.providers.HadoopSSLCredentialProvider; +import org.apache.solr.util.configuration.providers.SysPropSSLCredentialProvider; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; +import org.mockito.Mockito; +import static org.apache.hadoop.security.alias.CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; public class SSLConfigurationsTest { private Map envs; @@ -38,11 +48,16 @@ public class SSLConfigurationsTest { public static final String SAMPLE_PW3 = "pw789"; public static final String KEY_STORE_PASSWORD = SSLConfigurations.SysProps.SSL_KEY_STORE_PASSWORD; public static final String TRUST_STORE_PASSWORD = SSLConfigurations.SysProps.SSL_TRUST_STORE_PASSWORD; + public static final String CLIENT_KEY_STORE_PASSWORD = SSLConfigurations.SysProps.SSL_CLIENT_KEY_STORE_PASSWORD; + public static final String CLIENT_TRUST_STORE_PASSWORD = SSLConfigurations.SysProps.SSL_CLIENT_TRUST_STORE_PASSWORD; @Rule public TestRule syspropRestore = new TestRuleRestoreSystemProperties( SSLConfigurations.SysProps.SSL_KEY_STORE_PASSWORD, - SSLConfigurations.SysProps.SSL_TRUST_STORE_PASSWORD + SSLConfigurations.SysProps.SSL_TRUST_STORE_PASSWORD, + SSLConfigurations.SysProps.SSL_CLIENT_KEY_STORE_PASSWORD, + SSLConfigurations.SysProps.SSL_CLIENT_TRUST_STORE_PASSWORD, + CREDENTIAL_PROVIDER_PATH ); @Before @@ -50,72 +65,204 @@ public class SSLConfigurationsTest { envs = new HashMap<>(); } + private SSLConfigurations createSut(Configuration mockHadoopConfiguration) { + EnvSSLCredentialProvider envSSLCredentialProvider = new EnvSSLCredentialProvider(); + envSSLCredentialProvider.setEnvVars(envs); + sut = new SSLConfigurations(Arrays.asList( + new HadoopSSLCredentialProvider(mockHadoopConfiguration), + envSSLCredentialProvider, + new SysPropSSLCredentialProvider()) + ); + return sut; + } + private SSLConfigurations createSut() { - sut = new SSLConfigurations(envs); + EnvSSLCredentialProvider envSSLCredentialProvider = new EnvSSLCredentialProvider(); + envSSLCredentialProvider.setEnvVars(envs); + sut = new SSLConfigurations(Arrays.asList(envSSLCredentialProvider, new SysPropSSLCredentialProvider())); return sut; } @Test public void testSslConfigKeystorePwFromKeystoreEnvVar() { - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW1); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW1); createSut().init(); - assertThat(System.getProperty(KEY_STORE_PASSWORD), is(SAMPLE_PW1)); + assertThat(System.getProperty(CLIENT_KEY_STORE_PASSWORD), is(SAMPLE_PW1)); } @Test public void testSslConfigKeystorePwFromClientKeystoreEnvVar() { - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2); createSut().init(); - assertThat(System.getProperty(KEY_STORE_PASSWORD), is(SAMPLE_PW2)); + assertThat(System.getProperty(CLIENT_KEY_STORE_PASSWORD), is(SAMPLE_PW2)); } @Test public void testSslConfigKeystorePwFromBothEnvVars() { - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW1); - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW1); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2); createSut().init(); - assertThat(System.getProperty(KEY_STORE_PASSWORD), is(SAMPLE_PW2)); + assertThat(System.getProperty(CLIENT_KEY_STORE_PASSWORD), is(SAMPLE_PW2)); + } + + @Test + public void testSslConfigKeystorePwFromKeystoreHadoopCredentialProvider() throws IOException { + getSutWithMockedHadoopCredentialProvider(SSLConfigurations.SysProps.SSL_KEY_STORE_PASSWORD, SAMPLE_PW1) + .init(); + assertThat(System.getProperty(CLIENT_KEY_STORE_PASSWORD), is(SAMPLE_PW1)); + } + + @Test + public void testSslConfigKeystorePwFromClientKeystoreHadoopCredentialProvider() throws IOException { + getSutWithMockedHadoopCredentialProvider(SSLConfigurations.SysProps.SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2) + .init(); + assertThat(System.getProperty(CLIENT_KEY_STORE_PASSWORD), is(SAMPLE_PW2)); } @Test public void testSslConfigKeystorePwNotOverwrittenIfExists() { - System.setProperty(KEY_STORE_PASSWORD, SAMPLE_PW3); - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW1); - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2); + System.setProperty(CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW3); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW1); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2); createSut().init(); - assertThat(System.getProperty(KEY_STORE_PASSWORD), is(SAMPLE_PW3)); // unchanged + assertThat(System.getProperty(CLIENT_KEY_STORE_PASSWORD), is(SAMPLE_PW3)); // unchanged } @Test public void testSslConfigTruststorePwFromKeystoreEnvVar() { - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, SAMPLE_PW1); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, SAMPLE_PW1); createSut().init(); - assertThat(System.getProperty(TRUST_STORE_PASSWORD), is(SAMPLE_PW1)); + assertThat(System.getProperty(CLIENT_TRUST_STORE_PASSWORD), is(SAMPLE_PW1)); } @Test public void testSslConfigTruststorePwFromClientKeystoreEnvVar() { - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW2); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW2); createSut().init(); - assertThat(System.getProperty(TRUST_STORE_PASSWORD), is(SAMPLE_PW2)); + assertThat(System.getProperty(CLIENT_TRUST_STORE_PASSWORD), is(SAMPLE_PW2)); } @Test public void testSslConfigTruststorePwFromBothEnvVars() { - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, SAMPLE_PW1); - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW2); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, SAMPLE_PW1); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW2); createSut().init(); - assertThat(System.getProperty(TRUST_STORE_PASSWORD), is(SAMPLE_PW2)); + assertThat(System.getProperty(CLIENT_TRUST_STORE_PASSWORD), is(SAMPLE_PW2)); } @Test public void testSslConfigTruststorePwNotOverwrittenIfExists() { - System.setProperty(TRUST_STORE_PASSWORD, SAMPLE_PW3); - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, SAMPLE_PW1); - envs.put(SSLConfigurations.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW2); + System.setProperty(CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW3); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, SAMPLE_PW1); + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW2); createSut().init(); - assertThat(System.getProperty(TRUST_STORE_PASSWORD), is(SAMPLE_PW3)); // unchanged + assertThat(System.getProperty(CLIENT_TRUST_STORE_PASSWORD), is(SAMPLE_PW3)); // unchanged + } + + @Test + public void testGetKeyStorePasswordFromProperty() { + System.setProperty(KEY_STORE_PASSWORD, SAMPLE_PW1); + assertThat(createSut().getKeyStorePassword(), is(SAMPLE_PW1)); + } + + @Test + public void testGetKeyStorePasswordFromEnv() { + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW2); + assertThat(createSut().getKeyStorePassword(), is(SAMPLE_PW2)); + } + + @Test + public void testGetKeyStorePasswordFromHadoopCredentialProvider() throws IOException { + SSLConfigurations sut = getSutWithMockedHadoopCredentialProvider(SSLConfigurations.SysProps.SSL_KEY_STORE_PASSWORD, SAMPLE_PW3); + assertThat(sut.getKeyStorePassword(), is(SAMPLE_PW3)); + } + + + @Test + public void testGetTrustStorePasswordFromProperty() { + System.setProperty(TRUST_STORE_PASSWORD, SAMPLE_PW1); + assertThat(createSut().getTrustStorePassword(), is(SAMPLE_PW1)); + } + + @Test + public void testGetTrustStorePasswordFromEnv() { + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, SAMPLE_PW2); + assertThat(createSut().getTrustStorePassword(), is(SAMPLE_PW2)); + } + + @Test + public void testGetTruststorePasswordFromHadoopCredentialProvider() throws IOException { + SSLConfigurations sut = getSutWithMockedHadoopCredentialProvider(SSLConfigurations.SysProps.SSL_TRUST_STORE_PASSWORD, SAMPLE_PW3); + assertThat(sut.getTrustStorePassword(), is(SAMPLE_PW3)); + } + + @Test + public void testGetClientKeyStorePasswordFromProperty() { + System.setProperty(CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW1); + assertThat(createSut().getClientKeyStorePassword(), is(SAMPLE_PW1)); + } + + @Test + public void testGetClientKeyStorePasswordFromEnv() { + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW2); + assertThat(createSut().getClientKeyStorePassword(), is(SAMPLE_PW2)); + } + + @Test + public void testGetClientKeyStorePasswordFromHadoopCredentialProvider() throws IOException { + SSLConfigurations sut = getSutWithMockedHadoopCredentialProvider(SSLConfigurations.SysProps.SSL_CLIENT_KEY_STORE_PASSWORD, SAMPLE_PW3); + assertThat(sut.getClientKeyStorePassword(), is(SAMPLE_PW3)); + } + + + @Test + public void testGetClientTrustStorePasswordFromProperty() { + System.setProperty(CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW1); + assertThat(createSut().getClientTrustStorePassword(), is(SAMPLE_PW1)); + } + + @Test + public void testGetClientTrustStorePasswordFromEnv() { + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW2); + assertThat(createSut().getClientTrustStorePassword(), is(SAMPLE_PW2)); + } + + @Test + public void testGetClientTruststorePasswordFromHadoopCredentialProvider() throws IOException { + SSLConfigurations sut = getSutWithMockedHadoopCredentialProvider(SSLConfigurations.SysProps.SSL_CLIENT_TRUST_STORE_PASSWORD, SAMPLE_PW3); + assertThat(sut.getClientTrustStorePassword(), is(SAMPLE_PW3)); + } + + @Test + public void testSystemPropertyPriorityOverEnvVar() throws IOException { + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW2); + assertThat(createSut().getKeyStorePassword(), is(SAMPLE_PW2)); + System.setProperty(KEY_STORE_PASSWORD, SAMPLE_PW1); + assertThat(createSut().getKeyStorePassword(), is(SAMPLE_PW2)); + } + + @Test + public void testHadoopCredentialProviderPrioritySysPropAndEnvVars() throws IOException { + envs.put(EnvSSLCredentialProvider.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, SAMPLE_PW2); + assertThat(createSut().getKeyStorePassword(), is(SAMPLE_PW2)); + System.setProperty(KEY_STORE_PASSWORD, SAMPLE_PW1); + assertThat(createSut().getKeyStorePassword(), is(SAMPLE_PW2)); + SSLConfigurations sut = getSutWithMockedHadoopCredentialProvider(KEY_STORE_PASSWORD, SAMPLE_PW3); + assertThat(sut.getKeyStorePassword(), is(SAMPLE_PW3)); + } + + private SSLConfigurations getSutWithMockedHadoopCredentialProvider(String key, String pw) throws IOException { + Configuration mockHadoopConfiguration = getMockHadoopConfiguration(); + when(mockHadoopConfiguration.getPassword(key)) + .then(invocationOnMock -> invocationOnMock.getArguments()[0].equals(key) ? pw.toCharArray() : null); + System.setProperty(CREDENTIAL_PROVIDER_PATH, "/some/path"); // enables HCP + return createSut(mockHadoopConfiguration); + } + + private Configuration getMockHadoopConfiguration() { + SolrTestCaseJ4.assumeWorkingMockito(); + return Mockito.mock(Configuration.class); } } diff --git a/solr/core/src/test/org/apache/solr/util/configuration/SSLCredentialProviderFactoryTest.java b/solr/core/src/test/org/apache/solr/util/configuration/SSLCredentialProviderFactoryTest.java new file mode 100644 index 00000000000..21e7f8a594d --- /dev/null +++ b/solr/core/src/test/org/apache/solr/util/configuration/SSLCredentialProviderFactoryTest.java @@ -0,0 +1,90 @@ +/* + * 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.solr.util.configuration; + +import java.util.List; + +import org.apache.lucene.util.TestRuleRestoreSystemProperties; +import org.apache.solr.util.configuration.providers.EnvSSLCredentialProvider; +import org.apache.solr.util.configuration.providers.SysPropSSLCredentialProvider; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + */ +public class SSLCredentialProviderFactoryTest { + + @Rule + public TestRule syspropRestore = new TestRuleRestoreSystemProperties( + SSLCredentialProviderFactory.PROVIDER_CHAIN_KEY + ); + + @Test + public void testGetProvidersOrder() { + SSLCredentialProviderFactory sut = getSut("sysprop;env"); + List providers = sut.getProviders(); + assertThat(providers.get(0), is(SysPropSSLCredentialProvider.class)); + assertThat(providers.get(1), is(EnvSSLCredentialProvider.class)); + + sut = getSut("env;sysprop"); + providers = sut.getProviders(); + assertThat(providers.get(0), is(EnvSSLCredentialProvider.class)); + assertThat(providers.get(1), is(SysPropSSLCredentialProvider.class)); + } + + @Test + public void testGetProvidersWithCustomProvider() { + SSLCredentialProviderFactory sut = getSut("sysprop;class://" + CustomSSLCredentialProvider.class.getName() + ";env"); + List providers = sut.getProviders(); + assertThat(providers.get(0), is(SysPropSSLCredentialProvider.class)); + assertThat(providers.get(1), is(CustomSSLCredentialProvider.class)); + assertThat(providers.get(2), is(EnvSSLCredentialProvider.class)); + } + + @Test(expected = RuntimeException.class) + public void testGetProvidersInvalidProvider() { + getSut("sysprop;DoesNotExists").getProviders(); + } + + @Test + public void testGetProvidersBySysprop() { + String chain = "sysprop;class://" + CustomSSLCredentialProvider.class.getName() + ";env"; + System.setProperty(SSLCredentialProviderFactory.PROVIDER_CHAIN_KEY, chain); + SSLCredentialProviderFactory sut = new SSLCredentialProviderFactory(); + List providers = sut.getProviders(); + assertThat(providers.get(0), is(SysPropSSLCredentialProvider.class)); + assertThat(providers.get(1), is(CustomSSLCredentialProvider.class)); + assertThat(providers.get(2), is(EnvSSLCredentialProvider.class)); + } + + private SSLCredentialProviderFactory getSut(String providerChain) { + return new SSLCredentialProviderFactory(providerChain); + } + + static public class CustomSSLCredentialProvider implements SSLCredentialProvider { + @Override + public String getCredential(CredentialType type) { + return null; + } + } + +} diff --git a/solr/core/src/test/org/apache/solr/util/configuration/providers/EnvSSLCredentialProviderTest.java b/solr/core/src/test/org/apache/solr/util/configuration/providers/EnvSSLCredentialProviderTest.java new file mode 100644 index 00000000000..2b85e7daf81 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/util/configuration/providers/EnvSSLCredentialProviderTest.java @@ -0,0 +1,61 @@ +/* + * 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.solr.util.configuration.providers; + +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import org.apache.solr.util.configuration.SSLCredentialProvider; +import org.junit.Test; + +import static org.apache.solr.util.configuration.providers.AbstractSSLCredentialProvider.DEFAULT_CREDENTIAL_KEY_MAP; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + */ +public class EnvSSLCredentialProviderTest { + + @Test + public void testGetCredentials() throws Exception { + int cnt = 0; + Map envvars = ImmutableMap.of( + EnvSSLCredentialProvider.EnvVars.SOLR_SSL_KEY_STORE_PASSWORD, "pw" + ++cnt, + EnvSSLCredentialProvider.EnvVars.SOLR_SSL_TRUST_STORE_PASSWORD, "pw" + ++cnt, + EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_KEY_STORE_PASSWORD, "pw" + ++cnt, + EnvSSLCredentialProvider.EnvVars.SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD, "pw" + ++cnt + ); + EnvSSLCredentialProvider sut = new EnvSSLCredentialProvider(); + sut.setEnvVars(envvars); + cnt = 0; + for (Map.Entry set : DEFAULT_CREDENTIAL_KEY_MAP.entrySet()) { + String expectedpw = "pw" + ++cnt; + assertThat(sut.getCredential(set.getKey()), is(expectedpw)); + } + } + + @Test + public void testGetCredentialsWithEnvVars() throws Exception { + EnvSSLCredentialProvider sut = new EnvSSLCredentialProvider(); + // assuming not to fail + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_KEY_STORE_PASSWORD); + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_CLIENT_KEY_STORE_PASSWORD); + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_TRUST_STORE_PASSWORD); + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_CLIENT_TRUST_STORE_PASSWORD); + } +} diff --git a/solr/core/src/test/org/apache/solr/util/configuration/providers/HadoopSSLCredentialProviderTest.java b/solr/core/src/test/org/apache/solr/util/configuration/providers/HadoopSSLCredentialProviderTest.java new file mode 100644 index 00000000000..3a554a31540 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/util/configuration/providers/HadoopSSLCredentialProviderTest.java @@ -0,0 +1,74 @@ +/* + * 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.solr.util.configuration.providers; + +import java.io.IOException; +import java.util.Map; + +import org.apache.hadoop.conf.Configuration; +import org.apache.lucene.util.TestRuleRestoreSystemProperties; +import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.util.configuration.SSLCredentialProvider; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.mockito.Mockito; + +import static org.apache.hadoop.security.alias.CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH; +import static org.apache.solr.util.configuration.providers.AbstractSSLCredentialProvider.DEFAULT_CREDENTIAL_KEY_MAP; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; + +/** + */ +public class HadoopSSLCredentialProviderTest { + + @Rule + public TestRule syspropRestore = new TestRuleRestoreSystemProperties( + CREDENTIAL_PROVIDER_PATH + ); + + @Test(expected = RuntimeException.class) + public void testConstructorRequiresCredPath() { + new HadoopSSLCredentialProvider(getMockHadoopConfiguration()); + } + + @Test + public void testGetCredentials() throws Exception { + int cnt = 0; + for (Map.Entry set : DEFAULT_CREDENTIAL_KEY_MAP.entrySet()) { + String pw = "pw" + ++cnt; + HadoopSSLCredentialProvider sut = new HadoopSSLCredentialProvider(getMockedHadoopCredentialProvider(set.getValue(), pw)); + assertThat(sut.getCredential(set.getKey()), is(pw)); + } + } + + private Configuration getMockedHadoopCredentialProvider(String key, String pw) throws IOException { + Configuration mockHadoopConfiguration = getMockHadoopConfiguration(); + when(mockHadoopConfiguration.getPassword(key)) + .then(invocationOnMock -> invocationOnMock.getArguments()[0].equals(key) ? pw.toCharArray() : null); + System.setProperty(CREDENTIAL_PROVIDER_PATH, "/some/path"); // enables HCP + return mockHadoopConfiguration; + } + + private Configuration getMockHadoopConfiguration() { + SolrTestCaseJ4.assumeWorkingMockito(); + return Mockito.mock(Configuration.class); + } +} diff --git a/solr/core/src/test/org/apache/solr/util/configuration/providers/SysPropSSLCredentialProviderTest.java b/solr/core/src/test/org/apache/solr/util/configuration/providers/SysPropSSLCredentialProviderTest.java new file mode 100644 index 00000000000..4a5894d786b --- /dev/null +++ b/solr/core/src/test/org/apache/solr/util/configuration/providers/SysPropSSLCredentialProviderTest.java @@ -0,0 +1,66 @@ +/* + * 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.solr.util.configuration.providers; + +import java.util.Map; + +import org.apache.lucene.util.TestRuleRestoreSystemProperties; +import org.apache.solr.util.configuration.SSLConfigurations; +import org.apache.solr.util.configuration.SSLCredentialProvider; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; + +import static org.apache.solr.util.configuration.providers.AbstractSSLCredentialProvider.DEFAULT_CREDENTIAL_KEY_MAP; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + */ +public class SysPropSSLCredentialProviderTest { + + @Rule + public TestRule syspropRestore = new TestRuleRestoreSystemProperties( + SSLConfigurations.SysProps.SSL_KEY_STORE_PASSWORD, + SSLConfigurations.SysProps.SSL_TRUST_STORE_PASSWORD, + SSLConfigurations.SysProps.SSL_CLIENT_KEY_STORE_PASSWORD, + SSLConfigurations.SysProps.SSL_CLIENT_TRUST_STORE_PASSWORD + ); + + @Test + public void testGetCredentials() throws Exception { + int cnt = 0; + SysPropSSLCredentialProvider sut = new SysPropSSLCredentialProvider(); + for (Map.Entry set : DEFAULT_CREDENTIAL_KEY_MAP.entrySet()) { + String pw = "pw" + ++cnt; + System.setProperty(set.getValue(), pw); + assertThat(sut.getCredential(set.getKey()), is(pw)); + } + } + + + @Test + public void testGetCredentialsWithoutSetup() throws Exception { + SysPropSSLCredentialProvider sut = new SysPropSSLCredentialProvider(); + // assuming not to fail + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_KEY_STORE_PASSWORD); + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_CLIENT_KEY_STORE_PASSWORD); + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_TRUST_STORE_PASSWORD); + sut.getCredential(SSLCredentialProvider.CredentialType.SSL_CLIENT_TRUST_STORE_PASSWORD); + } +} diff --git a/solr/server/etc/jetty-ssl.xml b/solr/server/etc/jetty-ssl.xml index 741ac480788..cdbf57e6f8f 100644 --- a/solr/server/etc/jetty-ssl.xml +++ b/solr/server/etc/jetty-ssl.xml @@ -7,10 +7,14 @@ + + + + - + - + diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/CorrelationEvaluator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/CorrelationEvaluator.java index 866c5d0d207..ac6f2e22aaa 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/CorrelationEvaluator.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/CorrelationEvaluator.java @@ -118,7 +118,7 @@ public class CorrelationEvaluator extends RecursiveObjectEvaluator implements Ma realMatrix.setAttribute("corr", kendallsCorrelation); return realMatrix; } else if (type.equals(CorrelationType.spearmans)) { - SpearmansCorrelation spearmansCorrelation = new SpearmansCorrelation(new Array2DRowRealMatrix(data)); + SpearmansCorrelation spearmansCorrelation = new SpearmansCorrelation(new Array2DRowRealMatrix(data, false)); RealMatrix corrMatrix = spearmansCorrelation.getCorrelationMatrix(); double[][] corrMatrixData = corrMatrix.getData(); Matrix realMatrix = new Matrix(corrMatrixData); diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/DistanceEvaluator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/DistanceEvaluator.java index e82fc4cb6b5..47cc39a970e 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/DistanceEvaluator.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/eval/DistanceEvaluator.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Locale; import org.apache.commons.math3.linear.Array2DRowRealMatrix; -import org.apache.commons.math3.linear.RealMatrix; import org.apache.commons.math3.ml.distance.CanberraDistance; import org.apache.commons.math3.ml.distance.DistanceMeasure; import org.apache.commons.math3.ml.distance.EarthMoversDistance; @@ -136,9 +135,9 @@ public class DistanceEvaluator extends RecursiveObjectEvaluator implements ManyV private Matrix distance(DistanceMeasure distanceMeasure, Matrix matrix) { double[][] data = matrix.getData(); - RealMatrix realMatrix = new Array2DRowRealMatrix(data); - realMatrix = realMatrix.transpose(); - data = realMatrix.getData(); + Array2DRowRealMatrix realMatrix = new Array2DRowRealMatrix(data, false); + realMatrix = (Array2DRowRealMatrix)realMatrix.transpose(); + data = realMatrix.getDataRef(); double[][] distanceMatrix = new double[data.length][data.length]; for(int i=0; i vec = (List)o; double[][] data1 = new double[1][vec.size()]; for(int i=0; i sums = new ArrayList(data.length); + List sums = new ArrayList(data[0].length); - for(int i=0; i