88

I'm working for a customer who has a server with self-signed SSL cert.

I'm using Retrofit + CustomClient using wrapped OkHttp client:

RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(Config.BASE_URL + Config.API_VERSION)
    .setClient(new CustomClient(new OkClient(), context))
    .build();

Does OkHttp support calling Self-Signed SSL cert server by default?

By the way. Which client is using Retrofit by default? I thought it was OkHttp but when I researched a bit more I realized I needed to import OkHttp dependencies

rekire
  • 47,260
  • 30
  • 167
  • 264
cesards
  • 15,882
  • 11
  • 70
  • 65
  • Regarding the second part, Retrofit will use OkHttp if it's available your classpath. Check `defaultClient()` in [Platform.java](https://github.com/square/retrofit/blob/449cfaa4b91ed28ce6928a400272d5b4542d13b7/retrofit/src/main/java/retrofit/Platform.java#L120) for more details. – Hassan Ibraheem Apr 17 '14 at 08:35
  • see: [How to setup Retrofit2 with a custom SSL sertificate] (https://adiyatmubarak.wordpress.com/tag/add-ssl-certificate-in-retrofit-2/) – afruzan Aug 24 '16 at 06:51

10 Answers10

101

Yes, It does.

Retrofit allows you to set your custom HTTP client, that is configured to your needs.

As for self-signed SSL certs there is a discussion here. The link contains code samples to add self-signed SSL to Android's DefaultHttpClient and to load this client to Retrofit.

If you need OkHttpClient to accept self signed SSL, you need to pass it custom javax.net.ssl.SSLSocketFactory instance via setSslSocketFactory(SSLSocketFactory sslSocketFactory) method.

The easiest method to get a socket factory is to get one from javax.net.ssl.SSLContext as discussed here.

Here is a sample for configuring OkHttpClient:

OkHttpClient client = new OkHttpClient();
KeyStore keyStore = readKeyStore(); //your method to obtain KeyStore
SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "keystore_pass".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(),trustManagerFactory.getTrustManagers(), new SecureRandom());
client.setSslSocketFactory(sslContext.getSocketFactory());

Updated code for okhttp3 (using builder):

    OkHttpClient client = new OkHttpClient.Builder()
            .sslSocketFactory(sslContext.getSocketFactory())
            .build();

the client here is now configured to use certificates from your KeyStore. However it will only trust the certificates in your KeyStore and will not trust anything else, even if your system trust them by default. (If you have only self signed certs in your KeyStore and try to connect to Google main page via HTTPS you will get SSLHandshakeException).

You can obtain KeyStore instance from file as seen in docs:

KeyStore readKeyStore() {
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

    // get user password and file input stream
    char[] password = getPassword();

    java.io.FileInputStream fis = null;
    try {
        fis = new java.io.FileInputStream("keyStoreName");
        ks.load(fis, password);
    } finally {
        if (fis != null) {
            fis.close();
        }
    }
    return ks;
}

If you are on android you can put it in res/raw folder and get it from a Context instance using

fis = context.getResources().openRawResource(R.raw.your_keystore_filename);

There are several discussions on how to create your keystore. For example here

selectAll
  • 7
  • 2
