org.dataone.proto.trove.net.SocketFactoryManager.java Source code

Java tutorial

Introduction

Here is the source code for org.dataone.proto.trove.net.SocketFactoryManager.java

Source

/*
 * 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;

    }
}