/* ==================================================================
* ConfigurableSSLServiceTests.java - 2/04/2017 10:58:37 AM
*
* Copyright 2007-2017 SolarNetwork.net Dev Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
* ==================================================================
*/
package net.solarnetwork.support.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLSocketFactory;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import net.solarnetwork.pki.bc.BCCertificateService;
import net.solarnetwork.support.ConfigurableSSLService;
/**
* Unit tests for the {@link ConfigurableSSLService} class.
*
* @author matt
* @version 1.0
*/
public class ConfigurableSSLServiceTests {
private static final String TEST_KEY_STORE_PASSWORD = "secret!!";
private static final String TEST_KEY_STORE_PATH = "var/test-keystore.jks";
private static final String TEST_TRUST_STORE_PASSWORD = "trustme!";
private static final String TEST_TRUST_STORE_PATH = "var/test-truststore.jks";
private static final String TEST_CA_DN = "CN=Test CA, O=SolarTest";
private static final String TEST_CA_ALIAS = "ca";
private BCCertificateService certService;
private KeyPairGenerator keyPairGenerator;
private KeyPair caKeyPair;
private TestConfigurableSSLService service;
private static final class TestConfigurableSSLService extends ConfigurableSSLService {
private KeyStore getKeyStore() {
return loadKeyStore();
}
private KeyStore getTrustStore() {
return loadTrustStore();
}
}
@Before
public void setup() {
certService = new BCCertificateService();
try {
keyPairGenerator = KeyPairGenerator.getInstance("RSA");
} catch ( NoSuchAlgorithmException e ) {
throw new RuntimeException(e);
}
keyPairGenerator.initialize(2048, new SecureRandom());
deleteFile(TEST_KEY_STORE_PATH);
deleteFile(TEST_TRUST_STORE_PATH);
service = new TestConfigurableSSLService();
service.setKeyStorePassword(TEST_KEY_STORE_PASSWORD);
service.setTrustStorePassword(TEST_TRUST_STORE_PASSWORD);
service.setKeyStorePath(TEST_KEY_STORE_PATH);
service.setTrustStorePath(TEST_TRUST_STORE_PATH);
}
private static final void deleteFile(final String path) {
File f = new File(path);
if ( f.exists() ) {
f.delete();
}
}
protected KeyStore loadKeyStore(String keyStorePath, String passwd) {
File ksFile = new File(keyStorePath);
InputStream in = null;
try {
if ( ksFile.isFile() ) {
in = new BufferedInputStream(new FileInputStream(ksFile));
}
return ConfigurableSSLService.loadKeyStore(KeyStore.getDefaultType(), in, passwd);
} catch ( IOException e ) {
throw new RuntimeException("Error opening keystore file " + keyStorePath, e);
}
}
private void saveKeyStore(KeyStore keyStore, String keyStorePath, String passwd) {
if ( keyStore == null ) {
return;
}
File ksFile = new File(keyStorePath);
File ksDir = ksFile.getParentFile();
if ( !ksDir.isDirectory() && !ksDir.mkdirs() ) {
throw new RuntimeException("Unable to create KeyStore directory: " + ksFile.getParent());
}
try {
ConfigurableSSLService.saveKeyStore(keyStore, passwd,
new BufferedOutputStream(new FileOutputStream(ksFile)));
} catch ( IOException e ) {
throw new RuntimeException("Error saving keystore to " + ksFile.getPath(), e);
}
}
private void createCA(KeyStore keyStore, KeyStore trustStore) {
caKeyPair = keyPairGenerator.generateKeyPair();
X509Certificate cert = certService.generateCertificationAuthorityCertificate(TEST_CA_DN,
caKeyPair.getPublic(), caKeyPair.getPrivate());
try {
trustStore.setCertificateEntry(TEST_CA_ALIAS, cert);
keyStore.setKeyEntry(TEST_CA_ALIAS, caKeyPair.getPrivate(),
TEST_KEY_STORE_PASSWORD.toCharArray(), new Certificate[] { cert });
} catch ( KeyStoreException e ) {
throw new RuntimeException(e);
}
}
private void setupCA() {
KeyStore keyStore = loadKeyStore(TEST_KEY_STORE_PATH, TEST_KEY_STORE_PASSWORD);
KeyStore trustStore = loadKeyStore(TEST_TRUST_STORE_PATH, TEST_TRUST_STORE_PASSWORD);
createCA(keyStore, trustStore);
saveKeyStore(keyStore, TEST_KEY_STORE_PATH, TEST_KEY_STORE_PASSWORD);
saveKeyStore(trustStore, TEST_TRUST_STORE_PATH, TEST_TRUST_STORE_PASSWORD);
}
private void verifyCA() {
try {
KeyStore keyStore = service.getKeyStore();
Assert.assertNotNull("Service keystore", keyStore);
Key key = keyStore.getKey(TEST_CA_ALIAS, TEST_KEY_STORE_PASSWORD.toCharArray());
Assert.assertNotNull("CA private key", key);
Assert.assertTrue("CA key is PrivateKey", key instanceof PrivateKey);
Assert.assertArrayEquals("CA private key", caKeyPair.getPrivate().getEncoded(),
key.getEncoded());
keyStore = service.getTrustStore();
Assert.assertNotNull("Service truststore", keyStore);
Certificate cert = keyStore.getCertificate(TEST_CA_ALIAS);
Assert.assertNotNull("CA cert", cert);
Assert.assertArrayEquals("CA cert public key", caKeyPair.getPublic().getEncoded(),
cert.getPublicKey().getEncoded());
} catch ( GeneralSecurityException e ) {
throw new RuntimeException(e);
}
}
@Test
public void createContext() {
setupCA();
SSLSocketFactory sf = service.getSSLSocketFactory();
Assert.assertNotNull("SSLSocketFactory", sf);
verifyCA();
}
@Test
public void createSocketFactorySingleton() {
setupCA();
SSLSocketFactory sf = service.getSSLSocketFactory();
SSLSocketFactory sf2 = service.getSSLSocketFactory();
Assert.assertSame("SSLSocketFactory is a singleton", sf, sf2);
}
}