Andrey Makarov
  • 1,026
  • 1
  • 10
  • 12
  • Where do I get the SSLContext from? – Oliver Dixon Dec 08 '16 at 12:48
  • To accept the system CA certs plus a custom keystore of certs look at [this answer](http://stackoverflow.com/a/35759057/726777). – DreamOfMirrors Jan 17 '17 at 00:52
  • 3
    Method "sslSocketFactory(SSLSocketFactory)" from OkHttpBuilder is now deprecated and we should use "sslSoocketFactory(SSLSocketFactory, X506TrustManager)". This prevent the application to make some reflections. Source : https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.Builder.html#sslSocketFactory-javax.net.ssl.SSLSocketFactory-javax.net.ssl.X509TrustManager- – MHogge Feb 17 '17 at 14:01
  • fis = context.getResources().openRawResource(R.raw.your_keystore_filename); - java.lang.ClassCastException: android.content.res.AssetManager$AssetInputStream cannot be cast to java.io.FileInputStream – Zon May 03 '17 at 05:04
  • No need for FileInputStream, InputStream will do. – Zon May 03 '17 at 05:13
  • Line of code - client.setSslSocketFactory(sslContext.getSocketFactory()); will not be compiled. Reason - setSslSocketFactory is not available in ok http client. Is is avaialable in builder of ok http client - Replace above line as - builder.sslSocketFactory(sslContext.getSocketFactory()); where OkHttpClient client = new OkHttpClient(); OkHttpClient.Builder builder = client.newBuilder(); Reference - https://github.com/square/okhttp/blob/3f7a3344a4c85aa3bbb879dabac5ee625ab987f3/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java#L54 – Dinakar Prasad Maurya Feb 05 '18 at 06:13
  • 1
    Is is safe to put the keystore as a raw resource in your apk? – PrashanD Dec 16 '19 at 04:59
  • I tried this and got "IOException: Wrong version of key store" – Bencri Mar 04 '20 at 16:01
  • 1
    @PrashanD yes it's safe, cert is generally safe to be published. – Michał Klimczak Mar 27 '20 at 06:34
  • keyManagerFactory.init should be passed with the correct KeyStore password IMAO not "keystore_pass".toCharArray() – CodeSun Jan 11 '23 at 08:22
15

Another thing to note, if you pre-install the CA on the device, you can make regular https calls with OKHttp, and no special ssl hoops. The key is to add the network security configs to your manifest.

The key for me to know to do this was that I was getting the following exception.

"Trust anchor for certification path not found."

Here is a good article from Google about how to configure it. https://developer.android.com/training/articles/security-config

Here is an example of my network_security_config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="user"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>
Brian S
  • 3,096
  • 37
  • 55
  • Although, this may not be direct answer to the question, this help me fix: `javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.` – vijay Apr 09 '20 at 05:47
  • Thanks, exact answer I was looking for a long time – DFJ Apr 28 '20 at 10:02
  • Doesn't work, at least, in Android emulator API 21. Tried many variants of the XML file. – CoolMind Jun 17 '20 at 09:32
  • I'm sure I'm missing something, but the attached document states that API 23 and below trust by default. By default, secure connections (using protocols like TLS and HTTPS) from all apps trust the pre-installed system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default – Brian S Jun 17 '20 at 11:45
  • 2
    Wish I could +10000! I've searched hundreds of other answers to similar questions and this is the only that fixed it. I'm on Android 29 and this still was needed (at least user trust is). In my case I'm on an intranet accessing an internal site with a company-issued root cert installed on the device. – Samuel Neff May 31 '21 at 15:08
12

For okhttp3.OkHttpClient Version com.squareup.okhttp3:okhttp:3.2.0 you have to use the code below :

import okhttp3.Call;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

......

OkHttpClient.Builder clientBuilder = client.newBuilder().readTimeout(LOGIN_TIMEOUT_SEC, TimeUnit.SECONDS);

            boolean allowUntrusted = true;

            if (  allowUntrusted) {
                Log.w(TAG,"**** Allow untrusted SSL connection ****");
                final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        X509Certificate[] cArrr = new X509Certificate[0];
                        return cArrr;
                    }

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

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

                SSLContext sslContext = SSLContext.getInstance("SSL");

                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                clientBuilder.sslSocketFactory(sslContext.getSocketFactory());

                HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        Log.d(TAG, "Trust Host :" + hostname);
                        return true;
                    }
                };
                clientBuilder.hostnameVerifier( hostnameVerifier);
            }

            final Call call = clientBuilder.build().newCall(request);
Gugelhupf
  • 943
  • 12
  • 16
  • 12
    Downvoted because this disables hostname verification, removing man in the middle protection. – Bryan Mar 10 '17 at 14:30
  • 5
    This solution is only for debugging in case you have no vaild SSL certificate. Not for production code ! – Gugelhupf Sep 12 '19 at 08:54
  • 2
    The OkHttpClient.Builder clientBuilder.sslSocketFactory() *deprecated* and didn't work with Android 10 anymore. Please don't use my suggestion anymore. – Gugelhupf May 11 '20 at 06:27
  • 2
    @Gugelhupf just change `clientBuilder.sslSocketFactory(sslContext.getSocketFactory());` to `clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), trustAllCerts[0]);` and it works again. Only the first overload is deprecated. – Agent_L Aug 30 '21 at 10:13
6

Two methods from our app to get OkHttpClient 3.0 instance that recognizes your self-signed certificates from your keystore (uses prepared pkcs12 certificate file in your Android project "raw" resources folder):

