Skip to content

Commit

Permalink
add https support (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
shzcore authored Jun 11, 2020
1 parent 0d90ae4 commit c2c5ba4
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 5 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.baidu.hugegraph</groupId>
<artifactId>hugegraph-common</artifactId>
<version>1.7.5</version>
<version>1.7.6</version>

<name>hugegraph-common</name>
<url>https://github.com/hugegraph/hugegraph-common</url>
Expand Down Expand Up @@ -260,7 +260,7 @@
<manifestEntries>
<!-- Must be on one line, otherwise the automatic
upgrade script cannot replace the version number -->
<Implementation-Version>1.7.5.0</Implementation-Version>
<Implementation-Version>1.7.6.0</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
Expand Down
108 changes: 106 additions & 2 deletions src/main/java/com/baidu/hugegraph/rest/RestClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,23 @@

import static org.glassfish.jersey.apache.connector.ApacheClientProperties.CONNECTION_MANAGER;

import java.net.URI;
import java.security.KeyManagementException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
Expand All @@ -40,6 +51,7 @@
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.glassfish.jersey.SslConfigurator;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
Expand Down Expand Up @@ -90,9 +102,70 @@ public RestClient(String url, String user, String password, int timeout,
.config(maxTotal, maxPerRoute)
.build());
}


public RestClient(String url, String user, String password, int timeout,
int maxTotal, int maxPerRoute, String protocol,
String trustStoreFile, String trustStorePassword) {
this(url, new ConfigBuilder().config(timeout)
.config(user, password)
.config(maxTotal, maxPerRoute)
.config(protocol, trustStoreFile,
trustStorePassword)
.build());
}

private TrustManager[] createNoCheckTrustManager() {
return new TrustManager[]{new NoCheckTrustManager()};
}

private static class NoCheckTrustManager 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 null;
}
}

private Client wrapTrustConfig(String url, ClientConfig config) {

SslConfigurator sslConfig = SslConfigurator.newInstance();
String trustStoreFile = config.getProperty("trustStoreFile").toString();
String trustStorePassword = config.getProperty("trustStorePassword").toString();
sslConfig.trustStoreFile(trustStoreFile)
.trustStorePassword(trustStorePassword);
sslConfig.securityProtocol("SSL");
SSLContext sc = sslConfig.createSSLContext();
TrustManager[] trustAllCerts = createNoCheckTrustManager();
try {
sc.init(null, trustAllCerts, new SecureRandom());
} catch (KeyManagementException e) {
throw new ClientException("Failed to init security key management", e);
}
return ClientBuilder.newBuilder()
.hostnameVerifier(new HostNameVerifier(url))
.sslContext(sc)
.build();
}

public RestClient(String url, ClientConfig config) {
this.client = ClientBuilder.newClient(config);
Client client = null;
Object protocol = config.getProperty("protocol");
if (protocol != null && protocol.equals("https")) {
client = wrapTrustConfig(url, config);
} else {
client = ClientBuilder.newClient(config);
}
this.client = client;
this.client.register(GZipEncoder.class);
this.target = this.client.target(url);
this.pool = (PoolingHttpClientConnectionManager)
Expand Down Expand Up @@ -284,6 +357,29 @@ private static String encode(String raw) {
return UriComponent.encode(raw, UriComponent.Type.PATH_SEGMENT);
}

public static class HostNameVerifier implements HostnameVerifier {

private final String url;

public HostNameVerifier(String url) {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url;
}
url = URI.create(url).getHost();
this.url = url;
}

@Override
public boolean verify(String hostname, SSLSession session) {
if (!this.url.isEmpty() && this.url.endsWith(hostname)) {
return true;
} else {
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
return verifier.verify(hostname, session);
}
}
}

protected abstract void checkStatus(Response response,
Response.Status... statuses);

Expand Down Expand Up @@ -336,6 +432,14 @@ public ConfigBuilder config(int maxTotal, int maxPerRoute) {
return this;
}

public ConfigBuilder config(String protocol, String trustStoreFile,
String trustStorePassword) {
this.config.property("protocol", protocol);
this.config.property("trustStoreFile", trustStoreFile);
this.config.property("trustStorePassword", trustStorePassword);
return this;
}

public ClientConfig build() {
return this.config;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ public class CommonVersion {

// The second parameter of Version.of() is for all-in-one JAR
public static final Version VERSION = Version.of(CommonVersion.class,
"1.7.5");
"1.7.6");
}
54 changes: 54 additions & 0 deletions src/test/java/com/baidu/hugegraph/unit/rest/RestClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@

package com.baidu.hugegraph.unit.rest;

import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
Expand Down Expand Up @@ -80,6 +85,17 @@ public RestClientImpl(String url, String user, String password,
this.content = "";
}

public RestClientImpl(String url, String user, String password,
int timeout, int maxTotal, int maxPerRoute,
String protocol, String trustStoreFile,
String trustStorePassword, int status) {
super(url, user, password, timeout, maxTotal, maxPerRoute, protocol,
trustStoreFile, trustStorePassword);
this.status = status;
this.headers = ImmutableMultivaluedMap.empty();
this.content = "";
}

public RestClientImpl(String url, int timeout, int status) {
this(url, timeout, status, ImmutableMultivaluedMap.empty(), "");
}
Expand Down Expand Up @@ -221,6 +237,44 @@ public void testPostWithAllParams() {
Assert.assertEquals(200, restResult.status());
}

@Test
public void testPostHttpsWithAllParams() {
String trustStoreFile = "src/test/resources/cacerts.jks";
String trustStorePassword = "changeit";
RestClient client = new RestClientImpl("/test", "user", "", 1000,
10, 5, "https", trustStoreFile,
trustStorePassword, 200);
RestResult restResult = client.post("path", "body");
Assert.assertEquals(200, restResult.status());
}

@Test
public void testHostNameVerifier() {
BiFunction<String, String, Boolean> verifer = (url, hostname) -> {
RestClient.HostNameVerifier verifier;
SSLSession session;
try {
SSLSessionContext sc = SSLContext.getDefault()
.getClientSessionContext();
session = sc.getSession(new byte[]{11});
verifier = new RestClient.HostNameVerifier(url);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return verifier.verify(hostname, session);
};

Assert.assertTrue(verifer.apply("http://baidu.com", "baidu.com"));
Assert.assertTrue(verifer.apply("http://test1.baidu.com", "baidu.com"));
Assert.assertTrue(verifer.apply("http://test2.baidu.com", "baidu.com"));
Assert.assertFalse(verifer.apply("http://baidu2.com", "baidu.com"));
Assert.assertTrue(verifer.apply("http://baidu.com", ""));
Assert.assertTrue(verifer.apply("baidu.com", "baidu.com"));
Assert.assertTrue(verifer.apply("http://baidu.com/test/abc", "baidu.com"));
Assert.assertTrue(verifer.apply("baidu.com/test/abc", "baidu.com"));
Assert.assertFalse(verifer.apply("baidu.com.sina.com", "baidu.com"));
}

@Test
public void testPostWithHeaderAndContent() {
MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
Expand Down
Binary file added src/test/resources/cacerts.jks
Binary file not shown.

0 comments on commit c2c5ba4

Please sign in to comment.