Skip to content

Commit d1d02fd

Browse files
authored
Add ability to override the API hostname url (#38)
1 parent 52625b4 commit d1d02fd

File tree

6 files changed

+126
-7
lines changed

6 files changed

+126
-7
lines changed

src/main/java/com/darksci/pardot/api/Configuration.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ public class Configuration {
4545
private String pardotApiHost = "https://pi.pardot.com/api";
4646
private String pardotApiVersion = "3";
4747

48+
/**
49+
* Optional setting to skip validating Pardot's SSL certificate.
50+
* There should be no real valid use case for this option other then use against
51+
* development environments.
52+
*/
53+
private boolean ignoreInvalidSslCertificates = false;
54+
4855
/**
4956
* Constructor.
5057
* @param email Pardot user's email address.
@@ -139,8 +146,9 @@ public String getPardotApiHost() {
139146
return pardotApiHost;
140147
}
141148

142-
public void setPardotApiHost(final String pardotApiHost) {
149+
public Configuration setPardotApiHost(final String pardotApiHost) {
143150
this.pardotApiHost = pardotApiHost;
151+
return this;
144152
}
145153

146154
public String getPardotApiVersion() {
@@ -159,6 +167,20 @@ public void setApiKey(final String apiKey) {
159167
this.apiKey = apiKey;
160168
}
161169

170+
/**
171+
* Skip all validation of SSL Certificates. This is insecure and highly discouraged!
172+
*
173+
* @return Configuration instance.
174+
*/
175+
public Configuration useInsecureSslCertificates() {
176+
this.ignoreInvalidSslCertificates = true;
177+
return this;
178+
}
179+
180+
public boolean getIgnoreInvalidSslCertificates() {
181+
return ignoreInvalidSslCertificates;
182+
}
183+
162184
@Override
163185
public String toString() {
164186
final StringBuilder stringBuilder = new StringBuilder("Configuration{")

src/main/java/com/darksci/pardot/api/PardotClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@
102102
import com.darksci.pardot.api.request.prospect.ProspectUnassignRequest;
103103
import com.darksci.pardot.api.request.prospect.ProspectUpdateRequest;
104104
import com.darksci.pardot.api.request.prospect.ProspectUpsertRequest;
105-
import com.darksci.pardot.api.request.tag.TagReadRequest;
106105
import com.darksci.pardot.api.request.tag.TagQueryRequest;
106+
import com.darksci.pardot.api.request.tag.TagReadRequest;
107107
import com.darksci.pardot.api.request.tagobject.TagObjectQueryRequest;
108108
import com.darksci.pardot.api.request.tagobject.TagObjectReadRequest;
109109
import com.darksci.pardot.api.request.user.UserAbilitiesRequest;

src/main/java/com/darksci/pardot/api/request/tagobject/TagObjectQueryRequest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
package com.darksci.pardot.api.request.tagobject;
1919

2020
import com.darksci.pardot.api.request.BaseQueryRequest;
21-
import com.darksci.pardot.api.request.DateParameter;
22-
import com.darksci.pardot.api.request.tag.TagQueryRequest;
2321

2422
/**
2523
* Defines a TagObject Query Request.

src/main/java/com/darksci/pardot/api/rest/HttpClientRestClient.java

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.http.client.entity.UrlEncodedFormEntity;
3232
import org.apache.http.client.methods.HttpPost;
3333
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
34+
import org.apache.http.conn.ssl.NoopHostnameVerifier;
3435
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
3536
import org.apache.http.impl.client.BasicCredentialsProvider;
3637
import org.apache.http.impl.client.CloseableHttpClient;
@@ -40,10 +41,18 @@
4041
import org.slf4j.Logger;
4142
import org.slf4j.LoggerFactory;
4243

44+
import javax.net.ssl.HostnameVerifier;
45+
import javax.net.ssl.KeyManager;
4346
import javax.net.ssl.SSLContext;
47+
import javax.net.ssl.TrustManager;
48+
import javax.net.ssl.TrustManagerFactory;
4449
import java.io.IOException;
45-
import java.nio.charset.Charset;
4650
import java.nio.charset.StandardCharsets;
51+
import java.security.KeyManagementException;
52+
import java.security.KeyStore;
53+
import java.security.KeyStoreException;
54+
import java.security.NoSuchAlgorithmException;
55+
import java.security.SecureRandom;
4756
import java.util.ArrayList;
4857
import java.util.List;
4958
import java.util.Map;
@@ -85,12 +94,32 @@ public void init(final Configuration configuration) {
8594
// Create default SSLContext
8695
final SSLContext sslcontext = SSLContexts.createDefault();
8796

97+
// Initialize ssl context with configured key and trust managers.
98+
try {
99+
sslcontext.init(new KeyManager[0], getTrustManagers(), new SecureRandom());
100+
} catch (final KeyManagementException exception) {
101+
throw new RuntimeException(exception.getMessage(), exception);
102+
}
103+
104+
// Create hostname verifier instance.
105+
final HostnameVerifier hostnameVerifier;
106+
// Emit an warning letting everyone know we're using an insecure configuration.
107+
if (configuration.getIgnoreInvalidSslCertificates()) {
108+
logger.warn("Using insecure configuration, skipping server-side certificate validation checks.");
109+
110+
// If we're configured to ignore invalid certificates, use the Noop verifier.
111+
hostnameVerifier = NoopHostnameVerifier.INSTANCE;
112+
} else {
113+
// Use default implementation
114+
hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
115+
}
116+
88117
// Allow TLSv1_1 and TLSv1_2 protocols
89118
final LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
90119
sslcontext,
91120
new String[] { "TLSv1.1", "TLSv1.2" },
92121
null,
93-
SSLConnectionSocketFactory.getDefaultHostnameVerifier()
122+
hostnameVerifier
94123
);
95124

96125
// Setup client builder
@@ -136,6 +165,31 @@ public void init(final Configuration configuration) {
136165
httpClient = clientBuilder.build();
137166
}
138167

168+
/**
169+
* Based on Client Configuration, construct TrustManager instances to use.
170+
* @return Array of 0 or more TrustManager instances.
171+
*/
172+
private TrustManager[] getTrustManagers() {
173+
try {
174+
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
175+
176+
// If client configuration is set to ignore invalid certificates
177+
if (configuration.getIgnoreInvalidSslCertificates()) {
178+
// Initialize ssl context with a TrustManager instance that just accepts everything blindly.
179+
// HIGHLY INSECURE / NOT RECOMMENDED!
180+
return new TrustManager[]{ new NoopTrustManager() };
181+
182+
// If client configuration has a trust store defined.
183+
} else {
184+
// use default TrustManager instances
185+
trustManagerFactory.init((KeyStore) null);
186+
return trustManagerFactory.getTrustManagers();
187+
}
188+
} catch (final KeyStoreException | NoSuchAlgorithmException exception) {
189+
throw new RuntimeException(exception.getMessage(), exception);
190+
}
191+
}
192+
139193
@Override
140194
public void close() {
141195
if (httpClient != null) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright 2017, 2018, 2019 Stephen Powis https://github.com/Crim/pardot-java-client
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
6+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
7+
* persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
10+
* Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
15+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16+
*/
17+
18+
package com.darksci.pardot.api.rest;
19+
20+
import javax.net.ssl.X509TrustManager;
21+
import java.security.cert.X509Certificate;
22+
23+
/**
24+
* Implementation of TrustManager that blindly trusts all certificates with no validation or verification.
25+
*/
26+
class NoopTrustManager implements X509TrustManager {
27+
@Override
28+
public void checkClientTrusted(final X509Certificate[] x509Certificates, final String input) {
29+
}
30+
31+
@Override
32+
public void checkServerTrusted(final X509Certificate[] x509Certificates, final String input) {
33+
}
34+
35+
@Override
36+
public X509Certificate[] getAcceptedIssuers() {
37+
return new X509Certificate[0];
38+
}
39+
}

src/test/java/com/darksci/pardot/api/PardotClientTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,12 @@ public void setup() throws IOException {
157157
properties.getProperty("password"),
158158
properties.getProperty("user_key")
159159
);
160+
if (properties.getProperty("api_host") != null) {
161+
testConfig
162+
.setPardotApiHost(properties.getProperty("api_host"))
163+
.useInsecureSslCertificates();
164+
165+
}
160166
logger.info("Config: {}", testConfig);
161167

162168
// Create client
@@ -269,7 +275,7 @@ public void campaignReadTest() throws IOException {
269275
public void campaignCreateTest() {
270276
// Define campaign
271277
final Campaign campaign = new Campaign();
272-
campaign.setName("API Test Campaign " + System.currentTimeMillis());
278+
campaign.setName("API 新 Test Campaign " + System.currentTimeMillis());
273279
campaign.setCost(31337);
274280

275281
// Create request

0 commit comments

Comments
 (0)