blob: cf1a98248db3c075027c7fdf11bb254d23a26572 [file] [log] [blame]
/*
* 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.taverna.security.credentialmanager.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManagerFactory;
import org.apache.taverna.security.credentialmanager.CMException;
import org.apache.taverna.security.credentialmanager.MasterPasswordProvider;
import org.apache.taverna.security.credentialmanager.TrustConfirmationProvider;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
//import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class HTTPSConnectionAndTrustConfirmationIT {
private static CredentialManagerImpl credentialManager;
private static DummyMasterPasswordProvider masterPasswordProvider;
private static File credentialManagerDirectory;
//private static URL trustedCertficateFileURL = HTTPSConnectionAndTrustConfirmationIT.class.getResource("/security/tomcat_heater_certificate.pem");
// Log4J Logger
//private static Logger logger = Logger.getLogger(HTTPSConnectionAndTrustConfirmationIT.class);
// public static void main(String[] args){
//
// try {
// CredentialManagerOld.initialiseSSL();
// //CredentialManager.getInstance();
// //HttpsURLConnection.setDefaultSSLSocketFactory(CredentialManager.createTavernaSSLSocketFactory());
// URL url = new URL ("https://rpc103.cs.man.ac.uk:8443/wsrf/services/cagrid/SecureHelloWorld?wsdl");
// HttpsURLConnection httpsConnection = (HttpsURLConnection) url.openConnection();
// // user should be asked automatically if they want to trust the connection
// httpsConnection.connect();
//
// } catch (CMException e) {
// logger.error("", e);
// } catch (MalformedURLException e) {
// logger.error("", e);
// } catch (IOException e) {
// logger.error("", e);
// }
// catch(Exception ex){ // anything we did not expect
// logger.error("", ex);
// }
//
// }
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
// Just in case, add the BouncyCastle provider
// It gets added from the CredentialManagerImpl constructor as well
// but we may need some crypto operations before we invoke the Cred. Manager
Security.addProvider(new BouncyCastleProvider());
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
try {
credentialManager = new CredentialManagerImpl();
} catch (CMException e) {
System.out.println(e.getStackTrace());
}
Random randomGenerator = new Random();
String credentialManagerDirectoryPath = System
.getProperty("java.io.tmpdir")
+ System.getProperty("file.separator")
+ "taverna-security-"
+ randomGenerator.nextInt(1000000);
System.out.println("Credential Manager's directory path: "
+ credentialManagerDirectoryPath);
credentialManagerDirectory = new File(credentialManagerDirectoryPath);
try {
credentialManager
.setConfigurationDirectoryPath(credentialManagerDirectory.toPath());
} catch (CMException e) {
System.out.println(e.getStackTrace());
}
// Create the dummy master password provider
masterPasswordProvider = new DummyMasterPasswordProvider();
masterPasswordProvider.setMasterPassword("uber");
List<MasterPasswordProvider> masterPasswordProviders = new ArrayList<MasterPasswordProvider>();
masterPasswordProviders.add(masterPasswordProvider);
credentialManager.setMasterPasswordProviders(masterPasswordProviders);
// Set an empty list for trust confirmation providers
credentialManager.setTrustConfirmationProviders(new ArrayList<TrustConfirmationProvider>());
}
@After
// Clean up the credentialManagerDirectory we created for testing
public void cleanUp() throws NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException{
// assertTrue(credentialManagerDirectory.exists());
// assertFalse(credentialManagerDirectory.listFiles().length == 0); // something was created there
if (credentialManagerDirectory.exists()){
try {
FileUtils.deleteDirectory(credentialManagerDirectory);
System.out.println("Deleting Credential Manager's directory: "
+ credentialManagerDirectory.getAbsolutePath());
} catch (IOException e) {
System.out.println(e.getStackTrace());
}
}
// Reset the SSLSocketFactory in JVM so we always have a clean start
SSLContext sc = null;
sc = SSLContext.getInstance("SSLv3");
// Create a "default" JSSE X509KeyManager.
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509",
"SunJSSE");
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null, null);
kmf.init(ks, "blah".toCharArray());
// Create a "default" JSSE X509TrustManager.
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
"SunX509", "SunJSSE");
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(null, null);
tmf.init(ts);
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
SSLContext.setDefault(sc);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
@Test
public void testTrustConfirmationProvidersTrustAlways() throws IOException, CMException {
// Initially trust provider list is empty, we only verify by what is in
// Credential Manager's Truststore (and it does not contains the certificate for https://heater.cs.man.ac.uk:7443/)
// Do not forget to initialise Taverna's/Credential Manager's SSLSocketFactory
credentialManager.initializeSSL();
URL url = new URL("https://heater.cs.man.ac.uk:7443/");
HttpsURLConnection conn;
conn = (HttpsURLConnection) url.openConnection();
try{
// This should fail
conn.connect();
fail("Connection to https://heater.cs.man.ac.uk:7443/ should be untrusted at this point.");
}
catch(SSLHandshakeException sslex){
// expected to fail so all is good
System.out.println(sslex.getStackTrace());
}
finally{
conn.disconnect();
}
// Add the trust confirmation provider that trusts everyone
List<TrustConfirmationProvider> trustProviders = new ArrayList<TrustConfirmationProvider>();
trustProviders.add(new TrustAlwaysTrustConfirmationProvider());
credentialManager.setTrustConfirmationProviders(trustProviders);
HttpsURLConnection conn2 = (HttpsURLConnection) url.openConnection();
// This should work now
conn2.connect();
System.out.println("Status header: "+ conn2.getHeaderField(0));
assertEquals("HTTP/1.1 200 OK", conn2.getHeaderField(0));
conn2.disconnect();
}
@Test
public void testTrustConfirmationProvidersTrustNever() throws IOException, CMException {
// Initially trust provider list is empty, we only verify by what is in
// Credential Manager's Truststore (and it does not contains the certificate for https://heater.cs.man.ac.uk:7443/)
// Do not forget to initialise Taverna's/Credential Manager's SSLSocketFactory
credentialManager.initializeSSL();
URL url = new URL("https://heater.cs.man.ac.uk:7443/");
HttpsURLConnection conn;
conn = (HttpsURLConnection) url.openConnection();
try{
// This should fail
conn.connect();
fail("Connection to https://heater.cs.man.ac.uk:7443/ should be untrusted at this point.");
}
catch(SSLHandshakeException sslex){
// expected to fail so all is good
}
finally{
conn.disconnect();
}
// Add the trust confirmation provider that trusts no one
List<TrustConfirmationProvider> trustProviders = new ArrayList<TrustConfirmationProvider>();
credentialManager.setTrustConfirmationProviders(trustProviders);
trustProviders = new ArrayList<TrustConfirmationProvider>();
trustProviders.add(new TrustNeverTrustConfimationProvider());
credentialManager.setTrustConfirmationProviders(trustProviders);
HttpsURLConnection conn2 = (HttpsURLConnection) url.openConnection();
try{
// This should still fail as our trust providers are not trusting anyone
// and we have not added heater's certificate to Credential Manager's Truststore
conn2.connect();
fail("Connection to https://heater.cs.man.ac.uk:7443/ should be untrusted at this point.");
}
catch(SSLHandshakeException sslex){
// expected to fail so all is good
}
finally{
conn2.disconnect();
}
}
@Test
public void testTrustConfirmationAddDeleteCertificateDirectly() throws CMException, IOException, CertificateException{
// Initially trust provider list is empty, we only verify by what is in
// Credential Manager's Truststore (and it does not contains the certificate for https://heater.cs.man.ac.uk:7443/)
// Do not forget to initialise Taverna's/Credential Manager's SSLSocketFactory
credentialManager.initializeSSL();
URL url = new URL("https://heater.cs.man.ac.uk:7443/");
HttpsURLConnection conn;
conn = (HttpsURLConnection) url.openConnection();
try{
// This should fail
conn.connect();
fail("Connection to https://heater.cs.man.ac.uk:7443/ should be untrusted at this point.");
}
catch(SSLHandshakeException sslex){
// expected to fail so all is good
}
finally{
conn.disconnect();
}
// Add heater's certificate directly to Credential Manager's Truststore
// Load the test trusted certificate (belonging to heater.cs.man.ac.uk)
X509Certificate trustedCertficate;
URL trustedCertficateFileURL = getClass().getResource("/security/tomcat_heater_certificate.pem");
System.out.println("testTrustConfirmationAddDeleteCertificateDirectly: trusted certficate file URL " + trustedCertficateFileURL);
File trustedCertFile = new File(trustedCertficateFileURL.getPath());
FileInputStream inStream = new FileInputStream(trustedCertFile);
//InputStream inStream = getClass().getClassLoader().getResourceAsStream("security/tomcat_heater_certificate.pem");
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
trustedCertficate = (X509Certificate) certFactory.generateCertificate(inStream);
try{
inStream.close();
}
catch (Exception e) {
// Ignore
}
String alias = credentialManager.addTrustedCertificate(trustedCertficate);
HttpsURLConnection conn2 = (HttpsURLConnection) url.openConnection();
// This should work now
conn2.connect();
//System.out.println(conn2.getHeaderField(0));
assertEquals("HTTP/1.1 200 OK", conn2.getHeaderField(0));
conn2.disconnect();
// Now remove certificate and see if the "trust" changes
credentialManager.deleteTrustedCertificate(alias);
HttpsURLConnection conn3;
conn3 = (HttpsURLConnection) url.openConnection();
try{
// This should fail
conn3.connect();
fail("Connection to https://heater.cs.man.ac.uk:7443/ should be untrusted at this point.");
}
catch(SSLHandshakeException sslex){
// expected to fail so all is good
}
finally{
conn3.disconnect();
}
}
}