HADOOP-16727. KMS Jetty server does not startup if trust store password is null.

This commit is contained in:
Hanisha Koneru 2020-01-07 15:46:14 -08:00
parent d1f5976c00
commit a7fccc1122
5 changed files with 366 additions and 59 deletions

View File

@ -545,17 +545,23 @@ private ServerConnector createHttpsChannelConnector(
SslContextFactory.Server sslContextFactory =
new SslContextFactory.Server();
sslContextFactory.setNeedClientAuth(needsClientAuth);
if (keyPassword != null) {
sslContextFactory.setKeyManagerPassword(keyPassword);
}
if (keyStore != null) {
sslContextFactory.setKeyStorePath(keyStore);
sslContextFactory.setKeyStoreType(keyStoreType);
if (keyStorePassword != null) {
sslContextFactory.setKeyStorePassword(keyStorePassword);
}
}
if (trustStore != null) {
sslContextFactory.setTrustStorePath(trustStore);
sslContextFactory.setTrustStoreType(trustStoreType);
if (trustStorePassword != null) {
sslContextFactory.setTrustStorePassword(trustStorePassword);
}
}
if(null != excludeCiphers && !excludeCiphers.isEmpty()) {
sslContextFactory.setExcludeCipherSuites(
StringUtils.getTrimmedStrings(excludeCiphers));

View File

@ -62,16 +62,15 @@ public class TestSSLHttpServer extends HttpServerFunctionalTest {
LoggerFactory.getLogger(TestSSLHttpServer.class);
private static final String HTTPS_CIPHER_SUITES_KEY = "https.cipherSuites";
private static final String JAVAX_NET_DEBUG_KEY = "javax.net.debug";
private static final String SSL_SERVER_KEYSTORE_PROP_PREFIX = "ssl.server" +
".keystore";
private static final String SSL_SERVER_TRUSTSTORE_PROP_PREFIX = "ssl.server" +
static final String SSL_SERVER_KEYSTORE_PROP_PREFIX = "ssl.server.keystore";
static final String SSL_SERVER_TRUSTSTORE_PROP_PREFIX = "ssl.server" +
".truststore";
private static final String SERVLET_NAME_LONGHEADER = "longheader";
private static final String SERVLET_PATH_LONGHEADER =
static final String SERVLET_NAME_LONGHEADER = "longheader";
static final String SERVLET_PATH_LONGHEADER =
"/" + SERVLET_NAME_LONGHEADER;
private static final String SERVLET_NAME_ECHO = "echo";
private static final String SERVLET_PATH_ECHO = "/" + SERVLET_NAME_ECHO;
static final String SERVLET_NAME_ECHO = "echo";
static final String SERVLET_PATH_ECHO = "/" + SERVLET_NAME_ECHO;
private static HttpServer2 server;
private static String keystoreDir;
@ -79,7 +78,7 @@ public class TestSSLHttpServer extends HttpServerFunctionalTest {
private static SSLFactory clientSslFactory;
private static String cipherSuitesPropertyValue;
private static String sslDebugPropertyValue;
private static final String EXCLUDED_CIPHERS =
static final String EXCLUDED_CIPHERS =
"TLS_ECDHE_RSA_WITH_RC4_128_SHA,"
+ "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, \n"
+ "SSL_RSA_WITH_DES_CBC_SHA,"
@ -98,7 +97,7 @@ public class TestSSLHttpServer extends HttpServerFunctionalTest {
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA,\t\n "
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
private static final String INCLUDED_PROTOCOLS = "SSLv2Hello,TLSv1.1";
static final String INCLUDED_PROTOCOLS = "SSLv2Hello,TLSv1.1";
@BeforeClass
public static void setup() throws Exception {
@ -166,7 +165,7 @@ public static void cleanup() throws Exception {
* This ensures that the value https.cipherSuites does
* not affect the result of tests.
*/
private static void storeHttpsCipherSuites() {
static void storeHttpsCipherSuites() {
String cipherSuites = System.getProperty(HTTPS_CIPHER_SUITES_KEY);
if (cipherSuites != null) {
LOG.info(
@ -177,7 +176,7 @@ private static void storeHttpsCipherSuites() {
System.clearProperty(HTTPS_CIPHER_SUITES_KEY);
}
private static void restoreHttpsCipherSuites() {
static void restoreHttpsCipherSuites() {
if (cipherSuitesPropertyValue != null) {
LOG.info("Restoring property {} to value: {}", HTTPS_CIPHER_SUITES_KEY,
cipherSuitesPropertyValue);
@ -186,7 +185,7 @@ private static void restoreHttpsCipherSuites() {
}
}
private static void turnOnSSLDebugLogging() {
static void turnOnSSLDebugLogging() {
String sslDebug = System.getProperty(JAVAX_NET_DEBUG_KEY);
if (sslDebug != null) {
sslDebugPropertyValue = sslDebug;
@ -194,7 +193,7 @@ private static void turnOnSSLDebugLogging() {
System.setProperty(JAVAX_NET_DEBUG_KEY, "all");
}
private static void restoreSSLDebugLogging() {
static void restoreSSLDebugLogging() {
if (sslDebugPropertyValue != null) {
System.setProperty(JAVAX_NET_DEBUG_KEY, sslDebugPropertyValue);
sslDebugPropertyValue = null;

View File

@ -0,0 +1,266 @@
/**
* 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.hadoop.http;
import com.google.common.base.Supplier;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
import org.apache.hadoop.security.ssl.SSLFactory;
import org.apache.hadoop.test.GenericTestUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.apache.hadoop.http.TestSSLHttpServer.EXCLUDED_CIPHERS;
import static org.apache.hadoop.http.TestSSLHttpServer.INCLUDED_PROTOCOLS;
import static org.apache.hadoop.http.TestSSLHttpServer.SSL_SERVER_KEYSTORE_PROP_PREFIX;
import static org.apache.hadoop.http.TestSSLHttpServer.SSL_SERVER_TRUSTSTORE_PROP_PREFIX;
import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.CLIENT_KEY_STORE_PASSWORD_DEFAULT;
import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.SERVER_KEY_STORE_PASSWORD_DEFAULT;
import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.TRUST_STORE_PASSWORD_DEFAULT;
/**
* Test suit for testing KeyStore and TrustStore password settings.
*/
public class TestSSLHttpServerConfigs {
private static final String BASEDIR =
GenericTestUtils.getTempPath(TestSSLHttpServer.class.getSimpleName());
private static Configuration conf;
private static Configuration sslConf;
private static String keystoreDir;
private static String sslConfDir;
private static final String SERVER_PWD = SERVER_KEY_STORE_PASSWORD_DEFAULT;
private static final String CLIENT_PWD = CLIENT_KEY_STORE_PASSWORD_DEFAULT;
private static final String TRUST_STORE_PWD = TRUST_STORE_PASSWORD_DEFAULT;
@Before
public void start() throws Exception {
TestSSLHttpServer.turnOnSSLDebugLogging();
TestSSLHttpServer.storeHttpsCipherSuites();
conf = new Configuration();
conf.setInt(HttpServer2.HTTP_MAX_THREADS_KEY, 10);
File base = new File(BASEDIR);
FileUtil.fullyDelete(base);
base.mkdirs();
keystoreDir = new File(BASEDIR).getAbsolutePath();
sslConfDir = KeyStoreTestUtil.getClasspathDir(TestSSLHttpServer.class);
}
@After
public void shutdown() throws Exception {
FileUtil.fullyDelete(new File(BASEDIR));
KeyStoreTestUtil.cleanupSSLConfig(keystoreDir, sslConfDir);
TestSSLHttpServer.restoreHttpsCipherSuites();
TestSSLHttpServer.restoreSSLDebugLogging();
}
/**
* Setup KeyStore and TrustStore with given passwords.
*/
private void setupKeyStores(String serverPassword,
String clientPassword, String trustStorePassword) throws Exception {
KeyStoreTestUtil.setupSSLConfig(keystoreDir, sslConfDir, conf, false, true,
EXCLUDED_CIPHERS, serverPassword, clientPassword, trustStorePassword);
sslConf = KeyStoreTestUtil.getSslConfig();
sslConf.set(SSLFactory.SSL_ENABLED_PROTOCOLS_KEY, INCLUDED_PROTOCOLS);
conf.set(SSLFactory.SSL_ENABLED_PROTOCOLS_KEY, INCLUDED_PROTOCOLS);
}
/**
* Build HttpServer2 using the given passwords to access KeyStore/ TrustStore.
*/
private HttpServer2 setupServer(String keyStoreKeyPassword,
String keyStorePassword, String trustStorePassword) throws Exception {
HttpServer2 server = new HttpServer2.Builder().setName("test")
.addEndpoint(new URI("https://localhost")).setConf(conf)
.keyPassword(keyStoreKeyPassword)
.keyStore(sslConf.get(SSL_SERVER_KEYSTORE_PROP_PREFIX + ".location"),
keyStorePassword,
sslConf.get(SSL_SERVER_KEYSTORE_PROP_PREFIX + ".type", "jks"))
.trustStore(
sslConf.get(SSL_SERVER_TRUSTSTORE_PROP_PREFIX + ".location"),
trustStorePassword,
sslConf.get(SSL_SERVER_TRUSTSTORE_PROP_PREFIX + ".type", "jks"))
.excludeCiphers(sslConf.get("ssl.server.exclude.cipher.list")).build();
return server;
}
/**
* Test if HttpServer2 start succeeds in validating KeyStore/ TrustStore
* using the given passowords.
*/
private void testServerStart(String keyStoreKeyPassword,
String keyStorePassword, String trustStorePassword) throws Exception {
HttpServer2 server = setupServer(keyStoreKeyPassword, keyStorePassword,
trustStorePassword);
try {
server.start();
GenericTestUtils.waitFor(new Supplier<Boolean>() {
@Override
public Boolean get() {
return server.isAlive();
}
}, 200, 100000);
} finally {
server.stop();
}
}
@Test(timeout=120000)
public void testServerSetup() throws Exception {
setupKeyStores(SERVER_PWD, CLIENT_PWD, TRUST_STORE_PWD);
testServerStart(SERVER_PWD, SERVER_PWD, TRUST_STORE_PWD);
}
@Test(timeout=120000)
public void testServerSetupWithoutTrustPassword() throws Exception {
setupKeyStores(SERVER_PWD, CLIENT_PWD, TRUST_STORE_PWD);
testServerStart(SERVER_PWD, SERVER_PWD, null);
}
@Test(timeout=120000)
public void testServerSetupWithoutKeyStorePassword() throws Exception {
setupKeyStores(SERVER_PWD, CLIENT_PWD, TRUST_STORE_PWD);
testServerStart(SERVER_PWD, null, null);
}
@Test(timeout=120000)
public void testServerSetupWithoutKeyStoreKeyPassword() throws Exception {
setupKeyStores(SERVER_PWD, CLIENT_PWD, TRUST_STORE_PWD);
testServerStart(null, SERVER_PWD, null);
}
@Test(timeout=120000)
public void testServerSetupWithNoKeyStorePassword() throws Exception {
setupKeyStores(SERVER_PWD, CLIENT_PWD, TRUST_STORE_PWD);
// Accessing KeyStore without either of KeyStore.KeyPassword or KeyStore
// .password should fail.
try {
testServerStart(null, null, null);
Assert.fail("Server should have failed to start without any " +
"KeyStore password.");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Problem starting http server",
e);
}
}
@Test(timeout=120000)
public void testServerSetupWithWrongKeyStorePassword() throws Exception {
setupKeyStores(SERVER_PWD, CLIENT_PWD, TRUST_STORE_PWD);
// Accessing KeyStore with wrong keyStore password/ keyPassword should fail.
try {
testServerStart(SERVER_PWD, "wrongPassword", null);
Assert.fail("Server should have failed to start with wrong " +
"KeyStore password.");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Keystore was tampered with, " +
"or password was incorrect", e);
}
try {
testServerStart("wrongPassword", SERVER_PWD, null);
Assert.fail("Server should have failed to start with wrong " +
"KeyStore password.");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Problem starting http server",
e);
GenericTestUtils.assertExceptionContains("Cannot recover key",
e.getCause());
}
}
@Test(timeout=120000)
public void testKeyStoreSetupWithoutTrustStorePassword() throws Exception {
// Setup TrustStore without TrustStore password
setupKeyStores(SERVER_PWD, CLIENT_PWD, "");
// Accessing TrustStore without password (null password) should succeed
testServerStart(SERVER_PWD, SERVER_PWD, null);
// Accessing TrustStore with wrong password (even if password is not
// set) should fail.
try {
testServerStart(SERVER_PWD, SERVER_PWD, "wrongPassword");
Assert.fail("Server should have failed to start with wrong " +
"TrustStore password.");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Keystore was tampered with, " +
"or password was incorrect", e);
}
}
@Test(timeout=120000)
public void testKeyStoreSetupWithoutKeyStorePassword() throws Exception {
// Setup KeyStore without KeyStore password
setupKeyStores(SERVER_PWD, "", TRUST_STORE_PWD);
// Accessing KeyStore without password (null password) should succeed
testServerStart(SERVER_PWD, null, TRUST_STORE_PWD);
// Accessing KeyStore with wrong password (even if password is not
// set) should fail.
try {
testServerStart(SERVER_PWD, "wrongPassword", TRUST_STORE_PWD);
Assert.fail("Server should have failed to start with wrong " +
"KeyStore password.");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Keystore was tampered with, " +
"or password was incorrect", e);
}
}
@Test(timeout=120000)
public void testKeyStoreSetupWithoutPassword() throws Exception {
// Setup KeyStore without any password
setupKeyStores("", "", "");
// Accessing KeyStore with either one of KeyStore.Password or KeyStore
// .KeyPassword as empty string should pass. If the password is null, it
// is not set in SSLContextFactory while setting up the server.
testServerStart("", null, null);
testServerStart(null, "", null);
try {
testServerStart(null, null, null);
Assert.fail("Server should have failed to start without " +
"KeyStore password.");
} catch (IOException e) {
GenericTestUtils.assertExceptionContains("Problem starting http server",
e);
GenericTestUtils.assertExceptionContains("Password must not be null",
e.getCause());
}
}
}

View File

@ -68,6 +68,10 @@
public class KeyStoreTestUtil {
public final static String SERVER_KEY_STORE_PASSWORD_DEFAULT = "serverP";
public final static String CLIENT_KEY_STORE_PASSWORD_DEFAULT = "clientP";
public final static String TRUST_STORE_PASSWORD_DEFAULT = "trustP";
public static String getClasspathDir(Class klass) throws Exception {
String file = klass.getName();
file = file.replace('.', '/') + ".class";
@ -272,15 +276,42 @@ public static void setupSSLConfig(String keystoresDir, String sslConfDir,
* @throws Exception
*/
public static void setupSSLConfig(String keystoresDir, String sslConfDir,
Configuration conf, boolean useClientCert,
boolean trustStore, String excludeCiphers)
throws Exception {
Configuration conf, boolean useClientCert, boolean trustStore,
String excludeCiphers) throws Exception {
setupSSLConfig(keystoresDir, sslConfDir, conf, useClientCert, trustStore,
excludeCiphers, SERVER_KEY_STORE_PASSWORD_DEFAULT,
CLIENT_KEY_STORE_PASSWORD_DEFAULT, TRUST_STORE_PASSWORD_DEFAULT);
}
/**
* Performs complete setup of SSL configuration in preparation for testing an
* SSLFactory. This includes keys, certs, keystores, truststores, the server
* SSL configuration file, the client SSL configuration file, and the master
* configuration file read by the SSLFactory and the passwords required to
* access the keyStores (Server and Client KeyStore Passwords and
* TrustStore Password).
*
* @param keystoresDir
* @param sslConfDir
* @param conf
* @param useClientCert
* @param trustStore
* @param excludeCiphers
* @param serverPassword
* @param clientPassword
* @param trustPassword
* @throws Exception
*/
@SuppressWarnings("checkstyle:parameternumber")
public static void setupSSLConfig(String keystoresDir, String sslConfDir,
Configuration conf, boolean useClientCert, boolean trustStore,
String excludeCiphers, String serverPassword, String clientPassword,
String trustPassword) throws Exception {
String clientKS = keystoresDir + "/clientKS.jks";
String clientPassword = "clientP";
String serverKS = keystoresDir + "/serverKS.jks";
String serverPassword = "serverP";
String trustKS = null;
String trustPassword = "trustP";
File sslClientConfFile = new File(sslConfDir, getClientSSLConfigFileName());
File sslServerConfFile = new File(sslConfDir, getServerSSLConfigFileName());
@ -310,10 +341,10 @@ public static void setupSSLConfig(String keystoresDir, String sslConfDir,
KeyStoreTestUtil.createTrustStore(trustKS, trustPassword, certs);
}
Configuration clientSSLConf = createClientSSLConfig(clientKS, clientPassword,
clientPassword, trustKS, excludeCiphers);
Configuration serverSSLConf = createServerSSLConfig(serverKS, serverPassword,
serverPassword, trustKS, excludeCiphers);
Configuration clientSSLConf = createClientSSLConfig(clientKS,
clientPassword, clientPassword, trustKS, trustPassword, excludeCiphers);
Configuration serverSSLConf = createServerSSLConfig(serverKS,
serverPassword, serverPassword, trustKS, trustPassword, excludeCiphers);
saveConfig(sslClientConfFile, clientSSLConf);
saveConfig(sslServerConfFile, serverSSLConf);
@ -336,9 +367,10 @@ public static void setupSSLConfig(String keystoresDir, String sslConfDir,
* @return Configuration for client SSL
*/
public static Configuration createClientSSLConfig(String clientKS,
String password, String keyPassword, String trustKS) {
String password, String keyPassword, String trustKS,
String trustPassword) {
return createSSLConfig(SSLFactory.Mode.CLIENT,
clientKS, password, keyPassword, trustKS, "");
clientKS, password, keyPassword, trustKS, trustPassword, "");
}
/**
@ -354,9 +386,10 @@ public static Configuration createClientSSLConfig(String clientKS,
* @return Configuration for client SSL
*/
public static Configuration createClientSSLConfig(String clientKS,
String password, String keyPassword, String trustKS, String excludeCiphers) {
String password, String keyPassword, String trustKS,
String trustPassword, String excludeCiphers) {
return createSSLConfig(SSLFactory.Mode.CLIENT,
clientKS, password, keyPassword, trustKS, excludeCiphers);
clientKS, password, keyPassword, trustKS, trustPassword, excludeCiphers);
}
/**
@ -372,9 +405,10 @@ public static Configuration createClientSSLConfig(String clientKS,
* @throws java.io.IOException
*/
public static Configuration createServerSSLConfig(String serverKS,
String password, String keyPassword, String trustKS) throws IOException {
String password, String keyPassword, String trustKS, String trustPassword)
throws IOException {
return createSSLConfig(SSLFactory.Mode.SERVER,
serverKS, password, keyPassword, trustKS, "");
serverKS, password, keyPassword, trustKS, trustPassword, "");
}
/**
@ -391,9 +425,10 @@ public static Configuration createServerSSLConfig(String serverKS,
* @throws IOException
*/
public static Configuration createServerSSLConfig(String serverKS,
String password, String keyPassword, String trustKS, String excludeCiphers) throws IOException {
String password, String keyPassword, String trustKS, String trustPassword,
String excludeCiphers) throws IOException {
return createSSLConfig(SSLFactory.Mode.SERVER,
serverKS, password, keyPassword, trustKS, excludeCiphers);
serverKS, password, keyPassword, trustKS, trustPassword, excludeCiphers);
}
/**
@ -445,8 +480,8 @@ private static String getSSLConfigFileName(String base) {
* @return Configuration for SSL
*/
private static Configuration createSSLConfig(SSLFactory.Mode mode,
String keystore, String password, String keyPassword, String trustKS, String excludeCiphers) {
String trustPassword = "trustP";
String keystore, String password, String keyPassword, String trustKS,
String trustStorePwd, String excludeCiphers) {
Configuration sslConf = new Configuration(false);
if (keystore != null) {
@ -466,10 +501,10 @@ private static Configuration createSSLConfig(SSLFactory.Mode mode,
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_LOCATION_TPL_KEY), trustKS);
}
if (trustPassword != null) {
if (trustStorePwd != null) {
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_PASSWORD_TPL_KEY),
trustPassword);
trustStorePwd);
}
if(null != excludeCiphers && !excludeCiphers.isEmpty()) {
sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,

View File

@ -17,6 +17,7 @@
*/
package org.apache.hadoop.security.ssl;
import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.TRUST_STORE_PASSWORD_DEFAULT;
import static org.junit.Assert.assertTrue;
import org.apache.hadoop.conf.Configuration;
@ -407,7 +408,7 @@ private void checkSSLFactoryInitWithPasswords(SSLFactory.Mode mode,
String keystore = new File(KEYSTORES_DIR, "keystore.jks").getAbsolutePath();
String truststore = new File(KEYSTORES_DIR, "truststore.jks")
.getAbsolutePath();
String trustPassword = "trustP";
String trustPassword = TRUST_STORE_PASSWORD_DEFAULT;
// Create keys, certs, keystore, and truststore.
KeyPair keyPair = KeyStoreTestUtil.generateKeyPair("RSA");
@ -433,7 +434,7 @@ private void checkSSLFactoryInitWithPasswords(SSLFactory.Mode mode,
if (mode == SSLFactory.Mode.SERVER) {
sslConfFileName = "ssl-server.xml";
sslConf = KeyStoreTestUtil.createServerSSLConfig(keystore, confPassword,
confKeyPassword, truststore);
confKeyPassword, truststore, trustPassword);
if (useCredProvider) {
File testDir = GenericTestUtils.getTestDir();
final Path jksPath = new Path(testDir.toString(), "test.jks");
@ -444,7 +445,7 @@ private void checkSSLFactoryInitWithPasswords(SSLFactory.Mode mode,
} else {
sslConfFileName = "ssl-client.xml";
sslConf = KeyStoreTestUtil.createClientSSLConfig(keystore, confPassword,
confKeyPassword, truststore);
confKeyPassword, truststore, trustPassword);
}
KeyStoreTestUtil.saveConfig(new File(sslConfsDir, sslConfFileName), sslConf);