private static OkHttpClient getSSLClient(Context context) throws
                              NoSuchAlgorithmException,
                              KeyStoreException,
                              KeyManagementException,
                              CertificateException,
                              IOException {

  OkHttpClient client;
  SSLContext sslContext;
  SSLSocketFactory sslSocketFactory;
  TrustManager[] trustManagers;
  TrustManagerFactory trustManagerFactory;
  X509TrustManager trustManager;

  trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  trustManagerFactory.init(readKeyStore(context));
  trustManagers = trustManagerFactory.getTrustManagers();

  if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
    throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
  }

  trustManager = (X509TrustManager) trustManagers[0];

  sslContext = SSLContext.getInstance("TLS");

  sslContext.init(null, new TrustManager[]{trustManager}, null);

  sslSocketFactory = sslContext.getSocketFactory();

  client = new OkHttpClient.Builder()
      .sslSocketFactory(sslSocketFactory, trustManager)
      .build();
  return client;
}

/**
 * Get keys store. Key file should be encrypted with pkcs12 standard. It    can be done with standalone encrypting java applications like "keytool". File password is also required.
 *
 * @param context Activity or some other context.
 * @return Keys store.
 * @throws KeyStoreException
 * @throws CertificateException
 * @throws NoSuchAlgorithmException
 * @throws IOException
*/
private static KeyStore readKeyStore(Context context) throws
                          KeyStoreException,
                          CertificateException,
                          NoSuchAlgorithmException,
                          IOException {
  KeyStore keyStore;
  char[] PASSWORD = "12345678".toCharArray();
  ArrayList<InputStream> certificates;
  int certificateIndex;
  InputStream certificate;

  certificates = new ArrayList<>();
  certificates.add(context.getResources().openRawResource(R.raw.ssl_pkcs12));

keyStore = KeyStore.getInstance("pkcs12");

for (Certificate certificate : certificates) {
    try {
      keyStore.load(certificate, PASSWORD);
    } finally {
      if (certificate != null) {
        certificate.close();
      }
    }
  }
  return keyStore;
}
Sky Kelsey
  • 19,192
  • 5
  • 36
  • 77
Zon
  • 18,610
  • 7
  • 91
  • 99
  • ```certificates.add(context.getResources().openRawResource(R.raw.ssl_pkcs12));``` this line show error can you please give the reason why?? is there a why to class this from non activity class – Raj Kumar Jun 13 '19 at 11:10
4

I had the same problem and I fixed it with the okhttp client as follow:

1.) Add the certificate file to src/main/res/raw/, which includes this content:

-----BEGIN CERTIFICATE-----
...=
-----END CERTIFICATE-----

2.) Instanciate the okHttpClient:

OkHttpClient client = new OkHttpClient.Builder()
                .sslSocketFactory(getSslContext(context).getSocketFactory())
                .build();

3.) Here is the used getSslContext(Context context) method:

SSLContext getSslContext(Context context) throws Exception {
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); // "BKS"
    ks.load(null, null);

    InputStream is = context.getResources().openRawResource(R.raw.certificate);
    String certificate = Converter.convertStreamToString(is);

    // generate input stream for certificate factory
    InputStream stream = IOUtils.toInputStream(certificate);

    // CertificateFactory
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    // certificate
    Certificate ca;
    try {
        ca = cf.generateCertificate(stream);
    } finally {
        is.close();
    }

    ks.setCertificateEntry("my-ca", ca);

    // TrustManagerFactory
    String algorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
    // Create a TrustManager that trusts the CAs in our KeyStore
    tmf.init(ks);

    // Create a SSLContext with the certificate that uses tmf (TrustManager)
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());

    return sslContext;
}

If there is the need to add multiple certificates to the SslContext, here is the solution.

Manuel Schmitzberger
  • 5,162
  • 3
  • 36
  • 45
1

Against Retrofit 1.9 I was able to accept any certificate with the following strategy: use at your own risk! Accepting any certificate is dangerous and you should understand the consequences. Some relevant parts come from org.apache.http.ssl, so you may require some imports here.

// ...

    Client httpClient = getHttpClient();

    RestAdapter adapter = new RestAdapter.Builder()
        .setClient(httpClient)
        // ... the rest of your builder setup
        .build();

// ...

