/*$Id: SSLUtil.java,v 1.2 2011/09/03 07:24:51 mathankarthik.r Exp $*/
/*
 * SSLUtil.java
 *
 * Created on December 20, 2004, 12:04 PM
 */
package com.adventnet.sym.server.downloadmgr;

import HTTPClient.Cookie;
import HTTPClient.CookieModule;
import HTTPClient.CookiePolicyHandler;
import HTTPClient.DefaultAuthHandler;
import HTTPClient.HTTPConnection;
import HTTPClient.NTLMAuthorizationHandler;
import HTTPClient.NVPair;
import HTTPClient.ProtocolNotSuppException;
import HTTPClient.RoRequest;
import HTTPClient.RoResponse;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Security;
import java.security.Provider;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * This class is used to create the http or https connection using the HTTPClient API Package.
 * @author rajeshr
 */
public class SSLUtil {

    private static Logger logger = Logger.getLogger("DownloadManager");
    private static boolean isProviderSet = false;
    private static SSLUtil sslUtil = null;

    /**
     * Create a new instance for SSLUtil when it is not created for the jvm.
     * @return - instance for SSLUtil
     */
    public static SSLUtil getInstance() {
        if (sslUtil == null) {
            sslUtil = new SSLUtil();
            initSSLFactory();
            initSecurityProvider();
            removeEncodingModule();
        }
        return sslUtil;
    }

    /**
     * This method is used to initialize the CryptixCrypto provider for making the secure
     * communication.
     */
    private static void initSecurityProvider() {
        if (!isProviderSet) {
            String securityProviderClassName = "cryptix.jce.provider.CryptixCrypto"; // NO I18N
            try {
                System.setProperty("java.protocol.handler.pkgs", "HTTPClient");
                String os = System.getProperty("os.name");
                InetAddress localHost = java.net.InetAddress.getLocalHost();
                System.setProperty("HTTPClient.host", localHost.getHostName());
                if (os.indexOf("Windows") != -1) {
                    String domain = localHost.getCanonicalHostName();
                    int ind = domain.indexOf('.');
                    if (ind != -1) {
                        domain = domain.substring(ind + 1);
                    }
                    System.setProperty("HTTPClient.hostDomain", domain);
                } else {
                    System.setProperty("HTTPClient.hostDomain", "");
                }
                if (securityProviderClassName != null) {
                    Class securityProvider = Class.forName(securityProviderClassName);
                    Security.addProvider((Provider) securityProvider.newInstance());
                    logger.log(Level.INFO, "Provider :: {0}", Security.getProvider(((Provider) securityProvider.newInstance()).getName()));
                }
            } catch (Exception e) {
                logger.log(Level.WARNING, "Error occurred during initializing the security providers : {0}", e);
            }
            isProviderSet = true;
            CookieModule.setCookiePolicyHandler((CookiePolicyHandler) new DCCookiePolicyHandler());
            System.getProperties().put("java.protocol.handler.pkgs", "HTTPClient");
        }
    }

    /**
     * Remove Content-Encoding module if specified in wrapper-user.conf.
     * Check for java system parameter for "enable.content.encoding", if false -> then remove the module
     * Note : This check is introduced to fix unexpected content-encoding response headers.
     */
     private static void removeEncodingModule() {
        try {

            String encodingModule = System.getProperty("enable.content.encoding", null); //No I18N
            if(encodingModule != null){
                boolean enableEncoding = Boolean.valueOf(encodingModule);
                if(!enableEncoding){
                    logger.log(Level.INFO,"\"enable.content.encoding\" java system property is false. Hence, removing default module : HTTPClient.ContentEncodingModule ");
                    HTTPConnection.removeDefaultModule(Class.forName("HTTPClient.ContentEncodingModule")); //No I18N
                }
            }
        } catch (ClassNotFoundException e) {
            logger.log(Level.WARNING, "Exception while removing module \"HTTPClient.ContentEncodingModule\":: ", e);
        }
    }

    /**
     * This method is used to create a httpconnection for the specified url with the proxy details.
     * @param connectionURL
     * @param proxyConf
     * @return - HTTPConnection
     * @throws ProtocolNotSuppException
     * @throws MalformedURLException
     */
    public HTTPConnection getConnection(String connectionURL, Properties proxyConf) throws ProtocolNotSuppException, MalformedURLException{
        String proxyHost = null;
        String proxyPort = null;
        String userName = null;
        String password = null;
        if (proxyConf != null) {
            proxyHost = (String) proxyConf.get("proxyHost");
            proxyPort = (String) proxyConf.get("proxyPort");
            userName = (String) proxyConf.get("proxyUser");
            password = (String) proxyConf.get("proxyPass");
        }
        HTTPClient.AuthorizationHandler ntlm = new HTTPClient.NTLMAuthorizationHandler();
        NTLMAuthorizationHandler.setAuthorizationPrompter(new DCAuthorizationPrompter(userName, password));
        HTTPClient.AuthorizationInfo.setAuthHandler(ntlm);
        DefaultAuthHandler.setAuthorizationPrompter(new DCAuthorizationPrompter(userName, password));

        URL url = new URL(connectionURL);
        HTTPConnection connection = new HTTPConnection(url);
        connection.setDefaultHeaders(getDefaultHeaders(connection));
        if (proxyHost != null && proxyPort != null && !proxyHost.equalsIgnoreCase("") && !proxyPort.equalsIgnoreCase("")) {
            logger.log(Level.INFO, "Connection {0},{1},{2}", new Object[]{connection, proxyHost.trim(), proxyPort.trim()});
            if (proxyHost != null) {
                connection.setCurrentProxy(proxyHost.trim(), new Integer(proxyPort.trim()).intValue());
            }
        }
        return connection;
    }

    private NVPair[] getDefaultHeaders(HTTPConnection connection){
        NVPair[] defaultHeaders = connection.getDefaultHeaders();
        NVPair clearCache = new NVPair("Cache-Control","no-cache"); // No I18N
        NVPair acceptHeader = new NVPair("Accept","*/*"); //No I18N
        if(defaultHeaders != null){
            if(defaultHeaders.length > 0){
                defaultHeaders[defaultHeaders.length + 1] = clearCache;
                defaultHeaders[defaultHeaders.length + 1] = acceptHeader;
            } else {
                defaultHeaders = new NVPair[2];
                defaultHeaders[0] = clearCache;
                defaultHeaders[1] = acceptHeader;
             }
        }
        return defaultHeaders;
    }
    private static void initSSLFactory() {
        TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {

                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public boolean isClientTrusted(
                        java.security.cert.X509Certificate[] certs) {
                    return true;
                }

                public boolean isServerTrusted(
                        java.security.cert.X509Certificate[] certs) {
                    return true;
                }

                public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
                        String authType) {
                }

                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authtype) {
                }
            }
        };

        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            // con.setSSLSocketFactory(sc.getSocketFactory());
            HTTPConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            logger.log(Level.WARNING, "Error occurred during initializing the ssl factories : {0}", e);
        }

    }
}

class DCCookiePolicyHandler implements CookiePolicyHandler {

    public boolean sendCookie(Cookie cookie, RoRequest req) {
        // Currently accepts all cookies
        return true;
    }

    public boolean acceptCookie(Cookie cookie, RoRequest req, RoResponse resp) {
        // Currently accepts all cookies
        CookieModule.addCookie(cookie);
        return true;
    }
}

