Package winstone.ssl

Source Code of winstone.ssl.HttpsListener

/*
* Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
* Distributed under the terms of either:
* - the common development and distribution license (CDDL), v1.0; or
* - the GNU Lesser General Public License, v2.1 or later
*/
package winstone.ssl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import winstone.HostGroup;
import winstone.HttpListener;
import winstone.Logger;
import winstone.ObjectPool;
import winstone.WebAppConfiguration;
import winstone.WinstoneException;
import winstone.WinstoneRequest;
import winstone.WinstoneResourceBundle;

/**
* Implements the main listener daemon thread. This is the class that gets
* launched by the command line, and owns the server socket, etc.
*
* @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
* @version $Id: HttpsListener.java,v 1.10 2007/06/13 15:27:35 rickknowles Exp $
*/
public class HttpsListener extends HttpListener {
    private static final WinstoneResourceBundle SSL_RESOURCES = new WinstoneResourceBundle("winstone.ssl.LocalStrings");
    private String keystore;
    private String password;
    private String keyManagerType;

    /**
     * Constructor
     */
    public HttpsListener(Map args, ObjectPool objectPool, HostGroup hostGroup) throws IOException {
        super(args, objectPool, hostGroup);
        this.keystore = WebAppConfiguration.stringArg(args, getConnectorName()
                + "KeyStore", "winstone.ks");
        this.password = WebAppConfiguration.stringArg(args, getConnectorName()
                + "KeyStorePassword", null);
        this.keyManagerType = WebAppConfiguration.stringArg(args,
                getConnectorName() + "KeyManagerType", "SunX509");
    }

    /**
     * The default port to use - this is just so that we can override for the
     * SSL connector.
     */
    protected int getDefaultPort() {
        return -1; // https disabled by default
    }

    /**
     * The name to use when getting properties - this is just so that we can
     * override for the SSL connector.
     */
    protected String getConnectorScheme() {
        return "https";
    }

    /**
     * Gets a server socket - this gets as SSL socket instead of the standard
     * socket returned in the base class.
     */
    protected ServerSocket getServerSocket() throws IOException {
        // Just to make sure it's set before we start
        SSLContext context = getSSLContext(this.keystore, this.password);
        SSLServerSocketFactory factory = context.getServerSocketFactory();
        SSLServerSocket ss = (SSLServerSocket) (this.listenAddress == null ? factory
                .createServerSocket(this.listenPort, BACKLOG_COUNT)
                : factory.createServerSocket(this.listenPort, BACKLOG_COUNT,
                        InetAddress.getByName(this.listenAddress)));
        ss.setEnableSessionCreation(true);
        ss.setWantClientAuth(true);
        return ss;
    }

    /**
     * Extracts the relevant socket stuff and adds it to the request object.
     * This method relies on the base class for everything other than SSL
     * related attributes
     */
    protected void parseSocketInfo(Socket socket, WinstoneRequest req)
            throws IOException {
        super.parseSocketInfo(socket, req);
        if (socket instanceof SSLSocket) {
            SSLSocket s = (SSLSocket) socket;
            SSLSession ss = s.getSession();
            if (ss != null) {
                Certificate certChain[] = null;
                try {
                    certChain = ss.getPeerCertificates();
                } catch (Throwable err) {/* do nothing */
                }

                if (certChain != null) {
                    req.setAttribute("javax.servlet.request.X509Certificate",
                            certChain);
                    req.setAttribute("javax.servlet.request.cipher_suite", ss
                            .getCipherSuite());
                    req.setAttribute("javax.servlet.request.ssl_session",
                            new String(ss.getId()));
                    req.setAttribute("javax.servlet.request.key_size",
                            getKeySize(ss.getCipherSuite()));
                }
            }
            req.setIsSecure(true);
        }
    }

    /**
     * Just a mapping of key sizes for cipher types. Taken indirectly from the
     * TLS specs.
     */
    private Integer getKeySize(String cipherSuite) {
        if (cipherSuite.indexOf("_WITH_NULL_") != -1)
            return new Integer(0);
        else if (cipherSuite.indexOf("_WITH_IDEA_CBC_") != -1)
            return new Integer(128);
        else if (cipherSuite.indexOf("_WITH_RC2_CBC_40_") != -1)
            return new Integer(40);
        else if (cipherSuite.indexOf("_WITH_RC4_40_") != -1)
            return new Integer(40);
        else if (cipherSuite.indexOf("_WITH_RC4_128_") != -1)
            return new Integer(128);
        else if (cipherSuite.indexOf("_WITH_DES40_CBC_") != -1)
            return new Integer(40);
        else if (cipherSuite.indexOf("_WITH_DES_CBC_") != -1)
            return new Integer(56);
        else if (cipherSuite.indexOf("_WITH_3DES_EDE_CBC_") != -1)
            return new Integer(168);
        else
            return null;
    }

    /**
     * Used to get the base ssl context in which to create the server socket.
     * This is basically just so we can have a custom location for key stores.
     */
    public SSLContext getSSLContext(String keyStoreName, String password)
            throws IOException {
        try {
            // Check the key manager factory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(this.keyManagerType);
           
            File ksFile = new File(keyStoreName);
            if (!ksFile.exists() || !ksFile.isFile())
                throw new WinstoneException(SSL_RESOURCES.getString(
                        "HttpsListener.KeyStoreNotFound", ksFile.getPath()));
            InputStream in = new FileInputStream(ksFile);
            char[] passwordChars = password == null ? null : password.toCharArray();
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(in, passwordChars);
            kmf.init(ks, passwordChars);
            Logger.log(Logger.FULL_DEBUG, SSL_RESOURCES,
                    "HttpsListener.KeyCount", ks.size() + "");
            for (Enumeration e = ks.aliases(); e.hasMoreElements();) {
                String alias = (String) e.nextElement();
                Logger.log(Logger.FULL_DEBUG, SSL_RESOURCES,
                        "HttpsListener.KeyFound", new String[] { alias,
                                ks.getCertificate(alias) + "" });
            }

            SSLContext context = SSLContext.getInstance("SSL");
            context.init(kmf.getKeyManagers(), null, null);
            Arrays.fill(passwordChars, 'x');
            return context;
        } catch (IOException err) {
            throw err;
        } catch (Throwable err) {
            throw new WinstoneException(SSL_RESOURCES
                    .getString("HttpsListener.ErrorGettingContext"), err);
        }
    }
}
TOP

Related Classes of winstone.ssl.HttpsListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.