HADOOP-10658. SSLFactory expects truststores being configured. Contributed by Alejandro Abdelnur.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1599436 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Aaron Myers 2014-06-03 07:24:42 +00:00
parent f8a3041cfe
commit 53a0b3c496
4 changed files with 103 additions and 65 deletions

View File

@ -178,6 +178,8 @@ Release 2.5.0 - UNRELEASED
HADOOP-10630. Possible race condition in RetryInvocationHandler. (jing9) HADOOP-10630. Possible race condition in RetryInvocationHandler. (jing9)
HADOOP-10658. SSLFactory expects truststores being configured. (tucu via atm)
Release 2.4.1 - UNRELEASED Release 2.4.1 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -188,33 +188,33 @@ public class FileBasedKeyStoresFactory implements KeyStoresFactory {
String locationProperty = String locationProperty =
resolvePropertyName(mode, SSL_TRUSTSTORE_LOCATION_TPL_KEY); resolvePropertyName(mode, SSL_TRUSTSTORE_LOCATION_TPL_KEY);
String truststoreLocation = conf.get(locationProperty, ""); String truststoreLocation = conf.get(locationProperty, "");
if (truststoreLocation.isEmpty()) { if (!truststoreLocation.isEmpty()) {
throw new GeneralSecurityException("The property '" + locationProperty + String passwordProperty = resolvePropertyName(mode,
"' has not been set in the ssl configuration file."); SSL_TRUSTSTORE_PASSWORD_TPL_KEY);
String truststorePassword = conf.get(passwordProperty, "");
if (truststorePassword.isEmpty()) {
throw new GeneralSecurityException("The property '" + passwordProperty +
"' has not been set in the ssl configuration file.");
}
long truststoreReloadInterval =
conf.getLong(
resolvePropertyName(mode, SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY),
DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL);
LOG.debug(mode.toString() + " TrustStore: " + truststoreLocation);
trustManager = new ReloadingX509TrustManager(truststoreType,
truststoreLocation,
truststorePassword,
truststoreReloadInterval);
trustManager.init();
LOG.debug(mode.toString() + " Loaded TrustStore: " + truststoreLocation);
trustManagers = new TrustManager[]{trustManager};
} else {
LOG.warn("The property '" + locationProperty + "' has not been set, " +
"no TrustStore will be loaded");
trustManagers = null;
} }
String passwordProperty = resolvePropertyName(mode,
SSL_TRUSTSTORE_PASSWORD_TPL_KEY);
String truststorePassword = conf.get(passwordProperty, "");
if (truststorePassword.isEmpty()) {
throw new GeneralSecurityException("The property '" + passwordProperty +
"' has not been set in the ssl configuration file.");
}
long truststoreReloadInterval =
conf.getLong(
resolvePropertyName(mode, SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY),
DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL);
LOG.debug(mode.toString() + " TrustStore: " + truststoreLocation);
trustManager = new ReloadingX509TrustManager(truststoreType,
truststoreLocation,
truststorePassword,
truststoreReloadInterval);
trustManager.init();
LOG.debug(mode.toString() + " Loaded TrustStore: " + truststoreLocation);
trustManagers = new TrustManager[]{trustManager};
} }
/** /**

View File

@ -76,8 +76,8 @@ public class KeyStoreTestUtil {
* @throws GeneralSecurityException thrown if an Security error ocurred. * @throws GeneralSecurityException thrown if an Security error ocurred.
*/ */
public static X509Certificate generateCertificate(String dn, KeyPair pair, public static X509Certificate generateCertificate(String dn, KeyPair pair,
int days, String algorithm) int days, String algorithm)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
PrivateKey privkey = pair.getPrivate(); PrivateKey privkey = pair.getPrivate();
X509CertInfo info = new X509CertInfo(); X509CertInfo info = new X509CertInfo();
Date from = new Date(); Date from = new Date();
@ -92,7 +92,7 @@ public class KeyStoreTestUtil {
info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner)); info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic())); info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
info info
.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); .set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid); AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo)); info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
@ -103,30 +103,30 @@ public class KeyStoreTestUtil {
// Update the algorith, and resign. // Update the algorith, and resign.
algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG); algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG);
info info
.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, .set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM,
algo); algo);
cert = new X509CertImpl(info); cert = new X509CertImpl(info);
cert.sign(privkey, algorithm); cert.sign(privkey, algorithm);
return cert; return cert;
} }
public static KeyPair generateKeyPair(String algorithm) public static KeyPair generateKeyPair(String algorithm)
throws NoSuchAlgorithmException { throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm); KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
keyGen.initialize(1024); keyGen.initialize(1024);
return keyGen.genKeyPair(); return keyGen.genKeyPair();
} }
private static KeyStore createEmptyKeyStore() private static KeyStore createEmptyKeyStore()
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance("JKS"); KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null, null); // initialize ks.load(null, null); // initialize
return ks; return ks;
} }
private static void saveKeyStore(KeyStore ks, String filename, private static void saveKeyStore(KeyStore ks, String filename,
String password) String password)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
FileOutputStream out = new FileOutputStream(filename); FileOutputStream out = new FileOutputStream(filename);
try { try {
ks.store(out, password.toCharArray()); ks.store(out, password.toCharArray());
@ -136,18 +136,18 @@ public class KeyStoreTestUtil {
} }
public static void createKeyStore(String filename, public static void createKeyStore(String filename,
String password, String alias, String password, String alias,
Key privateKey, Certificate cert) Key privateKey, Certificate cert)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
KeyStore ks = createEmptyKeyStore(); KeyStore ks = createEmptyKeyStore();
ks.setKeyEntry(alias, privateKey, password.toCharArray(), ks.setKeyEntry(alias, privateKey, password.toCharArray(),
new Certificate[]{cert}); new Certificate[]{cert});
saveKeyStore(ks, filename, password); saveKeyStore(ks, filename, password);
} }
/** /**
* Creates a keystore with a single key and saves it to a file. * Creates a keystore with a single key and saves it to a file.
* *
* @param filename String file to save * @param filename String file to save
* @param password String store password to set on keystore * @param password String store password to set on keystore
* @param keyPassword String key password to set on key * @param keyPassword String key password to set on key
@ -158,27 +158,27 @@ public class KeyStoreTestUtil {
* @throws IOException if there is an I/O error saving the file * @throws IOException if there is an I/O error saving the file
*/ */
public static void createKeyStore(String filename, public static void createKeyStore(String filename,
String password, String keyPassword, String alias, String password, String keyPassword, String alias,
Key privateKey, Certificate cert) Key privateKey, Certificate cert)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
KeyStore ks = createEmptyKeyStore(); KeyStore ks = createEmptyKeyStore();
ks.setKeyEntry(alias, privateKey, keyPassword.toCharArray(), ks.setKeyEntry(alias, privateKey, keyPassword.toCharArray(),
new Certificate[]{cert}); new Certificate[]{cert});
saveKeyStore(ks, filename, password); saveKeyStore(ks, filename, password);
} }
public static void createTrustStore(String filename, public static void createTrustStore(String filename,
String password, String alias, String password, String alias,
Certificate cert) Certificate cert)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
KeyStore ks = createEmptyKeyStore(); KeyStore ks = createEmptyKeyStore();
ks.setCertificateEntry(alias, cert); ks.setCertificateEntry(alias, cert);
saveKeyStore(ks, filename, password); saveKeyStore(ks, filename, password);
} }
public static <T extends Certificate> void createTrustStore( public static <T extends Certificate> void createTrustStore(
String filename, String password, Map<String, T> certs) String filename, String password, Map<String, T> certs)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
KeyStore ks = createEmptyKeyStore(); KeyStore ks = createEmptyKeyStore();
for (Map.Entry<String, T> cert : certs.entrySet()) { for (Map.Entry<String, T> cert : certs.entrySet()) {
ks.setCertificateEntry(cert.getKey(), cert.getValue()); ks.setCertificateEntry(cert.getKey(), cert.getValue());
@ -187,7 +187,7 @@ public class KeyStoreTestUtil {
} }
public static void cleanupSSLConfig(String keystoresDir, String sslConfDir) public static void cleanupSSLConfig(String keystoresDir, String sslConfDir)
throws Exception { throws Exception {
File f = new File(keystoresDir + "/clientKS.jks"); File f = new File(keystoresDir + "/clientKS.jks");
f.delete(); f.delete();
f = new File(keystoresDir + "/serverKS.jks"); f = new File(keystoresDir + "/serverKS.jks");
@ -196,7 +196,7 @@ public class KeyStoreTestUtil {
f.delete(); f.delete();
f = new File(sslConfDir + "/ssl-client.xml"); f = new File(sslConfDir + "/ssl-client.xml");
f.delete(); f.delete();
f = new File(sslConfDir + "/ssl-server.xml"); f = new File(sslConfDir + "/ssl-server.xml");
f.delete(); f.delete();
} }
@ -205,22 +205,42 @@ public class KeyStoreTestUtil {
* SSLFactory. This includes keys, certs, keystores, truststores, the server * SSLFactory. This includes keys, certs, keystores, truststores, the server
* SSL configuration file, the client SSL configuration file, and the master * SSL configuration file, the client SSL configuration file, and the master
* configuration file read by the SSLFactory. * configuration file read by the SSLFactory.
* *
* @param keystoresDir String directory to save keystores * @param keystoresDir String directory to save keystores
* @param sslConfDir String directory to save SSL configuration files * @param sslConfDir String directory to save SSL configuration files
* @param conf Configuration master configuration to be used by an SSLFactory, * @param conf Configuration master configuration to be used by an SSLFactory,
* which will be mutated by this method * which will be mutated by this method
* @param useClientCert boolean true to make the client present a cert in the * @param useClientCert boolean true to make the client present a cert in the
* SSL handshake * SSL handshake
*/ */
public static void setupSSLConfig(String keystoresDir, String sslConfDir, public static void setupSSLConfig(String keystoresDir, String sslConfDir,
Configuration conf, boolean useClientCert) Configuration conf, boolean useClientCert) throws Exception {
setupSSLConfig(keystoresDir, sslConfDir, conf, useClientCert, true);
}
/**
* 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.
*
* @param keystoresDir String directory to save keystores
* @param sslConfDir String directory to save SSL configuration files
* @param conf Configuration master configuration to be used by an SSLFactory,
* which will be mutated by this method
* @param useClientCert boolean true to make the client present a cert in the
* SSL handshake
* @param trustStore boolean true to create truststore, false not to create it
*/
public static void setupSSLConfig(String keystoresDir, String sslConfDir,
Configuration conf, boolean useClientCert,
boolean trustStore)
throws Exception { throws Exception {
String clientKS = keystoresDir + "/clientKS.jks"; String clientKS = keystoresDir + "/clientKS.jks";
String clientPassword = "clientP"; String clientPassword = "clientP";
String serverKS = keystoresDir + "/serverKS.jks"; String serverKS = keystoresDir + "/serverKS.jks";
String serverPassword = "serverP"; String serverPassword = "serverP";
String trustKS = keystoresDir + "/trustKS.jks"; String trustKS = null;
String trustPassword = "trustP"; String trustPassword = "trustP";
File sslClientConfFile = new File(sslConfDir + "/ssl-client.xml"); File sslClientConfFile = new File(sslConfDir + "/ssl-client.xml");
@ -246,7 +266,10 @@ public class KeyStoreTestUtil {
sKP.getPrivate(), sCert); sKP.getPrivate(), sCert);
certs.put("server", sCert); certs.put("server", sCert);
KeyStoreTestUtil.createTrustStore(trustKS, trustPassword, certs); if (trustStore) {
trustKS = keystoresDir + "/trustKS.jks";
KeyStoreTestUtil.createTrustStore(trustKS, trustPassword, certs);
}
Configuration clientSSLConf = createClientSSLConfig(clientKS, clientPassword, Configuration clientSSLConf = createClientSSLConfig(clientKS, clientPassword,
clientPassword, trustKS); clientPassword, trustKS);

View File

@ -50,11 +50,12 @@ public class TestSSLFactory {
base.mkdirs(); base.mkdirs();
} }
private Configuration createConfiguration(boolean clientCert) private Configuration createConfiguration(boolean clientCert,
boolean trustStore)
throws Exception { throws Exception {
Configuration conf = new Configuration(); Configuration conf = new Configuration();
KeyStoreTestUtil.setupSSLConfig(KEYSTORES_DIR, sslConfsDir, conf, KeyStoreTestUtil.setupSSLConfig(KEYSTORES_DIR, sslConfsDir, conf,
clientCert); clientCert, trustStore);
return conf; return conf;
} }
@ -67,7 +68,7 @@ public class TestSSLFactory {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void clientMode() throws Exception { public void clientMode() throws Exception {
Configuration conf = createConfiguration(false); Configuration conf = createConfiguration(false, true);
SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf); SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
try { try {
sslFactory.init(); sslFactory.init();
@ -80,7 +81,7 @@ public class TestSSLFactory {
} }
private void serverMode(boolean clientCert, boolean socket) throws Exception { private void serverMode(boolean clientCert, boolean socket) throws Exception {
Configuration conf = createConfiguration(clientCert); Configuration conf = createConfiguration(clientCert, true);
SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.SERVER, conf); SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.SERVER, conf);
try { try {
sslFactory.init(); sslFactory.init();
@ -119,7 +120,7 @@ public class TestSSLFactory {
@Test @Test
public void validHostnameVerifier() throws Exception { public void validHostnameVerifier() throws Exception {
Configuration conf = createConfiguration(false); Configuration conf = createConfiguration(false, true);
conf.unset(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY); conf.unset(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY);
SSLFactory sslFactory = new SSLFactory sslFactory = new
SSLFactory(SSLFactory.Mode.CLIENT, conf); SSLFactory(SSLFactory.Mode.CLIENT, conf);
@ -157,7 +158,7 @@ public class TestSSLFactory {
@Test(expected = GeneralSecurityException.class) @Test(expected = GeneralSecurityException.class)
public void invalidHostnameVerifier() throws Exception { public void invalidHostnameVerifier() throws Exception {
Configuration conf = createConfiguration(false); Configuration conf = createConfiguration(false, true);
conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "foo"); conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "foo");
SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf); SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
try { try {
@ -169,7 +170,7 @@ public class TestSSLFactory {
@Test @Test
public void testConnectionConfigurator() throws Exception { public void testConnectionConfigurator() throws Exception {
Configuration conf = createConfiguration(false); Configuration conf = createConfiguration(false, true);
conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "STRICT_IE6"); conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "STRICT_IE6");
SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf); SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
try { try {
@ -275,7 +276,7 @@ public class TestSSLFactory {
@Test @Test
public void testNoClientCertsInitialization() throws Exception { public void testNoClientCertsInitialization() throws Exception {
Configuration conf = createConfiguration(false); Configuration conf = createConfiguration(false, true);
conf.unset(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY); conf.unset(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY);
SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf); SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
try { try {
@ -285,4 +286,16 @@ public class TestSSLFactory {
} }
} }
@Test
public void testNoTrustStore() throws Exception {
Configuration conf = createConfiguration(false, false);
conf.unset(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY);
SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.SERVER, conf);
try {
sslFactory.init();
} finally {
sslFactory.destroy();
}
}
} }