Java tutorial
/* * This work was created by participants in the DataONE project, and is * jointly copyrighted by participating institutions in DataONE. For * more information on DataONE, see our web site at http://dataone.org. * * Copyright 2014 * * Licensed 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.dataone.proto.trove.net; import java.io.*; import java.security.KeyManagementException; import java.security.KeyPair; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.SecureRandom; import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import javax.security.auth.x500.X500Principal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.conn.ssl.SSLSocketFactory; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMParser; import org.dataone.proto.trove.jsse.X509KeyManagerImpl; /** * * @author waltz */ public class SocketFactoryManager { private static Log log = LogFactory.getLog(SocketFactoryManager.class); // this can be set by caller if the default discovery mechanism is not applicable static private String clientCertificateLocation = null; // this should be configurable static private String certificateLocationDir = "/etc/dataone/client/certs"; // other variables private String keyStorePassword = "changeit"; private String keyStoreType = "JKS"; static FilenameFilter certificateFilter = new CertificateFilter(); static { File certsDirectory = new File(certificateLocationDir); if (certsDirectory.exists() && certsDirectory.isDirectory()) { File[] certificateFiles = certsDirectory.listFiles(certificateFilter); if (certificateFiles.length > 0) { if (certificateFiles.length > 1) { System.console().printf("Choose the number of the Certificate to use\n"); for (int i = 0; i < certificateFiles.length; ++i) { System.console().printf("%d)\t%s\n", i, certificateFiles[i].getName()); } String certSelection = System.console().readLine(); Integer certInteger; try { certInteger = Integer.parseInt(certSelection); } catch (NumberFormatException e) { throw new RuntimeException(e.getMessage()); } clientCertificateLocation = certificateFiles[certInteger].getAbsolutePath(); } else { clientCertificateLocation = certificateFiles[0].getAbsolutePath(); } } } } public SSLSocketFactory getSSLSocketFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeyManagementException, CertificateException, IOException { // our return object log.debug("Enter getSSLSocketFactory"); SSLSocketFactory socketFactory = null; KeyStore keyStore = null; // get the keystore that will provide the material // Catch the exception here so that the TLS connection scheme // will still be setup if the client certificate is not found. try { keyStore = getKeyStore(); } catch (FileNotFoundException e) { // these are somewhat expected for anonymous d1 client use log.warn( "Could not set up client side authentication - likely because the certificate could not be located: " + e.getMessage()); } // create SSL context SSLContext ctx = SSLContext.getInstance("TLS"); // use a very liberal trust manager for trusting the server // TODO: check server trust policy X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { log.info("checkClientTrusted - " + string); } public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { log.info("checkServerTrusted - " + string); } public X509Certificate[] getAcceptedIssuers() { log.info("getAcceptedIssuers"); return null; } }; // specify the client key manager KeyManager[] keyManagers = { new X509KeyManagerImpl(keyStore, keyStorePassword.toCharArray(), "cilogon") }; // KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); // keyManagerFactory.init(keyStore, keyStorePassword.toCharArray()); // keyManagers = keyManagerFactory.getKeyManagers(); // initialize the context ctx.init(keyManagers, new TrustManager[] { tm }, new SecureRandom()); socketFactory = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); return socketFactory; } /** * Load PEM file contents into in-memory keystore NOTE: this implementation uses Bouncy Castle security provider * * @return the keystore that will provide the material * @throws KeyStoreException * @throws CertificateException * @throws NoSuchAlgorithmException * @throws IOException */ private KeyStore getKeyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { // if the location has been set, use it KeyStore keyStore = null; Object pemObject = null; keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, keyStorePassword.toCharArray()); // get the private key and certificate from the PEM // TODO: find a way to do this with default Java provider (not Bouncy Castle)? Security.addProvider(new BouncyCastleProvider()); PEMParser pemReader = new PEMParser(new FileReader(clientCertificateLocation)); X509Certificate certificate = null; PrivateKey privateKey = null; KeyPair keyPair = null; while ((pemObject = pemReader.readObject()) != null) { if (pemObject instanceof PrivateKey) { privateKey = (PrivateKey) pemObject; } else if (pemObject instanceof KeyPair) { keyPair = (KeyPair) pemObject; privateKey = keyPair.getPrivate(); } else if (pemObject instanceof X509Certificate) { certificate = (X509Certificate) pemObject; } } if (certificate == null) { log.warn("Certificate is null"); } else { if (certificate.getSubjectX500Principal().getName(X500Principal.RFC2253) .equals(certificate.getIssuerX500Principal().getName(X500Principal.RFC2253))) { log.warn("Certificate is Self Signed"); } } Certificate[] chain = new Certificate[] { certificate }; // set the entry keyStore.setKeyEntry("cilogon", privateKey, keyStorePassword.toCharArray(), chain); return keyStore; } }