简体   繁体   中英

How to make an HTTP or HTTPS request (emphasis on “or”)

I need to tweak an app somebody else built to use an API that I wrote. In a production environment, said app will be making HTTPS requests to a server with a signed, trusted certificate. No problem there.

However, my local development server has no SSL certificate (other than a self-signed one I knocked up). Android complains about this, specifically throwing javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

So, I need to do one of two things.

  • Convince a HttpsURLConnection to accept a http:// URL;
  • Convince the same HttpsURLConnection to accept a self-signed certificate being returned.

I've already tried writing a custom HostnameVerifier (with a verify method that always returns true), but that hasn't helped me past the problem.

Edit: For clarity, I cannot simply provide an http URL to HttpsURLConnection, since I then get a com.android.okhttp.internal.huc.HttpURLConnectionImpl cannot be cast to javax.net.ssl.HttpsURLConnection error.

在没有较低级别的解决方案的情况下,我只使用了Webb库。

I was in same situation working on one project few months ago. I had local server for developing with self signed certificate. This is my android code, it worked for me:

final HttpsURLConnection https = (HttpsURLConnection) requestedUrl.openConnection();

try {

    https.setConnectTimeout(timeout);
    https.setReadTimeout(timeout);
    https.setRequestMethod(method);

    if (sslSocketFactory != null) {
        https.setSSLSocketFactory(sslSocketFactory);
    }

    https.setHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
            return hv.verify("localhost", session);
        }
    });
...

I remember, that there was one tricky thing - the self signed certificate for server was written for name "localhost", but in android, the HTTPS request was made with IP address and this was a problem causing denying of server certificate.

And loading client certificate (in my case, it was stored in .p12 file on android device):

public static SSLContext loadCertificate(String password)
            throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException,
            UnrecoverableKeyException, KeyManagementException {

        final FileInputStream fis = new FileInputStream(new File(CERT_FILE_DIRECTORY, CERT_FILE_NAME));

        final KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(fis, password.toCharArray());

        final KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
        kmf.init(keyStore, null);
        final KeyManager[] keyManagers = kmf.getKeyManagers();
        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManagers, new TrustManager[]{new MyTrustManager()}, null);
        return sslContext;
    }

And empty MyTrustManager:

public class MyTrustManager implements X509TrustManager {

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}

With all this, i was able to connect via HTTPS to my local server with self signed certificate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM