com.adito.server.jetty.CustomJsseListener.java Source code

Java tutorial

Introduction

Here is the source code for com.adito.server.jetty.CustomJsseListener.java

Source

/*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package com.adito.server.jetty;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.security.KeyStore;
import java.security.SecureRandom;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mortbay.http.JsseListener;
import org.mortbay.util.InetAddrPort;

import com.adito.boot.ContextHolder;
import com.adito.boot.ContextKey;
import com.adito.boot.KeyStoreManager;
import com.adito.boot.PropertyList;
import com.adito.server.CustomKeyManager;

/**
 * Extension to Jettys {@link org.mortbay.http.JsseListener} that loads
 * its SSL keys from Aditos keystore using the password that has been
 * configured in the property database.
 */
public class CustomJsseListener extends JsseListener {
    private String keyPassword;
    private TrustManager trustManager;
    private boolean initialised;
    private boolean require = false;
    private boolean configureContext = true;
    private static boolean createAvailableCipherSuitesList = true;
    final static Log log = LogFactory.getLog(CustomJsseListener.class);

    /**
     * Constructor
     *
     * @param keyPassword key password
     */
    public CustomJsseListener(String keyPassword) {
        super();
        init(keyPassword);
    }

    /**
     * Constructor
     *
     * @param address address and port on which to listen
     * @param keyPassword key password
     */
    public CustomJsseListener(InetAddrPort address, String keyPassword) {
        super(address);
        init(keyPassword);
    }

    private void init(String keyPassword) {
        this.keyPassword = keyPassword;
    }

    /**
     * Set the trust manager to use. This must be done <b>before</b> the
     * socket factory is initialised (i.e. when Jetty is started). If the
     * method is not called the default trust managers will be used.
     *
     * @param trustManager trustManager
     * @throws IllegalStateException if the Jetty has already been started
     *
     */
    public void setTrustManager(TrustManager trustManager, boolean require) {
        if (initialised) {
            throw new IllegalStateException("Socket factory already created. Cannot set trust manager.");
        }
        this.trustManager = trustManager;
        this.require = require;

    }

    protected ServerSocket newServerSocket(InetAddrPort p_address, int p_acceptQueueSize) throws IOException {
        SSLServerSocket serverSocket = (SSLServerSocket) super.newServerSocket(p_address, p_acceptQueueSize);
        if (serverSocket.getNeedClientAuth()) {

            serverSocket.setNeedClientAuth(require);
            setNeedClientAuth(require);
            if (!require)
                serverSocket.setWantClientAuth(true);
        }

        String[] ciphers = serverSocket.getSupportedCipherSuites();
        String[] protocols = serverSocket.getSupportedProtocols();

        if (log.isInfoEnabled()) {
            log.info("The following protocols are supported:");
            for (int i = 0; i < protocols.length; i++) {
                log.info("     " + protocols[i]);
            }
        }

        if (createAvailableCipherSuitesList) {
            File f = new File(ContextHolder.getContext().getTempDirectory(), "availableCipherSuites.txt");
            BufferedWriter writer = null;

            try {
                writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
                if (log.isInfoEnabled())
                    log.info("The following cipher suites are supported:");
                for (int i = 0; i < ciphers.length; i++) {
                    if (log.isInfoEnabled())
                        log.info("     " + ciphers[i]);
                    writer.write(ciphers[i]);
                    writer.newLine();
                }
            } catch (Throwable e) {
                log.error("Could not create cipher list!", e);
                configureContext = false;
            } finally {
                if (writer != null)
                    writer.close();
            }
            createAvailableCipherSuitesList = false;
        }

        if (configureContext) {

            PropertyList list = ContextHolder.getContext().getConfig()
                    .retrievePropertyList(new ContextKey("ssl.supportedProtocols"));

            if (!list.isEmpty()) {
                serverSocket.setEnabledProtocols(list.asArray());
            }

            list = ContextHolder.getContext().getConfig()
                    .retrievePropertyList(new ContextKey("ssl.supportedCiphers"));

            if (!list.isEmpty()) {
                serverSocket.setEnabledCipherSuites(list.asArray());
            }
        }

        protocols = serverSocket.getEnabledProtocols();

        if (log.isInfoEnabled()) {
            log.info("The following protocols are enabled:");
            for (int i = 0; i < protocols.length; i++) {
                log.info("     " + protocols[i]);
            }
        }

        ciphers = serverSocket.getEnabledCipherSuites();
        if (log.isInfoEnabled()) {
            log.info("The following cipher suites are enabled:");
            for (int i = 0; i < ciphers.length; i++) {
                log.info("     " + ciphers[i]);
            }
        }

        return serverSocket;
    }

    protected SSLServerSocketFactory createFactory() throws Exception {
        if (KeyStoreManager.getInstance(KeyStoreManager.DEFAULT_KEY_STORE).isKeyStoreEmpty()) {
            throw new Exception(
                    "The keystore does not contain any certificates. Please run the installation wizard (--install).");
        }
        KeyStore ks = KeyStoreManager.getInstance(KeyStoreManager.DEFAULT_KEY_STORE).getKeyStore();
        String pw = ContextHolder.getContext().getConfig()
                .retrieveProperty(new ContextKey("webServer.keystore.sslCertificate.password"));
        KeyManager[] kma = new KeyManager[] { new CustomKeyManager(pw) };
        TrustManager[] tma = null;
        if (trustManager == null) {
            TrustManagerFactory tm = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tm.init(ks);
            tma = tm.getTrustManagers();
        } else {

            // LDP - Add the existing trust managers so that outgoing certificates are still trusted.
            TrustManagerFactory tm = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tm.init(ks);

            tma = new TrustManager[tm.getTrustManagers().length + 1];
            for (int i = 0; i < tm.getTrustManagers().length; i++) {
                tma[i] = tm.getTrustManagers()[i];
            }
            tma[tma.length - 1] = trustManager;
        }
        SSLContext sslc = SSLContext.getInstance("SSL");
        sslc.init(kma, tma, SecureRandom.getInstance("SHA1PRNG"));
        SSLServerSocketFactory ssfc = sslc.getServerSocketFactory();
        if (log.isInfoEnabled())
            log.info("SSLServerSocketFactory=" + ssfc);
        initialised = true;
        return ssfc;
    }

    public boolean isConfigureContext() {
        return configureContext;
    }

    public void setConfigureContext(boolean configureContext) {
        this.configureContext = configureContext;
    }

}