Skip to content

Commit 69911a1

Browse files
committed
Merge pull request #1311 from xhh/java-okhttp-gson-ssl
Add some SSL options to Java okhttp-gson client
2 parents 7610292 + f483f93 commit 69911a1

File tree

3 files changed

+239
-3
lines changed

3 files changed

+239
-3
lines changed

modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,9 @@ public List<CodegenSecurity> fromSecurity(Map<String, SecuritySchemeDefinition>
12991299
sec.flow = oauth2Definition.getFlow();
13001300
sec.authorizationUrl = oauth2Definition.getAuthorizationUrl();
13011301
sec.tokenUrl = oauth2Definition.getTokenUrl();
1302-
sec.scopes = oauth2Definition.getScopes().keySet();
1302+
if (oauth2Definition.getScopes() != null) {
1303+
sec.scopes = oauth2Definition.getScopes().keySet();
1304+
}
13031305
}
13041306

13051307
sec.hasMore = it.hasNext();

modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,31 @@ import java.net.URLEncoder;
3030
import java.net.URLConnection;
3131

3232
import java.io.File;
33+
import java.io.InputStream;
3334
import java.io.IOException;
3435
import java.io.UnsupportedEncodingException;
3536

37+
import java.security.GeneralSecurityException;
38+
import java.security.KeyStore;
39+
import java.security.SecureRandom;
40+
import java.security.cert.Certificate;
41+
import java.security.cert.CertificateException;
42+
import java.security.cert.CertificateFactory;
43+
import java.security.cert.X509Certificate;
44+
3645
import java.text.DateFormat;
3746
import java.text.SimpleDateFormat;
3847
import java.text.ParseException;
3948

49+
import javax.net.ssl.HostnameVerifier;
50+
import javax.net.ssl.KeyManager;
51+
import javax.net.ssl.KeyManagerFactory;
52+
import javax.net.ssl.SSLContext;
53+
import javax.net.ssl.SSLSession;
54+
import javax.net.ssl.TrustManager;
55+
import javax.net.ssl.TrustManagerFactory;
56+
import javax.net.ssl.X509TrustManager;
57+
4058
import okio.BufferedSink;
4159
import okio.Okio;
4260

