/*
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */
package com.ibm.trl.util.net;

import java.io.*;
import java.net.*;

import java.security.KeyStore;

import java.security.Security;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HandshakeCompletedEvent;

/*
  1. Add IBM Jsse's jars into jre/lib/ext
  2. Edit java.security, add
       security.provider.2=com.ibm.net.ssl.internal.ssl.Provider
  3. keytool -genkey -alias tomcat -keyalg RSA
     Use "changeit" as password ( this is the default we use )
 */

/**
 * SSL server socket factory. It _requires_ a valid RSA key and
 * **either**  IBM or Sun JSSE.
 *
 * @author Harish Prabandham
 * @author Costin Manolache
 * @author Stefan Freyr Stefansson
 * @author Darrell M. Drake
 */
public class TomcatSSLSocketFactory
    extends org.apache.tomcat.net.ServerSocketFactory
{
    private boolean clientAuth = false;
    private SSLServerSocketFactory sslProxy = null;

    // defaults
    static String defaultKeystoreFile=System.getProperty("user.home") +
	File.separator + ".keystore";
    static String defaultKeyPass="changeit";


    public TomcatSSLSocketFactory () {
    }

    public ServerSocket createSocket (int port)
	throws IOException
    {
	if( sslProxy == null ) initProxy();
	ServerSocket socket =
	    sslProxy.createServerSocket(port);
	initServerSocket(socket);
	return socket;
    }

    public ServerSocket createSocket (int port, int backlog)
	throws IOException
    {
	if( sslProxy == null ) initProxy();
	ServerSocket socket =
	    sslProxy.createServerSocket(port, backlog);
	initServerSocket(socket);
	return socket;
    }

    public ServerSocket createSocket (int port, int backlog,
				      InetAddress ifAddress)
	throws IOException
    {
	if( sslProxy == null ) initProxy();
	ServerSocket socket =
	    sslProxy.createServerSocket(port, backlog, ifAddress);
	initServerSocket(socket);
	return socket;
    }


    // -------------------- Internal methods
    /** init the SSL socket factory */
    private void initProxy() throws IOException {
	try {

	    clientAuth = "true".equals(attributes.get("clientAuth"));

	    String keystoreFile=(String)attributes.get("keystore");
	    if( keystoreFile==null) keystoreFile=defaultKeystoreFile;

	    String keyPass=(String)attributes.get("keypass");
	    if( keyPass==null) keyPass=defaultKeyPass;

	    System.setProperty("javax.net.ssl.keyStore", keystoreFile);
	    System.setProperty("javax.net.ssl.keyStorePassword", keyPass);
	    if (clientAuth) {
			System.setProperty("javax.net.ssl.trustStore", keystoreFile);
			System.setProperty("javax.net.ssl.trustStorePassword", keyPass);
		}

	    sslProxy = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
	    return;

	} catch(Exception e) {
	    if( e instanceof IOException )
		throw (IOException)e;
	    throw new IOException(e.getMessage());
	}
    }

    /** Set server socket properties ( accepted cipher suites, etc)
     */
    private void initServerSocket(ServerSocket ssocket) {
	SSLServerSocket socket=(SSLServerSocket)ssocket;

	// We enable all cipher suites when the socket is
	// connected - XXX make this configurable
	String cipherSuites[] = socket.getSupportedCipherSuites();
	socket.setEnabledCipherSuites(cipherSuites);

	// we don't know if client auth is needed -
	// after parsing the request we may re-handshake
	socket.setNeedClientAuth(clientAuth);
    }

    /** 3.2-specific hack - allow the socket factory to manipulate the
	request. This will be replaced with a clean, interceptor
	based mechanism in 3.3
	** Modified: cert is entered under  the "javax.net.ssl.peer_certificates" attribute name (per the JSSE spec)
	** Now added: session attribute, ciper_suite attribute
    */
    public void preProcessRequest( Socket socket,
				   org.apache.tomcat.core.Request reqA )
    {
	try {
	    //Set the client certificate attribute if appropriate
	    javax.net.ssl.SSLSocket sslSocket = (javax.net.ssl.SSLSocket)socket;
	    javax.net.ssl.SSLSession sslSession = sslSocket.getSession();
	    if (sslSession != null) { reqA.setAttribute("javax.net.ssl.session", sslSession); String suite = sslSession.getCipherSuite(); if (suite != null) reqA.setAttribute("javax.net.ssl.cipher_suite", suite); }
	    javax.security.cert.X509Certificate[] certChain = sslSession.getPeerCertificateChain();

	    if( certChain != null && certChain.length > 0 ) {
		reqA.setAttribute("javax.net.ssl.peer_certificates",
				  certChain);
		reqA.setAttribute("tomcat.request.X509CertificateChain",
				  certChain);
		reqA.setAttribute("javax.servlet.request.X509Certificate",
				  certChain[0]);
	    }
	} catch( Exception ex ) {
	}
	// this is a  ssl socket
	reqA.setScheme( "https" );
    }
}
