diff --git a/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java index de5ef58..d2bd20a 100644 --- a/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java +++ b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java @@ -280,15 +280,18 @@ public int run(String[] args) throws Exception { } } - private void setTlsIfNeccessary(Builder builder, Configuration conf) throws Exception { + //@VisibleForTesting + void setTlsIfNeccessary(Builder builder, Configuration conf) throws Exception { final boolean useTls = getConf().getBoolean(QueryServerProperties.QUERY_SERVER_TLS_ENABLED, QueryServerOptions.DEFAULT_QUERY_SERVER_TLS_ENABLED); if(useTls) { final String tlsKeystore = getConf().get(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE); final String keystoreType = getConf().get(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE_TYPE_KEY, QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE_TYPE_DEFAULT); - final String tlsKeystorePassword = getConf().get(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE_PASSWORD, QueryServerOptions.DEFAULT_QUERY_SERVER_TLS_KEYSTORE_PASSWORD); + final char[] tlsKeystorePasswordChars = getConf().getPassword(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE_PASSWORD); + final String tlsKeystorePassword = tlsKeystorePasswordChars != null ? new String(tlsKeystorePasswordChars) : QueryServerOptions.DEFAULT_QUERY_SERVER_TLS_KEYSTORE_PASSWORD; final String tlsTruststore = getConf().get(QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE); - final String tlsTruststorePassword = getConf().get(QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE_PASSWORD, QueryServerOptions.DEFAULT_QUERY_SERVER_TLS_TRUSTSTORE_PASSWORD); + final char[] tlsTruststorePasswordChars = getConf().getPassword(QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE_PASSWORD); + final String tlsTruststorePassword = tlsTruststorePasswordChars != null ? new String(tlsTruststorePasswordChars) : QueryServerOptions.DEFAULT_QUERY_SERVER_TLS_TRUSTSTORE_PASSWORD; if(tlsKeystore == null) { throw new Exception(String.format("if %s is enabled, %s must be specfified" , QueryServerProperties.QUERY_SERVER_TLS_ENABLED, QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE)); } diff --git a/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java index a28dba4..312054a 100644 --- a/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java +++ b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java @@ -17,9 +17,7 @@ */ package org.apache.phoenix.queryserver.server; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -35,6 +33,9 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.alias.CredentialProvider; +import org.apache.hadoop.security.alias.CredentialProviderFactory; +import org.apache.phoenix.queryserver.QueryServerOptions; import org.apache.phoenix.queryserver.QueryServerProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.io.TempDir; @@ -86,6 +87,73 @@ public void testCustomServerConfiguration() { verify(builder, never()).withImpersonation(any(DoAsRemoteUserCallback.class)); } + @Test + public void testTlsPasswordsResolvedFromCredentialProvider() throws Exception { + File jceks = new File(testFolder.toFile(), "pqs.jceks"); + Configuration conf = HBaseConfiguration.create(); + conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, + "jceks://" + jceks.getAbsolutePath()); + + CredentialProvider provider = CredentialProviderFactory.getProviders(conf).get(0); + provider.createCredentialEntry( + QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE_PASSWORD, "ksSecret".toCharArray()); + provider.createCredentialEntry( + QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE_PASSWORD, "tsSecret".toCharArray()); + provider.flush(); + + conf.setBoolean(QueryServerProperties.QUERY_SERVER_TLS_ENABLED, true); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE, jceks.getAbsolutePath()); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE, jceks.getAbsolutePath()); + + QueryServer qs = new QueryServer(new String[0], conf); + qs.setTlsIfNeccessary(builder, conf); + + verify(builder).withTLS( + any(File.class), eq("ksSecret"), + any(File.class), eq("tsSecret"), + anyString(), + nullable(String[].class), + nullable(String[].class)); + } + + @Test + public void testTlsPasswordsFallBackToPlaintextConfig() throws Exception { + File dummy = new File(testFolder.toFile(), "dummy.jsk"); + Configuration conf = HBaseConfiguration.create(); + + conf.setBoolean(QueryServerProperties.QUERY_SERVER_TLS_ENABLED, true); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE, dummy.getAbsolutePath()); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE, dummy.getAbsolutePath()); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE_PASSWORD, "ksPlain"); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE_PASSWORD, "tsPlain"); + + QueryServer qs = new QueryServer(new String[0], conf); + qs.setTlsIfNeccessary(builder, conf); + + verify(builder).withTLS( + any(File.class), eq("ksPlain"), + any(File.class), eq("tsPlain"), + anyString(), nullable(String[].class), nullable(String[].class)); + } + + @Test + public void testTlsPasswordsUseDefaultsWhenNoProvider() throws Exception { + File dummyStore = new File(testFolder.toFile(), "dummy.keystore"); + Configuration conf = HBaseConfiguration.create(); + + conf.setBoolean(QueryServerProperties.QUERY_SERVER_TLS_ENABLED, true); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_KEYSTORE, dummyStore.getAbsolutePath()); + conf.set(QueryServerProperties.QUERY_SERVER_TLS_TRUSTSTORE, dummyStore.getAbsolutePath()); + + QueryServer qs = new QueryServer(new String[0], conf); + qs.setTlsIfNeccessary(builder, conf); + + verify(builder).withTLS( + any(File.class), eq(QueryServerOptions.DEFAULT_QUERY_SERVER_TLS_KEYSTORE_PASSWORD), + any(File.class), eq(QueryServerOptions.DEFAULT_QUERY_SERVER_TLS_TRUSTSTORE_PASSWORD), + anyString(), nullable(String[].class), nullable(String[].class)); + } + private void setupKeytabForSpnego() throws IOException { File keytabFile = testFolder.resolve("test.keytab").toFile(); CONF.set(QueryServerProperties.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB, keytabFile.getAbsolutePath());