javax.net.ssl.SSLException: Certificate doesn't match any of the subject alternative names

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-03 08:54:45

If you use HttpClient 4.4 then you need to specify host verifier (NoopHostnameVerifier) to allow accepting certificates from different hosts:

SSLConnectionSocketFactory scsf = SSLConnectionSocketFactory(
     SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build(), 
        NoopHostnameVerifier.INSTANCE)
httpclient = HttpClients.custom().setSSLSocketFactory(scsf).build()

I don't know which version of the Apache HttpClient you were using but versions 4.4.1 and 4.5.1 had a bug where the SNI didn't work correctly. This was fixed in 4.5.3

https://issues.apache.org/jira/browse/HTTPCLIENT-1726

I was getting the same error when I was using methods from org.apache.http.* for making my http requests. From your stack trace I assume that even you are using the same.

This error disappeared when I used java.net.HttpURLConnection and I was able to connect successfully.

import java.net.HttpURLConnection;

public static HttpURLConnection connectToWeb(String uri) {
    HttpURLConnection connection = null;
    try {
        URL url = new URL(uri);
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.connect();
    } catch (MalformedURLException ex) {
        ex.printStackTrace();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    return connection;
}

Following Yurri's comment, it solved my problem by adding NoopHostnameVerifier.INSTANCE while initialising SSLConnectionSocketFactory :

import org.apache.http.HttpHost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.TrustStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;

/**
 * Provide basic Utils for getting HttpHeader and making REST api calls.
 * 
 */
@Component
public class HttpUtil {

    private static final Logger LOG = LoggerFactory.getLogger(HttpUtil.class);

    /**
     * The default implementation to get basic headers.
     * @return HttpHeaders.
     */
    public HttpHeaders getHttpHeaders(String userAgent, String host) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
        headers.set(HttpHeaders.USER_AGENT, userAgent);
        LOG.info("host=" + host);
        if (null != host) {
            headers.set(HttpHeaders.HOST, host);
        }

        return headers;
    }

    /**
     * Default implementation to get RestTemplate
     * @return
     */
     public RestTemplate getRestTemplate(String proxyHost, int proxyPort)
        throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {

    TrustStrategy acceptingTrustStrategy = new TrustSelfSignedStrategy();

    SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy)
            .build();

    SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);

    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();

    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    if (null != proxyHost && proxyPort > 0) {
        LOG.info("PROXY CONFIGURED | proxyHost=" + proxyHost + " | proxyPort=" + proxyPort);
        HttpHost proxy = new HttpHost(proxyHost, proxyPort, Proxy.Type.HTTP.name());
        httpClient = HttpClients.custom().setSSLSocketFactory(csf)
                .setRoutePlanner(new DefaultProxyRoutePlanner(proxy)).build();
    }
    requestFactory.setHttpClient(httpClient);
    RestTemplate restTemplate = new RestTemplate(requestFactory);
    return restTemplate;
}

    /**
     * Make a rest api call
     * @return ResponseEntity
     */
    public ResponseEntity<String> getApiResponse(HttpMethod httpMethod, final String URL, final String userAgent,
            String proxyHost, int proxyPort, String host) throws HttpClientErrorException {
        ResponseEntity<String> response = null;
        HttpEntity<String> httpEntity = new HttpEntity<>(getHttpHeaders(userAgent, host));
        try {
            if (null != httpMethod && null != URL) {
                RestTemplate request = null;
                try {
                    request = getRestTemplate(proxyHost, proxyPort);
                    response = request.exchange(URL, httpMethod, httpEntity, String.class);
                } catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) {
                    LOG.error("Error creating Rest Template", e);
                }
            }
        } catch (HttpClientErrorException ex) {
            LOG.error("Method = " + httpMethod.toString() + "Request URL = " + URL);
            LOG.error("Headers =" + getHttpHeaders(userAgent, host));
            LOG.error("Response Status = " + ex.getStatusText());
            LOG.error("Response Body = " + ex.getResponseBodyAsString());
            throw ex;
        }
        return response;
    }
}
/*
 * Inner class for Proxy SSL Socket Connection.
 */
static class MyConnectionSocketFactory extends SSLConnectionSocketFactory {
    private String proxyHost = null;
    private Integer proxyPort = null;

    public MyConnectionSocketFactory(final SSLContext sslContext, String proxyHost, Integer proxyPort) {
        super(sslContext, new NoopHostnameVerifier());
        this.proxyHost = proxyHost;
        this.proxyPort = proxyPort;
    }

    @Override
    public Socket createSocket(final HttpContext context) throws IOException {
        logger.debug("Create Socket:" + " ProxyHost: " + proxyHost + ", ProxyPort: " + proxyPort);
        InetSocketAddress socksaddr = new InetSocketAddress(proxyHost,proxyPort);
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
        return new Socket(proxy);
    }
}


   else if (proxyType.equalsIgnoreCase("socks")) {
        logger.debug("Proxy Type: " + proxyType);
        TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                return true;
            }
        };

        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
        SSLConnectionSocketFactory csf = new MyConnectionSocketFactory(sslContext, proxyHost, proxyPort);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        restTemplate = new RestTemplate(requestFactory);
        return;
    } else {
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!