Skip to content

Commit 1cc175c

Browse files
author
hansdude
committed
Merge pull request #47 from rpmoore/master
Adds better handling for HTTPS
2 parents 17955c8 + bc2f40a commit 1cc175c

File tree

19 files changed

+197
-55
lines changed

19 files changed

+197
-55
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
allprojects {
1717
group = 'com.spectralogic'
18-
version = '0.7.4-SNAPSHOT'
18+
version = '0.7.5-SNAPSHOT'
1919
}
2020

2121
subprojects {

integration/src/main/java/com/spectralogic/ds3client/integration/Util.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ public class Util {
2222
private Util() {}
2323

2424
public static Ds3Client fromEnv() {
25+
final Ds3ClientBuilder builder = clientBuilder();
26+
builder.withHttps(false);
27+
return builder.build();
28+
}
29+
30+
public static Ds3Client insecureFromEnv() {
31+
final Ds3ClientBuilder builder = clientBuilder();
32+
builder.withCertificateVerification(false);
33+
return builder.build();
34+
}
35+
36+
private static Ds3ClientBuilder clientBuilder() {
2537
final String endpoint = System.getenv("DS3_ENDPOINT");
2638
final String accessKey = System.getenv("DS3_ACCESS_KEY");
2739
final String secretKey = System.getenv("DS3_SECRET_KEY");
@@ -40,11 +52,10 @@ public static Ds3Client fromEnv() {
4052
}
4153

4254
final Ds3ClientBuilder builder = Ds3ClientBuilder.create(endpoint,new Credentials(accessKey, secretKey));
43-
builder.withHttpSecure(false);
4455
if (httpProxy != null) {
4556
builder.withProxy(httpProxy);
4657
}
47-
return builder.build();
58+
return builder;
4859
}
4960

5061
private static final String[] BOOKS = {"beowulf.txt", "sherlock_holmes.txt", "tale_of_two_cities.txt", "ulysses.txt"};
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.spectralogic.ds3client.integration;
2+
3+
import com.spectralogic.ds3client.Ds3Client;
4+
import com.spectralogic.ds3client.commands.GetServiceRequest;
5+
import com.spectralogic.ds3client.commands.GetServiceResponse;
6+
import org.junit.BeforeClass;
7+
import org.junit.Test;
8+
9+
import java.io.IOException;
10+
import java.security.SignatureException;
11+
12+
import static org.hamcrest.CoreMatchers.*;
13+
import static org.junit.Assert.assertThat;
14+
15+
/**
16+
*
17+
* This test is intended to be a sanity check to make sure that we can successfully ignore ssl certificate validation.
18+
*
19+
*/
20+
public class Insecure_Test {
21+
22+
private static Ds3Client client;
23+
24+
@BeforeClass
25+
public static void startup() {
26+
client = Util.insecureFromEnv();
27+
}
28+
29+
@Test
30+
public void getService() throws SignatureException, IOException{
31+
final GetServiceResponse response = client.getService(new GetServiceRequest());
32+
33+
assertThat(response, is(notNullValue()));
34+
}
35+
}

sdk/src/main/java/com/spectralogic/ds3client/ConnectionDetailsImpl.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,19 @@ static class Builder implements com.spectralogic.ds3client.utils.Builder<Connect
2525

2626
private final String endpoint;
2727
private final Credentials credentials;
28-
private boolean secure = false;
28+
private boolean https = false;
2929
private URI proxy = null;
3030
private int retries = 5;
3131
private int bufferSize = 1024 * 1024;
32+
private boolean certificateVerification;
3233

3334
private Builder(final String endpoint, final Credentials credentials) {
3435
this.endpoint = endpoint;
3536
this.credentials = credentials;
3637
}
3738

38-
public Builder withSecure(final boolean secure) {
39-
this.secure = secure;
39+
public Builder withHttps(final boolean secure) {
40+
this.https = secure;
4041
return this;
4142
}
4243

@@ -55,18 +56,25 @@ public Builder withBufferSize(final int bufferSize) {
5556
return this;
5657
}
5758

59+
public Builder withCertificateVerification(final boolean certificateVerification) {
60+
this.certificateVerification = certificateVerification;
61+
return this;
62+
}
63+
5864
@Override
5965
public ConnectionDetailsImpl build() {
6066
return new ConnectionDetailsImpl(this);
6167
}
68+
6269
}
6370

6471
private final String endpoint;
6572
private final Credentials credentials;
66-
private final boolean secure;
73+
private final boolean https;
6774
private final URI proxy;
6875
private final int retries;
6976
private final int bufferSize;
77+
private final boolean certificateVerification;
7078

7179
static Builder builder(final String uriEndpoint, final Credentials credentials) {
7280
return new Builder(uriEndpoint, credentials);
@@ -75,10 +83,11 @@ static Builder builder(final String uriEndpoint, final Credentials credentials)
7583
private ConnectionDetailsImpl(final Builder builder) {
7684
this.endpoint = builder.endpoint;
7785
this.credentials = builder.credentials;
78-
this.secure = builder.secure;
86+
this.https = builder.https;
7987
this.proxy = builder.proxy;
8088
this.retries = builder.retries;
8189
this.bufferSize = builder.bufferSize;
90+
this.certificateVerification = builder.certificateVerification;
8291
}
8392

8493
@Override
@@ -92,8 +101,8 @@ public Credentials getCredentials() {
92101
}
93102

94103
@Override
95-
public boolean isSecure() {
96-
return secure;
104+
public boolean isHttps() {
105+
return https;
97106
}
98107

99108
@Override
@@ -110,4 +119,10 @@ public int getRetries() {
110119
public int getBufferSize() {
111120
return bufferSize;
112121
}
122+
123+
@Override
124+
public boolean isCertificateVerification() {
125+
return certificateVerification;
126+
}
127+
113128
}

sdk/src/main/java/com/spectralogic/ds3client/Ds3ClientBuilder.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ public class Ds3ClientBuilder implements Builder<Ds3Client> {
1818
final private String endpoint;
1919
final private Credentials credentials;
2020

21-
private boolean secure = true;
21+
private boolean https = true;
22+
private boolean certificateVerification = true;
2223
private URI proxy = null;
2324
private int retries = 5;
2425
private int bufferSize = 1024 * 1024;
@@ -49,8 +50,8 @@ public static Ds3ClientBuilder create(final String endpoint, final Credentials c
4950
* @param secure True will use HTTPS, false will use HTTP.
5051
* @return The current builder.
5152
*/
52-
public Ds3ClientBuilder withHttpSecure(final boolean secure) {
53-
this.secure = secure;
53+
public Ds3ClientBuilder withHttps(final boolean secure) {
54+
this.https = secure;
5455
return this;
5556
}
5657

@@ -63,6 +64,14 @@ public Ds3ClientBuilder withBufferSize(final int bufferSize) {
6364
return this;
6465
}
6566

67+
/**
68+
* Specifies if the library should perform SSL certificate validation.
69+
*/
70+
public Ds3ClientBuilder withCertificateVerification(final boolean certificateVerification) {
71+
this.certificateVerification = certificateVerification;
72+
return this;
73+
}
74+
6675
/**
6776
* Sets a HTTP proxy.
6877
* @param proxy The endpoint of the HTTP proxy.
@@ -102,7 +111,7 @@ public Ds3ClientBuilder withRedirectRetries(final int retries) {
102111
@Override
103112
public Ds3Client build() {
104113
final ConnectionDetailsImpl.Builder connBuilder = ConnectionDetailsImpl.builder(this.endpoint, this.credentials)
105-
.withProxy(this.proxy).withSecure(this.secure).withRedirectRetries(this.retries).withBufferSize(this.bufferSize);
114+
.withProxy(this.proxy).withHttps(this.https).withCertificateVerification(this.certificateVerification).withRedirectRetries(this.retries).withBufferSize(this.bufferSize);
106115

107116
final NetworkClient netClient = new NetworkClientImpl(connBuilder.build());
108117
return new Ds3ClientImpl(netClient);

sdk/src/main/java/com/spectralogic/ds3client/NetworkClientImpl.java

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.spectralogic.ds3client.models.SignatureDetails;
2121
import com.spectralogic.ds3client.networking.*;
2222
import com.spectralogic.ds3client.utils.DateFormatter;
23+
import com.spectralogic.ds3client.utils.SSLSetupException;
2324
import com.spectralogic.ds3client.utils.Signature;
2425

2526
import org.apache.http.HttpHost;
@@ -28,17 +29,22 @@
2829
import org.apache.http.client.config.RequestConfig;
2930
import org.apache.http.client.methods.CloseableHttpResponse;
3031
import org.apache.http.client.protocol.HttpClientContext;
32+
import org.apache.http.conn.ssl.*;
33+
import org.apache.http.impl.client.CloseableHttpClient;
3134
import org.apache.http.impl.client.HttpClients;
3235
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
3336
import org.apache.http.message.BasicHttpRequest;
3437

38+
import javax.net.ssl.SSLContext;
3539
import java.io.Closeable;
3640
import java.io.IOException;
3741
import java.io.InputStream;
3842
import java.net.MalformedURLException;
3943
import java.net.URI;
4044
import java.net.URL;
41-
import java.security.SignatureException;
45+
import java.security.*;
46+
import java.security.cert.CertificateException;
47+
import java.security.cert.X509Certificate;
4248
import java.util.Map;
4349

4450
class NetworkClientImpl implements NetworkClient {
@@ -100,7 +106,7 @@ public CloseableHttpResponse execute() throws IOException, SignatureException {
100106

101107
final HttpRequest httpRequest = this.buildHttpRequest();
102108
this.addHeaders(httpRequest);
103-
return HttpClients.createDefault().execute(this.host, httpRequest, this.getContext());
109+
return getClient().execute(this.host, httpRequest, this.getContext());
104110
}
105111

106112
private HttpHost buildHost() throws MalformedURLException {
@@ -109,16 +115,32 @@ private HttpHost buildHost() throws MalformedURLException {
109115
return new HttpHost(proxyUri.getHost(), proxyUri.getPort(), proxyUri.getScheme());
110116
} else {
111117
final URL url = NetUtils.buildUrl(NetworkClientImpl.this.connectionDetails, "/");
112-
return new HttpHost(url.getHost(), this.getPort(url), url.getProtocol());
118+
return new HttpHost(url.getHost(), NetUtils.getPort(url), url.getProtocol());
113119
}
114120
}
115121

116-
private int getPort(final URL url) {
117-
final int port = url.getPort();
118-
if(port < 0) {
119-
return 80;
122+
private CloseableHttpClient getClient() {
123+
if (NetworkClientImpl.this.getConnectionDetails().isHttps() && !NetworkClientImpl.this.getConnectionDetails().isCertificateVerification()) {
124+
try {
125+
126+
final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
127+
@Override
128+
public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
129+
return true;
130+
}
131+
}).useTLS().build();
132+
133+
final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier());
134+
return HttpClients.custom().setSSLSocketFactory(
135+
sslsf).build();
136+
137+
} catch (final NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
138+
throw new SSLSetupException(e);
139+
}
140+
}
141+
else {
142+
return HttpClients.createDefault();
120143
}
121-
return port;
122144
}
123145

124146
private HttpRequest buildHttpRequest() throws IOException {

sdk/src/main/java/com/spectralogic/ds3client/helpers/JobState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private static int getObjectCount(final Collection<Objects> chunks) {
5656

5757
private static AutoCloseableCache<String, WindowedChannelFactory> buildCache(
5858
final ObjectChannelBuilder channelBuilder) {
59-
return new AutoCloseableCache<String, WindowedChannelFactory>(
59+
return new AutoCloseableCache<>(
6060
new ValueBuilder<String, WindowedChannelFactory>() {
6161
@Override
6262
public WindowedChannelFactory get(final String key) {

sdk/src/main/java/com/spectralogic/ds3client/helpers/ReadJobImpl.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@ public void transfer(final ObjectChannelBuilder channelBuilder)
4646
while (jobState.hasObjects()) {
4747
transferNextChunks(chunkTransferrer);
4848
}
49-
} catch (final SignatureException | IOException | XmlProcessingException e) {
50-
throw e;
51-
} catch (final RuntimeException e) {
49+
} catch (final RuntimeException | SignatureException | IOException | XmlProcessingException e) {
5250
throw e;
5351
} catch (final Exception e) {
5452
throw new RuntimeException(e);

sdk/src/main/java/com/spectralogic/ds3client/helpers/WriteJobImpl.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ public void transfer(final ObjectChannelBuilder channelBuilder)
5353
for (final Objects chunk : filteredChunks) {
5454
chunkTransferrer.transferChunks(this.masterObjectList.getNodes(), Arrays.asList(filterChunk(allocateChunk(chunk))));
5555
}
56-
} catch (final SignatureException | IOException | XmlProcessingException e) {
57-
throw e;
58-
} catch (final RuntimeException e) {
56+
} catch (final SignatureException | IOException | XmlProcessingException | RuntimeException e) {
5957
throw e;
6058
} catch (final Exception e) {
6159
throw new RuntimeException(e);
@@ -88,6 +86,12 @@ private Objects tryAllocateChunk(final Objects filtered) throws IOException, Sig
8886
}
8987
}
9088

89+
/**
90+
* Filters out chunks that have already been completed. We will get the same chunk name back from the server, but it
91+
* will not have any objects in it, so we remove that from the list of objects that are returned.
92+
* @param chunks The list to be filtered
93+
* @return The filtered list
94+
*/
9195
private static List<Objects> filterChunks(final List<Objects> chunks) {
9296
final List<Objects> filteredChunks = new ArrayList<>();
9397
for (final Objects chunk : chunks) {

sdk/src/main/java/com/spectralogic/ds3client/networking/ConnectionDetails.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,21 @@ public interface ConnectionDetails {
2424

2525
public Credentials getCredentials();
2626

27-
public boolean isSecure();
27+
/**
28+
* If true the network layer will use Https.
29+
* @return
30+
*/
31+
public boolean isHttps();
2832

2933
public URI getProxy();
3034

3135
public int getRetries();
3236

3337
public int getBufferSize();
38+
39+
/**
40+
* Returns true if the network layer should perform certificate authentication for SSL. False will disable
41+
* certificate authentication.
42+
*/
43+
boolean isCertificateVerification();
3444
}

0 commit comments

Comments
 (0)