package com.ycwl.basic.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * SSL工具类
 * 
 * @author songmingsong
 */
@Slf4j
public class SslUtil {
    /**
     * 获取HtttpClient对象
     * 
     * @return CloseableHttpClient
     */
    public static CloseableHttpClient sslHttpClientBuild() {
        Registry<ConnectionSocketFactory> socketFactoryRegistry =
            RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", trustAllHttpsCertificates()).build();
        // 创建ConnectionManager，添加Connection配置信息
        PoolingHttpClientConnectionManager connectionManager =
            new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
        return httpClient;
    }

    /**
     * 信任所有Http证书
     * 
     * @return SSLConnectionSocketFactory
     */
    private static SSLConnectionSocketFactory trustAllHttpsCertificates() {
        SSLConnectionSocketFactory socketFactory = null;
        TrustManager[] trustAllCerts = new TrustManager[1];
        TrustManager tm = new X509TrustManager() {

            @Override
            // 返回受信任的X509证书数组。
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            // 该方法检查服务器的证书，若不信任该证书同样抛出异常。通过自己实现该方法，可以使之信任我们指定的任何证书。
            // 在实现该方法时，也可以简单的不做任何处理，即一个空的函数体，由于不会抛出异常，它就会信任任何证书。
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                try {
                    if (chain!=null&&chain.length>0) {
                        chain[0].checkValidity();
                    }
                } catch (Exception e) {
                    log.error("checkServerTrusted",e);
                }
            }

            @Override
            // 该方法检查客户端的证书，若不信任该证书则抛出异常。由于我们不需要对客户端进行认证，
            // 因此我们只需要执行默认的信任管理器的这个方法。JSSE中，默认的信任管理器类为TrustManager。
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                try {
                    if (chain!=null&&chain.length>0) {
                        chain[0].checkValidity();
                    }
                } catch (Exception e) {
                   log.error("checkClientTrusted",e);
                }
            }
        };
        trustAllCerts[0] = tm;
        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("TLSv1.2");
            sc.init(null, trustAllCerts, null);
            socketFactory = new SSLConnectionSocketFactory(sc, NoopHostnameVerifier.INSTANCE);
            // HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            log.error("trustAllHttpsCertificates", e);
        }
        return socketFactory;
    }

}