@@ -64,12 +82,17 @@ public class ApiClient {
6482
private String datetimeFormat;
6583
private DateFormat datetimeFormatter;
6684
85+
private InputStream sslCaCert;
86+
private boolean verifyingSsl;
87+
6788
private OkHttpClient httpClient;
6889
private JSON json;
6990
7091
public ApiClient() {
7192
httpClient = new OkHttpClient();
7293
94+
verifyingSsl = true;
95+
7396
json = new JSON(this);
7497
7598
// Use ISO 8601 format for date and datetime.
@@ -134,6 +157,35 @@ public class ApiClient {
134157
return responseHeaders;
135158
}
136159

160+
public boolean isVerifyingSsl() {
161+
return verifyingSsl;
162+
}
163+
164+
/**
165+
* Configure whether to verify certificate and hostname when making https requests.
166+
* Default to true.
167+
* NOTE: Do NOT set to false in production code, otherwise you would face multiple types of cryptographic attacks.
168+
*/
169+
public ApiClient setVerifyingSsl(boolean verifyingSsl) {
170+
this.verifyingSsl = verifyingSsl;
171+
applySslSettings();
172+
return this;
173+
}
174+
175+
public InputStream getSslCaCert() {
176+
return sslCaCert;
177+
}
178+
179+
/**
180+
* Configure the CA certificate to be trusted when making https requests.
181+
* Use null to reset to default.
182+
*/
183+
public ApiClient setSslCaCert(InputStream sslCaCert) {
184+
this.sslCaCert = sslCaCert;
185+
applySslSettings();
186+
return this;
187+
}
188+
137189
public String getDateFormat() {
138190
return dateFormat;
139191
}
@@ -501,7 +553,7 @@ public class ApiClient {
501553
}
502554

503555
/**
504-
* Deserialize response body to Java object, according the Content-Type
556+
* Deserialize response body to Java object, according to the Content-Type
505557
* response header.
506558
*
507559
* @param response HTTP response
@@ -840,4 +892,69 @@ public class ApiClient {
840892
return contentType;
841893
}
842894
}
895+
896+
/**
897+
* Apply SSL related settings to httpClient according to the current values of
898+
* verifyingSsl and sslCaCert.
899+
*/
900+
private void applySslSettings() {
901+
try {
902+
KeyManager[] keyManagers = null;
903+
TrustManager[] trustManagers = null;
904+
HostnameVerifier hostnameVerifier = null;
905+
if (!verifyingSsl) {
906+
TrustManager trustAll = new X509TrustManager() {
907+
@Override
908+
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
909+
@Override
910+
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
911+
@Override
912+
public X509Certificate[] getAcceptedIssuers() { return null; }
913+
};
914+
SSLContext sslContext = SSLContext.getInstance("TLS");
915+
trustManagers = new TrustManager[]{ trustAll };
916+
hostnameVerifier = new HostnameVerifier() {
917+
@Override
918+
public boolean verify(String hostname, SSLSession session) { return true; }
919+
};
920+
} else if (sslCaCert != null) {
921+
char[] password = null; // Any password will work.
922+
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
923+
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(sslCaCert);
924+
if (certificates.isEmpty()) {
925+
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
926+
}
927+
KeyStore caKeyStore = newEmptyKeyStore(password);
928+
int index = 0;
929+
for (Certificate certificate : certificates) {
930+
String certificateAlias = "ca" + Integer.toString(index++);
931+
caKeyStore.setCertificateEntry(certificateAlias, certificate);
932+
}
933+
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
934+
trustManagerFactory.init(caKeyStore);
935+
trustManagers = trustManagerFactory.getTrustManagers();
936+
}
937+
938+
if (keyManagers != null || trustManagers != null) {
939+
SSLContext sslContext = SSLContext.getInstance("TLS");
940+
sslContext.init(keyManagers, trustManagers, new SecureRandom());
941+
httpClient.setSslSocketFactory(sslContext.getSocketFactory());
942+
} else {
943+
httpClient.setSslSocketFactory(null);
944+
}
945+
httpClient.setHostnameVerifier(hostnameVerifier);
946+
} catch (GeneralSecurityException e) {
947+
throw new RuntimeException(e);
948+
}
949+
}
950+
951+
private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
952+
try {
953+
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
954+
keyStore.load(null, password);
955+
return keyStore;
956+
} catch (IOException e) {
957+
throw new AssertionError(e);
958+
}
959+
}
843960
}

samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,31 @@
3030
import java.net.URLConnection;
3131

3232
import java.io.File;
33+
import java.io.InputStream;
3334
import java.io.IOException;
3435
import java.io.UnsupportedEncodingException;
3536

37+
import java.security.GeneralSecurityException;
38+
import java.security.KeyStore;
39+
import java.security.SecureRandom;
40+
import java.security.cert.Certificate;
41+
import java.security.cert.CertificateException;
42+
import java.security.cert.CertificateFactory;
43+
import java.security.cert.X509Certificate;
44+
3645
import java.text.DateFormat;
3746
import java.text.SimpleDateFormat;
3847
import java.text.ParseException;
3948

49+
import javax.net.ssl.HostnameVerifier;
50+
import javax.net.ssl.KeyManager;
51+
import javax.net.ssl.KeyManagerFactory;
52+
import javax.net.ssl.SSLContext;
53+
import javax.net.ssl.SSLSession;
54+
import javax.net.ssl.TrustManager;
55+
import javax.net.ssl.TrustManagerFactory;
56+
import javax.net.ssl.X509TrustManager;
57+
4058
import okio.BufferedSink;
4159
import okio.Okio;
4260

