J'ai écrit le code pour appeler REST-API avec SSL en utilisant OkHttp3. Il existe de nombreux exemples dans le monde qui se connectent sans valider le certificat, mais ce code effectue la validation suivante.
Obtenez le certificat de serveur à partir de l'endroit où l'API est publiée. Cette fois, je l'ai obtenu de Recruit dans le navigateur (Chrome). Vous pouvez trouver différentes manières de l'obtenir en recherchant «Comment obtenir un navigateur de certificat de serveur». Le format du fichier d'exportation est "X.509 encodé en base 64".
C'est celui au dessus du certificat dans le "chemin de certification". Obtenez-le de la même manière que ci-dessus.
Ouvrez les deux certificats ci-dessus avec un éditeur de texte et copiez-collez l'un d'eux dans un seul. J'ai présenté les parents comme une «carte de certification».
Déployez les fichiers fusionnés vers un emplacement de votre chemin de classe.
API(SSL)Classe d'exécution
public class RestSecureApiExecutor extends RestApiExecutor {
private CertificateManager certMgr;
/**
*constructeur.
*
* @Attribut d'API sécurisé param apiAttr
*/
public RestSecureApiExecutor(SecureApiAttribute apiAttr) {
super(apiAttr);
this.certMgr = apiAttr.getCertMgr();
}
/**
* {@inheritDoc}
*/
@Override
public Response get(Map<String, String> header, Map<String, String> param, boolean isValidCache) throws IOException {
//Assemblage d'URL
HttpUrl.Builder urlBuilder = createUrlBuilder(ProtocolType.Secure, param);
//Assembler les en-têtes HTTP
Request.Builder requestBuilder = createRequestBuilder(header);
//Utiliser ou non le cache
if (!isValidCache) {
requestBuilder.cacheControl(new CacheControl.Builder().noCache().noStore().maxAge(0, TimeUnit.SECONDS).build());
}
//Assembler la demande
Request request = requestBuilder.url(urlBuilder.build()).build();
//Utiliser ou non le cache
OkHttpClient.Builder clientBuilder = createClientBuilder(isValidCache);
addCertificatePinner(clientBuilder, certMgr.getCertificates());
addSslSocketFactory(clientBuilder, certMgr.getTrustManager());
//Exécution de l'API
return clientBuilder.build().newCall(request).execute();
}
/**
*Ajouter CertificatePinner au générateur.
*
* @param builder OkHttpClient.Objet constructeur
* @certificats param Informations sur le certificat
*/
private void addCertificatePinner(OkHttpClient.Builder builder, Certificate[] certificates) {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(this.hostname, CertificatePinner.pin(certificates[0]))
.build();
builder.certificatePinner(certificatePinner);
}
/**
*Ajouter SslSocketFactory au générateur.
*
* @param builder OkHttpClient.Objet constructeur
* @param trustManager TrustManager
*/
private void addSslSocketFactory(OkHttpClient.Builder builder, X509TrustManager trustManager) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { trustManager }, null);
builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException("____ failed to create ssl socket factory.", e);
}
}
Classe parent
public class RestApiExecutor {
/**
*Type de protocole.
*/
public enum ProtocolType {
/**Ordinaire. */
Normal("http"),
/** SSL. */
Secure("https"),;
private String type;
private ProtocolType(String type) {
this.type = type;
}
public String getValue() {
return this.type;
}
}
/**nom d'hôte. */
protected String hostname;
/**segment. */
protected String segment;
/**
*constructeur.
*
* @attribut API param apiAttr
*/
public RestApiExecutor(ApiAttribute apiAttr) {
//Nom d'hôte, segment
this.hostname = apiAttr.getHostname();
this.segment = apiAttr.getSegment();
}
/**
* REST API (get)Courir.
*
* @param header paramètres d'en-tête HTTP
* @param param paramètres de requête
* @param isValidCache Utiliser le cache (true: use, false: not use)
* @réponse de retour
* @jette IOException si le traitement échoue
*/
public Response get(Map<String, String> header, Map<String, String> param, boolean isValidCache) throws IOException {
//Assemblage d'URL
HttpUrl.Builder urlBuilder = createUrlBuilder(ProtocolType.Normal, param);
//Assembler les en-têtes HTTP
Request.Builder requestBuilder = createRequestBuilder(header);
//Utiliser ou non le cache
if (!isValidCache) {
requestBuilder.cacheControl(new CacheControl.Builder().noCache().noStore().maxAge(0, TimeUnit.SECONDS).build());
}
//Assembler la demande
Request request = requestBuilder.url(urlBuilder.build()).build();
//Utiliser ou non le cache
OkHttpClient.Builder clientBuilder = createClientBuilder(isValidCache);
//Exécution de l'API
return clientBuilder.build().newCall(request).execute();
}
/**
*Assemblez l'URL.
*
* @param type ProtocolType
* @paramètre param paramètre
* @return HttpUrl.Objet constructeur
*/
protected HttpUrl.Builder createUrlBuilder(ProtocolType type, Map<String, String> param) {
//Générateur d'URL
HttpUrl.Builder builder = new HttpUrl.Builder();
//Schéma(http or https)
builder.scheme(type.getValue());
//nom d'hôte
builder.host(this.hostname);
//segment
builder.addPathSegments(this.segment);
if (param != null) {
//Paramètres de requête
param.forEach(builder::addQueryParameter);
}
return builder;
}
/**
*Assemblez l'en-tête HTTP.
*
* @paramètre param paramètre
* @return Request.Objet constructeur
*/
protected Request.Builder createRequestBuilder(Map<String, String> param) {
Request.Builder builder = new Request.Builder();
builder.addHeader("Content-Type", "application/json");
if (param != null) {
param.forEach(builder::addHeader);
}
return builder;
}
/**
*Assemblez le client HTTP.
*
* @param isValidCache Avec ou sans cache
* @return OkHttpClient.Objet constructeur
*/
protected OkHttpClient.Builder createClientBuilder(boolean isValidCache) {
//Utiliser ou non le cache
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (!isValidCache) {
builder.cache(null);
}
return builder;
}
Lecture de certificat
public class CertificateLoader {
/**
*Lire le certificat.
*
* @chemin du paramètre Chemin du certificat
* @retourne le tableau X509Certificate
*/
public X509Certificate[] load(String path) {
List<X509Certificate> certificateList = new ArrayList<>();
try {
Collection<? extends Certificate> certificates = getCertificates(path);
for (Certificate certificate : certificates) {
X509Certificate x509certificate = (X509Certificate) certificate;
x509certificate.checkValidity(); //Déterminez si le certificat est actuellement valide
certificateList.add(x509certificate);
}
} catch (CertificateExpiredException | CertificateNotYetValidException e) {
throw new RuntimeException("____ failed to check valid cer file.", e);
}
return certificateList.toArray(new X509Certificate[certificateList.size()]);
}
/**
*Obtenir des informations sur le certificat.
*
* @chemin du paramètre Chemin du certificat
* @retourner les informations du certificat
*/
private Collection<? extends Certificate> getCertificates(String path) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream in = this.getClass().getClassLoader().getResourceAsStream(path);
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
return certificates;
} catch (CertificateException e) {
throw new RuntimeException("____ failed to get certificates.");
}
}
Gestion des certificats
public class CertificateManager {
private CertificateLoader loader;
private X509Certificate[] certificates;
private X509TrustManager trustManager;
/**
*constructeur.
*
* @chemin du paramètre Chemin du certificat
*/
public CertificateManager(String path) {
this.loader = new CertificateLoader();
this.certificates = loader.load(path);
//Créez un gestionnaire de certificats et vérifiez qu'il s'agit d'un certificat de serveur de confiance
this.trustManager = createTrustManager(certificates);
checkServerTrusted(trustManager, certificates);
}
/**
*Obtenir des informations sur le certificat.
*
* @retourner les informations du certificat
*/
public X509Certificate[] getCertificates() {
return this.certificates;
}
/**
*Obtenez TrustManager.
*
* @return TrustManager
*/
public X509TrustManager getTrustManager() {
return this.trustManager;
}
/**
*Générer TrustManager.
*
* @certificats param Informations sur le certificat
* @return TrustManager
*/
private X509TrustManager createTrustManager(X509Certificate[] certificates) {
TrustManager[] trustManagers = null;
try {
char[] password = "password".toCharArray();
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
for (X509Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers : " + Arrays.toString(trustManagers));
}
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
throw new RuntimeException("____ failed to create trust manager.", e);
}
return (X509TrustManager) trustManagers[0];
}
/**
*Créer un objet KeyStore vide.
*
* @mot de passe param mot de passe
* @retourne un objet KeyStore vide
*/
private KeyStore newEmptyKeyStore(char[] password) {
KeyStore keyStore = getDefaultKeyStoreInstance();
try {
InputStream in = null;
keyStore.load(in, password);
} catch (NoSuchAlgorithmException | CertificateException | IOException e) {
throw new RuntimeException("____ failed to load from KeyStore.", e);
}
return keyStore;
}
/**
*Obtient l'objet KeyStore par défaut.
*
* @retourne l'objet KeyStore par défaut
*/
private KeyStore getDefaultKeyStoreInstance() {
try {
return KeyStore.getInstance(KeyStore.getDefaultType());
} catch (KeyStoreException e) {
throw new RuntimeException("____ failed to get KeyStore default instance.", e);
}
}
/**
*Vérifiez le certificat.
*
* @param trustManager TrustManager
* @certificats param Certificats
*/
private void checkServerTrusted(X509TrustManager trustManager, X509Certificate[] certificates) {
try {
trustManager.checkServerTrusted(certificates, "SHA256withRSA");
} catch (CertificateException e) {
throw new RuntimeException("____ failed to check server trust.", e);
}
}
La vérification du nom d'hôte le fait probablement, car elle n'implémente pas (remplace) la méthode de vérification HostnameVerifier.
c'est tout