Last active
November 8, 2019 16:23
-
-
Save demixdn/3886de5a71dc2812c8f4d27a248a506b to your computer and use it in GitHub Desktop.
Retrofit with self signed https certificate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package <you_package>.data.api; | |
import android.content.Context; | |
import android.support.annotation.NonNull; | |
import com.google.gson.ExclusionStrategy; | |
import com.google.gson.FieldAttributes; | |
import com.google.gson.Gson; | |
import com.google.gson.GsonBuilder; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.security.KeyManagementException; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.cert.Certificate; | |
import java.security.cert.CertificateException; | |
import java.security.cert.CertificateFactory; | |
import java.util.concurrent.TimeUnit; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.TrustManagerFactory; | |
import io.realm.RealmObject; | |
import okhttp3.OkHttpClient; | |
import okhttp3.Request; | |
import okhttp3.logging.HttpLoggingInterceptor; | |
import retrofit2.GsonConverterFactory; | |
import retrofit2.Retrofit; | |
import retrofit2.RxJavaCallAdapterFactory; | |
import <you_package>.BuildConfig; | |
import <you_package>.utils.LogUtils; | |
public class ApiModule { | |
@NonNull | |
private final String baseUrl; | |
@NonNull | |
private static Gson gson; | |
@NonNull | |
private final OkHttpClient.Builder httpClientBuilder; | |
/** | |
* Create Rertofit params: logging, ssl connection and access token | |
* @param baseUrl endpoint of service | |
* @param authToken access token for connection, must be NULL in auth request | |
*/ | |
public ApiModule(@NonNull String baseUrl, @NonNull Context context, String authToken){ | |
this.baseUrl = baseUrl; | |
httpClientBuilder = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS); | |
initGson(); | |
initHttpLogging(HttpLoggingInterceptor.Level.BODY); | |
initSSL(context); | |
initAuthToken(authToken); | |
} | |
private void initGson() { | |
GsonBuilder gsonBuilder = new GsonBuilder(); | |
gsonBuilder.setExclusionStrategies(new ExclusionStrategy() { | |
@Override | |
public boolean shouldSkipField(FieldAttributes f) { | |
return f.getDeclaringClass().equals(RealmObject.class); | |
} | |
@Override | |
public boolean shouldSkipClass(Class<?> clazz) { | |
return false; | |
} | |
}); | |
gson = gsonBuilder.create(); | |
} | |
private void initHttpLogging(HttpLoggingInterceptor.Level level) { | |
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); | |
logging.setLevel(level); | |
if(BuildConfig.DEBUG) | |
httpClientBuilder.addInterceptor(logging); | |
} | |
/** | |
* ToDo modify this: set param is InputStream from certificate file,move beyond the context of the module | |
* @param context for read InputSream from raw resources | |
*/ | |
private void initSSL(@NonNull Context context) { | |
SSLContext sslContext = null; | |
try { | |
sslContext = createCertificate(context.getResources().openRawResource(R.raw.certificate)); | |
} catch (CertificateException | IOException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) { | |
e.printStackTrace(); | |
} | |
if(sslContext!=null) | |
httpClientBuilder.sslSocketFactory(sslContext.getSocketFactory()); | |
} | |
public void initAuthToken(String authToken) { | |
LogUtils.E("initAuthToken - "+authToken); | |
if (authToken != null) { | |
httpClientBuilder.addInterceptor(chain -> { | |
Request original = chain.request(); | |
Request.Builder requestBuilder = original.newBuilder() | |
.header("Authorization", authToken) | |
.method(original.method(), original.body()); | |
Request request = requestBuilder.build(); | |
return chain.proceed(request); | |
}); | |
} | |
} | |
private SSLContext createCertificate(InputStream trustedCertificateIS) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException { | |
CertificateFactory cf = CertificateFactory.getInstance("X.509"); | |
Certificate ca; | |
try { | |
ca = cf.generateCertificate(trustedCertificateIS); | |
} finally { | |
trustedCertificateIS.close(); | |
} | |
// creating a KeyStore containing our trusted CAs | |
String keyStoreType = KeyStore.getDefaultType(); | |
KeyStore keyStore = KeyStore.getInstance(keyStoreType); | |
keyStore.load(null, null); | |
keyStore.setCertificateEntry("ca", ca); | |
// creating a TrustManager that trusts the CAs in our KeyStore | |
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); | |
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); | |
tmf.init(keyStore); | |
// creating an SSLSocketFactory that uses our TrustManager | |
SSLContext sslContext = SSLContext.getInstance("TLS"); | |
sslContext.init(null, tmf.getTrustManagers(), null); | |
return sslContext; | |
} | |
@NonNull | |
public RestAPI provideApiRx() | |
{ | |
return new Retrofit.Builder() | |
.baseUrl(baseUrl) | |
.addConverterFactory(GsonConverterFactory.create(gson)) | |
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) | |
.client(httpClientBuilder.build()) | |
.build() | |
.create(RestAPI.class); | |
} | |
@NonNull | |
public RestAPI provideApi() | |
{ | |
return new Retrofit.Builder() | |
.baseUrl(baseUrl) | |
.addConverterFactory(GsonConverterFactory.create(gson)) | |
.client(httpClientBuilder.build()) | |
.build() | |
.create(RestAPI.class); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The raw certificate contents might look like this.
-----BEGIN CERTIFICATE----- MIIGJzCCBA+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjELMAkGA1UEBhMCRlIx DzANBgNVBAgMBkFsc2FjZTETMBEGA1UEBwwKU3RyYXNib3VyZzEYMBYGA1UECgwP d3d3LmZyZWVsYW4ub3JnMRAwDgYDVQQLDAdmcmVlbGFuMS0wKwYDVQQDDCRGcmVl bGFuIFNhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIjAgBgkqhkiG9w0BCQEW E2NvbnRhY3RAZnJlZWxhbi5vcmcwHhcNMTIwNDI3MTAzMTE4WhcNMjIwNDI1MTAz MTE4WjB+MQswCQYDVQQGEwJGUjEPMA0GA1UECAwGQWxzYWNlMRgwFgYDVQQKDA93 d3cuZnJlZWxhbi5vcmcxEDAOBgNVBAsMB2ZyZWVsYW4xDjAMBgNVBAMMBWFsaWNl MSIwIAYJKoZIhvcNAQkBFhNjb250YWN0QGZyZWVsYW4ub3JnMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEA3W29+ID6194bH6ejLrIC4hb2Ugo8v6ZC+Mrc k2dNYMNPjcOKABvxxEtBamnSaeU/IY7FC/giN622LEtV/3oDcrua0+yWuVafyxmZ yTKUb4/GUgafRQPf/eiX9urWurtIK7XgNGFNUjYPq4dSJQPPhwCHE/LKAykWnZBX RrX0Dq4XyApNku0IpjIjEXH+8ixE12wH8wt7DEvdO7T3N3CfUbaITl1qBX+Nm2Z6 q4Ag/u5rl8NJfXg71ZmXA3XOj7zFvpyapRIZcPmkvZYn7SMCp8dXyXHPdpSiIWL2 uB3KiO4JrUYvt2GzLBUThp+lNSZaZ/Q3yOaAAUkOx+1h08285Pi+P8lO+H2Xic4S vMq1xtLg2bNoPC5KnbRfuFPuUD2/3dSiiragJ6uYDLOyWJDivKGt/72OVTEPAL9o 6T2pGZrwbQuiFGrGTMZOvWMSpQtNl+tCCXlT4mWqJDRwuMGrI4DnnGzt3IKqNwS4 Qyo9KqjMIPwnXZAmWPm3FOKe4sFwc5fpawKO01JZewDsYTDxVj+cwXwFxbE2yBiF z2FAHwfopwaH35p3C6lkcgP2k/zgAlnBluzACUI+MKJ/G0gv/uAhj1OHJQ3L6kn1 SpvQ41/ueBjlunExqQSYD7GtZ1Kg8uOcq2r+WISE3Qc9MpQFFkUVllmgWGwYDuN3 Zsez95kCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNT TCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFlfyRO6G8y5qEFKikl5 ajb2fT7XMB8GA1UdIwQYMBaAFCNsLT0+KV14uGw+quK7Lh5sh/JTMA0GCSqGSIb3 DQEBBQUAA4ICAQAT5wJFPqervbja5+90iKxi1d0QVtVGB+z6aoAMuWK+qgi0vgvr mu9ot2lvTSCSnRhjeiP0SIdqFMORmBtOCFk/kYDp9M/91b+vS+S9eAlxrNCB5VOf PqxEPp/wv1rBcE4GBO/c6HcFon3F+oBYCsUQbZDKSSZxhDm3mj7pb67FNbZbJIzJ 70HDsRe2O04oiTx+h6g6pW3cOQMgIAvFgKN5Ex727K4230B0NIdGkzuj4KSML0NM slSAcXZ41OoSKNjy44BVEZv0ZdxTDrRM4EwJtNyggFzmtTuV02nkUj1bYYYC5f0L ADr6s0XMyaNk8twlWYlYDZ5uKDpVRVBfiGcq0uJIzIvemhuTrofh8pBQQNkPRDFT Rq1iTo1Ihhl3/Fl1kXk1WR3jTjNb4jHX7lIoXwpwp767HAPKGhjQ9cFbnHMEtkro RlJYdtRq5mccDtwT0GFyoJLLBZdHHMHJz0F9H7FNk2tTQQMhK5MVYwg+LIaee586 CQVqfbscp7evlgjLW98H+5zylRHAgoH2G79aHljNKMp9BOuq6SnEglEsiWGVtu2l hnx8SB3sVJZHeer8f/UQQwqbAO+Kdy70NmbSaqaVtp8jOxLiidWkwSyRTsuU6D8i DiH5uEqBXExjrj0FslxcVKdVj5glVcSmkLwZKbEU1OKwleT/iXFhvooWhQ== -----END CERTIFICATE-----
Note this is a sample.
Don't use it on production!