@@ -64,12 +82,17 @@ public class ApiClient {
6482
private String datetimeFormat;
6583
private DateFormat datetimeFormatter;
6684

85+
private InputStream sslCaCert;
86+
private boolean verifyingSsl;
87+
6788
private OkHttpClient httpClient;
6889
private JSON json;
6990

7091
public ApiClient() {
7192
httpClient = new OkHttpClient();
7293

94+
verifyingSsl = true;
95+
7396
json = new JSON(this);
7497

7598
// Use ISO 8601 format for date and datetime.
@@ -133,6 +156,35 @@ public Map<String, List<String>> getResponseHeaders() {
133156
return responseHeaders;
134157
}
135158

159+
public boolean isVerifyingSsl() {
160+
return verifyingSsl;
161+
}
162+
163+
/**
164+
* Configure whether to verify certificate and hostname when making https requests.
165+
* Default to true.
166+
* NOTE: Do NOT set to false in production code, otherwise you would face multiple types of cryptographic attacks.
167+
*/
168+
public ApiClient setVerifyingSsl(boolean verifyingSsl) {
169+
this.verifyingSsl = verifyingSsl;
170+
applySslSettings();
171+
return this;
172+
}
173+
174+
public InputStream getSslCaCert() {
175+
return sslCaCert;
176+
}
177+
178+
/**
179+
* Configure the CA certificate to be trusted when making https requests.
180+
* Use null to reset to default.
181+
*/
182+
public ApiClient setSslCaCert(InputStream sslCaCert) {
183+
this.sslCaCert = sslCaCert;
184+
applySslSettings();
185+
return this;
186+
}
187+
136188
public String getDateFormat() {
137189
return dateFormat;
138190
}
@@ -500,7 +552,7 @@ public String escapeString(String str) {
500552
}
501553

502554
/**
503-
* Deserialize response body to Java object, according the Content-Type
555+
* Deserialize response body to Java object, according to the Content-Type
504556
* response header.
505557
*
506558
* @param response HTTP response
@@ -839,4 +891,69 @@ public String guessContentTypeFromFile(File file) {
839891
return contentType;
840892
}
841893
}
894+
895+
/**
896+
* Apply SSL related settings to httpClient according to the current values of
897+
* verifyingSsl and sslCaCert.
898+
*/
899+
private void applySslSettings() {
900+
try {
901+
KeyManager[] keyManagers = null;
902+
TrustManager[] trustManagers = null;
903+
HostnameVerifier hostnameVerifier = null;
904+
if (!verifyingSsl) {
905+
TrustManager trustAll = new X509TrustManager() {
906+
@Override
907+
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
908+
@Override
909+
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
910+
@Override
911+
public X509Certificate[] getAcceptedIssuers() { return null; }
912+
};
913+
SSLContext sslContext = SSLContext.getInstance("TLS");
914+
trustManagers = new TrustManager[]{ trustAll };
915+
hostnameVerifier = new HostnameVerifier() {
916+
@Override
917+
public boolean verify(String hostname, SSLSession session) { return true; }
918+
};
919+
} else if (sslCaCert != null) {
920+
char[] password = null; // Any password will work.
921+
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
922+
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(sslCaCert);
923+
if (certificates.isEmpty()) {
924+
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
925+
}
926+
KeyStore caKeyStore = newEmptyKeyStore(password);
927+
int index = 0;
928+
for (Certificate certificate : certificates) {
929+
String certificateAlias = "ca" + Integer.toString(index++);
930+
caKeyStore.setCertificateEntry(certificateAlias, certificate);
931+
}
932+
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
933+
trustManagerFactory.init(caKeyStore);
934+
trustManagers = trustManagerFactory.getTrustManagers();
935+
}
936+
937+
if (keyManagers != null || trustManagers != null) {
938+
SSLContext sslContext = SSLContext.getInstance("TLS");
939+
sslContext.init(keyManagers, trustManagers, new SecureRandom());
940+
httpClient.setSslSocketFactory(sslContext.getSocketFactory());
941+
} else {
942+
httpClient.setSslSocketFactory(null);
943+
}
944+
httpClient.setHostnameVerifier(hostnameVerifier);
945+
} catch (GeneralSecurityException e) {
946+
throw new RuntimeException(e);
947+
}
948+
}
949+
950+
private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
951+
try {
952+
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
953+
keyStore.load(null, password);
954+
return keyStore;
955+
} catch (IOException e) {
956+
throw new AssertionError(e);
957+
}
958+
}
842959
}

0 commit comments

Comments
 (0)