/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 * 
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits réservés.
 * Ce logiciel est propriété de Sun Microsystems, Inc.
 * Distribué par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)MfJMXConnectorServerFactory.java 1.2     04/05/19 SMI"
 *
 */

/*
 * MfJMXConnectorServerFactory.java
 *
 * Created on May 13, 2004, 10:33 AM
 */

package com.sun.mfwk.security.factory;

import java.util.*;
import java.io.*;
import java.security.*;
import java.security.Security;
import java.security.cert.CertificateException;
import javax.net.ssl.*;
import javax.security.cert.X509Certificate;
import javax.management.remote.*;
import javax.management.*;
import java.util.logging.*;
import com.sun.mfwk.util.log.MfLogService;
import com.sun.mfwk.config.MfConfig;

/**
 *
 * @author  ooudghir
 */
public class MfJMXConnectorServerFactory {
    /** MfConfig reference to retrieve properties. */
    protected static MfConfig myConfig = MfConfig.getConfig();
    /** Mfwk logger. */
    protected static Logger logger = MfLogService.getLogger("MfJMXConnectorServerFactory");
    /** String containing the class name. */
    protected static String myClass = "com.sun.mfwk.security.factory.MfJMXConnectorServerFactory";
    
    /** There are no instances if this calss */
    private MfJMXConnectorServerFactory() {
    }
    
    public static JMXConnectorServer newJMXConnectorServer(JMXServiceURL url, String keystorePath, char keystorepass[] , MBeanServer mbs)
    throws MfSecurityException, IOException {
        
        logger.entering(myClass, "newJMXConnectorServer", url);
        
        // Some sanity checks
        if (url == null) {
            String msg = "url cannot be null";
            logger.severe(msg);
            throw new NullPointerException(msg);
        }
        if (keystorePath == null) {
            String msg = "keystore path cannot be null";
            logger.severe(msg);
            throw new NullPointerException(msg);
        }
        if (keystorepass == null) {
            String msg = "keystore password cannot be null";
            logger.severe(msg);
            throw new NullPointerException(msg);
        }
        if (mbs == null) {
            String msg = "MBean server cannot be null";
            logger.severe(msg);
            throw new NullPointerException(msg);
        }
        
        // Only jmxmp supported
        String proto = url.getProtocol();
        if (! proto.equals("jmxmp")) {
            String msg = "Protocol not supported: "+proto;
            logger.severe(msg);
            throw new MfSecurityException(msg);
        }
        
        // Retrieving the common truststore path and password
        String tspath = myConfig.getProperty("mfwk.security.truststore");
        if (tspath == null) { // should not occur
            String msg = "cannot get property mfwk.security.truststore.";
            logger.severe(msg);
            throw (new MfSecurityException(msg));
        }
        logger.finer("truststore path is "+tspath);
        char truststorepass[] = myConfig.getProperty("mfwk.security.trustpass").toCharArray();
        if (truststorepass == null) { // Should not occur
            String msg = "cannot get property mfwk.security.trustpass.";
            logger.severe(msg);
            throw (new MfSecurityException(msg));
        }
        
        // Loading keystore
        KeyStore ks = null;
        KeyManagerFactory kmf = null;
        try {
            ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(keystorePath), keystorepass);
            kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, keystorepass);
        } catch (Exception e) {
            String msg = null;
            if (e instanceof KeyStoreException)
                msg = "Cannot get keystore instance : ";
            else if (e instanceof IOException)
                msg = "Cannot load keystore from file "+keystorePath+" : ";
            else if (e instanceof NoSuchAlgorithmException)
                msg = "Cannot get KeyManagerFactory instance with algorithm SUNX509 :";
            else if (e instanceof CertificateException)
                msg = "Cannot load keystore :";
            else if (e instanceof UnrecoverableKeyException)
                msg = "Cannot init KeyManagerFactory : ";
            else
                msg = "Unknown exception : ";
            logger.warning("MfSecurityException "+msg+" : "+e.getMessage());
            throw new MfSecurityException(msg);
        }
        // Load the common truststore
        KeyStore ts = null;
        TrustManagerFactory tmf = null;
        try {
            ts = KeyStore.getInstance("JKS");
            ts.load(new FileInputStream(tspath), truststorepass);
            tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ts);
        } catch(Exception e) {
            String msg = null;
            if (e instanceof KeyStoreException)
                msg = "Cannot get keystore instance : ";
            else if (e instanceof IOException)
                msg = "Cannot load keystore from file "+tspath+" : ";
            else if (e instanceof NoSuchAlgorithmException)
                msg = "Cannot get KeyManagerFactory instance with algorithm SUNX509 :";
            else if (e instanceof CertificateException)
                msg = "Cannot load keystore :";
            else
                msg = "Unknown exception : ";
            logger.warning("MfSecurityException "+msg+" : "+e.getMessage());
            throw new MfSecurityException(msg);
        }
        
        SSLSocketFactory ssf = null;
        try {
            SSLContext ctx = SSLContext.getInstance("TLSv1");
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            ssf = ctx.getSocketFactory();
        } catch (Exception e) {
            String msg = null;
            if (e instanceof NoSuchAlgorithmException)
                msg = "cannot get instance of SSLContext with algorithm TLSv1";
            else if (e instanceof KeyManagementException)
                msg = "Cannot init SSL context";
            else
                msg = "Unknown exception : ";
            logger.warning("MfSecurityException "+msg+" : "+e.getMessage());
            throw new MfSecurityException(msg);
        }
        HashMap env = new HashMap();
        env.put("jmx.remote.profiles", "TLS");
        env.put("jmx.remote.tls.socket.factory", ssf);
        env.put("jmx.remote.tls.enabled.protocols", "TLSv1");
        env.put("jmx.remote.tls.enabled.cipher.suites","SSL_RSA_WITH_NULL_MD5");
        env.put("jmx.remote.tls.need.client.authentication","true");
        return(JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs));
    }
}