private Client getHttpClient() {
    try {
        // Allow self-signed (and actually any) SSL certificate to be trusted in this context
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

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

        sslContext.getSocketFactory();

        SSLSocketFactory sf = sslContext.getSocketFactory();

        OkHttpClient client = new OkHttpClient();
        client.setSslSocketFactory(sf);

        return new OkClient(client);
    } catch (Exception e) {
        throw new RuntimeException("Failed to create new HTTP client", e);
    }
}
jocull
  • 20,008
  • 22
  • 105
  • 149
1

I know that this post is quite old, bui i want to share the solution that worked for me with the latest update of OkHttp, the 3.12.1 version in the time i'm writing.

First of all you need to obtain the KeyStore object that will be then added to the TrustManager:

/**
 *  @param context The Android context to be used for retrieving the keystore from raw resource
 * @return the KeyStore read or null on error
 */
private static KeyStore readKeyStore(Context context) {

    char[] password = "keystore_password".toCharArray();

    // for non-android usage:
    // try(FileInputStream is = new FileInputStream(keystoreName)) {

    try(InputStream is = context.getResources().openRawResource(R.raw.keystore)) {
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(is, password);
        return ks;
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    }

    return null;
}

Now you can get the builded OkHttpClient with the self-signed certificate in your keystore:

/**
 * @param context The Android context used to obtain the KeyStore
 * @return the builded OkHttpClient or null on error
 */
public static OkHttpClient getOkHttpClient(Context context) {

    try {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());

        trustManagerFactory.init(readKeyStore(context));

        X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{trustManager}, null);

        return new OkHttpClient.Builder()
                .hostnameVerifier((hostname, session) -> {
                    HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
                    /* Never return true without verifying the hostname, otherwise you will be vulnerable
                    to man in the middle attacks. */
                    return  hv.verify("your_hostname_here", session);
                })
                .sslSocketFactory(sslContext.getSocketFactory(), trustManager)
                .build();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

Remember that it is highly discouraged to return always true in the hostnameVerifier to avoid risk of man in the middle attacks.

Domenico
  • 1,331
  • 18
  • 22
1

I find answer from :

https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java

It uses HandshakeCertificates to add certificates.

 HandshakeCertificates certificates = new HandshakeCertificates.Builder()
        .addTrustedCertificate(letsEncryptCertificateAuthority)
        .addTrustedCertificate(entrustRootCertificateAuthority)
        .addTrustedCertificate(comodoRsaCertificationAuthority)
        // Uncomment if standard certificates are also required.
        //.addPlatformTrustedCertificates()
        .build();

    client = new OkHttpClient.Builder()
            .sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager())
            .build();

If you have trust certificates in store, you can use it as below:

.......
List<X509Certificate> certificates = getCertificatesFromTrustStore();
        
Builder certificateBuilder =  new HandshakeCertificates.Builder();        
for (X509Certificate x509Certificate : certificates) {
    certificateBuilder.addTrustedCertificate(x509Certificate);
}
HandshakeCertificates handshakeCertificates =  certificateBuilder.build();
.......
//To get certificates from a keystore
private List<X509Certificate> getCertificatesFromTrustStore() throws Exception {
        KeyStore truststore = KeyStore.getInstance("JKS");
        truststore.load(new FileInputStream("d:\certs.jsk"), "mypassword".toCharArray());
        
        PKIXParameters params = new PKIXParameters(truststore);
        Set<TrustAnchor> trustAnchors = params.getTrustAnchors();
        LOG.debug("{} certificates found in {} which will be used", trustAnchors.size(), trustStorePath);
        
        List<X509Certificate> certificates = trustAnchors.stream()
                  .map(TrustAnchor::getTrustedCert)
                  .collect(Collectors.toList());
        return certificates;
    }
Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173
1

If you need to provide your own certificate, you can pass it like this:

Manifest:

<application android:networkSecurityConfig="@xml/network_security_config"
                    ... >

res/xml/network_security_config.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
    <trust-anchors>
        <certificates src="@raw/your_PEM_formatted_cert" />
        <certificates src="user" />
        <certificates src="system" />
    </trust-anchors>
</base-config>
Oleksandr Nos
  • 332
  • 5
  • 17
-4

The following piece of code allows you to create an OkHttp client that can be used with Retrofit. Mailmustdie's answer is "better" in the sense that it is more secure, but the code snippet below is faster to implement

import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.ResponseBody;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okio.BufferedSink;
import retrofit.client.Header;
import retrofit.client.OkClient;
import retrofit.client.Request;
import retrofit.client.Response;
import retrofit.mime.TypedInput;
import retrofit.mime.TypedOutput;

import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class TrustingOkClient extends OkClient {

static final int CONNECT_TIMEOUT_MILLIS = 15 * 1000; // 15s
static final int READ_TIMEOUT_MILLIS = 20 * 1000; // 20s

private static OkHttpClient generateDefaultOkHttp() {
    OkHttpClient client = new OkHttpClient();
    client.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    client.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);



    final TrustManager[] certs = new TrustManager[]{new X509TrustManager() {

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

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

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

    SSLContext ctx = null;
    try {
        ctx = SSLContext.getInstance("TLS");
        ctx.init(null, certs, new SecureRandom());
    } catch (final java.security.GeneralSecurityException ex) {
    }

    try {
        final HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(final String hostname,
                                  final SSLSession session) {
                return true;
            }
        };
        client.setHostnameVerifier(hostnameVerifier);
        client.setSslSocketFactory(ctx.getSocketFactory());
    } catch (final Exception e) {
    }
    return client;
}

private final OkHttpClient client;

public TrustingOkClient() {
    this(generateDefaultOkHttp());
}

public TrustingOkClient(OkHttpClient client) {
    if (client == null) throw new NullPointerException("client == null");
    this.client = client;
}

@Override public Response execute(Request request) throws IOException {
    return parseResponse(client.newCall(createRequest(request)).execute());
}

static com.squareup.okhttp.Request createRequest(Request request) {
    com.squareup.okhttp.Request.Builder builder = new com.squareup.okhttp.Request.Builder()
            .url(request.getUrl())
            .method(request.getMethod(), createRequestBody(request.getBody()));

    List<Header> headers = request.getHeaders();
    for (int i = 0, size = headers.size(); i < size; i++) {
        Header header = headers.get(i);
        String value = header.getValue();
        if (value == null) value = "";
        builder.addHeader(header.getName(), value);
    }

    return builder.build();
}

static Response parseResponse(com.squareup.okhttp.Response response) {
    return new Response(response.request().urlString(), response.code(), response.message(),
            createHeaders(response.headers()), createResponseBody(response.body()));
}

private static RequestBody createRequestBody(final TypedOutput body) {
    if (body == null) {
        return null;
    }
    final MediaType mediaType = MediaType.parse(body.mimeType());
    return new RequestBody() {
        @Override public MediaType contentType() {
            return mediaType;
        }

        @Override public void writeTo(BufferedSink sink) throws IOException {
            body.writeTo(sink.outputStream());
        }

        @Override public long contentLength() {
            return body.length();
        }
    };
}

private static TypedInput createResponseBody(final ResponseBody body) {
    try {
        if (body.contentLength() == 0) {
            return null;
        }
        return new TypedInput() {
            @Override public String mimeType() {
                MediaType mediaType = body.contentType();
                return mediaType == null ? null : mediaType.toString();
            }

            @Override public long length() {
                try {
                    return body.contentLength();
                } catch (Exception exception) {
                    System.out.println(exception.toString());
                }
                throw new Error("createResponseBody has invalid length for its response");
            }

            @Override public InputStream in() throws IOException {
                return body.byteStream();
            }
        };
    } catch (Exception exception) {
        System.out.println(exception.toString());
    }
    throw new Error("createResponseBody has invalid content length for its response");
}

private static List<Header> createHeaders(Headers headers) {
    int size = headers.size();
    List<Header> headerList = new ArrayList<Header>(size);
    for (int i = 0; i < size; i++) {
        headerList.add(new Header(headers.name(i), headers.value(i)));
    }
    return headerList;
}

}
rekire
  • 47,260
  • 30
  • 167
  • 264
Bruno Carrier
  • 530
  • 5
  • 8
  • 8
    I'd like to point out that this is not just "less secure" than the accepted answer, it's completely insecure. – GreyBeardedGeek Mar 08 '16 at 19:28
  • 1
    The solution allows for https to be used over HTTP, which is more secure, but doesn't protect against man in the middle attack. It's somewhat better than not secure at all, and allows for an app in development to connect to an https service that would later get a proper certificate for 50 dollars. Much better than spending many hours getting a self-signed certificate to work with an Android client – Bruno Carrier Mar 09 '16 at 21:29
  • 1
    Downvoted because this disables hostname verification, removing man in the middle protection. Accepted answer should not take 'many hours' to implement. – Bryan Mar 10 '17 at 14:30