|
47 | 47 | import org.apache.http.client.config.RequestConfig; |
48 | 48 | import org.apache.http.client.methods.CloseableHttpResponse; |
49 | 49 | import org.apache.http.client.methods.HttpPost; |
| 50 | +import org.apache.http.config.Registry; |
| 51 | +import org.apache.http.config.RegistryBuilder; |
| 52 | +import org.apache.http.conn.DnsResolver; |
| 53 | +import org.apache.http.conn.socket.ConnectionSocketFactory; |
| 54 | +import org.apache.http.conn.socket.PlainConnectionSocketFactory; |
50 | 55 | import org.apache.http.conn.ssl.NoopHostnameVerifier; |
| 56 | +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
51 | 57 | import org.apache.http.conn.ssl.TrustAllStrategy; |
52 | 58 | import org.apache.http.entity.ContentType; |
53 | 59 | import org.apache.http.entity.StringEntity; |
54 | 60 | import org.apache.http.impl.client.CloseableHttpClient; |
55 | 61 | import org.apache.http.impl.client.HttpClients; |
| 62 | +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; |
56 | 63 | import org.apache.http.message.BasicHeader; |
57 | 64 | import org.apache.http.ssl.SSLContextBuilder; |
58 | 65 | import org.apache.http.util.EntityUtils; |
@@ -102,17 +109,30 @@ protected boolean isValidJson(String json) { |
102 | 109 | return true; |
103 | 110 | } |
104 | 111 |
|
105 | | - protected void setHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { |
| 112 | + protected SSLConnectionSocketFactory getSslConnectionSocketFactory() throws NoSuchAlgorithmException, |
| 113 | + KeyStoreException, KeyManagementException { |
106 | 114 | if (webhook.isSslVerification()) { |
107 | | - httpClient = HttpClients.custom().disableRedirectHandling().build(); |
108 | | - return; |
| 115 | + return SSLConnectionSocketFactory.getSocketFactory(); |
109 | 116 | } |
| 117 | + return new SSLConnectionSocketFactory(new SSLContextBuilder().loadTrustMaterial(null, |
| 118 | + TrustAllStrategy.INSTANCE).build(), NoopHostnameVerifier.INSTANCE); |
| 119 | + } |
| 120 | + |
| 121 | + protected DnsResolver getDnsResolver() { |
| 122 | + return new WebhookUrlValidator.DestinationPolicyDnsResolver(destinationBlocklist, blockLocalAddresses); |
| 123 | + } |
| 124 | + |
| 125 | + protected void setHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { |
| 126 | + Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() |
| 127 | + .register("http", PlainConnectionSocketFactory.getSocketFactory()) |
| 128 | + .register("https", getSslConnectionSocketFactory()) |
| 129 | + .build(); |
| 130 | + // Destination addresses are validated by the DNS resolver |
110 | 131 | httpClient = HttpClients |
111 | 132 | .custom() |
112 | 133 | .disableRedirectHandling() |
113 | | - .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, |
114 | | - TrustAllStrategy.INSTANCE).build()) |
115 | | - .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) |
| 134 | + .setConnectionManager(new BasicHttpClientConnectionManager(socketFactoryRegistry, null, null, |
| 135 | + getDnsResolver())) |
116 | 136 | .build(); |
117 | 137 | } |
118 | 138 |
|
@@ -205,18 +225,34 @@ public void run() { |
205 | 225 | callback.complete(new WebhookDeliveryResult(headers, payload, success, response, new Date())); |
206 | 226 | return; |
207 | 227 | } |
208 | | - if (payloadUri == null) { |
209 | | - payloadUri = WebhookUrlValidator.validateWebhookDestinationUrl(webhook.getPayloadUrl(), allowHttp, |
210 | | - destinationBlocklist, blockLocalAddresses); |
211 | | - } |
212 | | - while (attempt < deliveryTries) { |
213 | | - attempt++; |
214 | | - if (delivery(attempt)) { |
215 | | - success = true; |
216 | | - break; |
| 228 | + try { |
| 229 | + if (payloadUri == null) { |
| 230 | + payloadUri = URI.create(webhook.getPayloadUrl()); |
| 231 | + WebhookUrlValidator.validateScheme(payloadUri, allowHttp); |
217 | 232 | } |
| 233 | + while (attempt < deliveryTries) { |
| 234 | + attempt++; |
| 235 | + if (delivery(attempt)) { |
| 236 | + success = true; |
| 237 | + break; |
| 238 | + } |
| 239 | + } |
| 240 | + } catch (InvalidParameterValueException | IllegalArgumentException e) { |
| 241 | + LOGGER.warn("Failed to deliver {} due to invalid payload URL: {}", webhook, e.getMessage()); |
| 242 | + response = String.format("Failed due to : %s", e.getMessage()); |
| 243 | + } finally { |
| 244 | + closeHttpClient(); |
| 245 | + } |
| 246 | + callback.complete(new WebhookDeliveryResult(headers, payload, success, response, |
| 247 | + startTime != null ? startTime : new Date())); |
| 248 | + } |
| 249 | + |
| 250 | + protected void closeHttpClient() { |
| 251 | + try { |
| 252 | + httpClient.close(); |
| 253 | + } catch (IOException e) { |
| 254 | + LOGGER.debug("Failed to close HTTP client for {}: {}", webhook, e.getMessage()); |
218 | 255 | } |
219 | | - callback.complete(new WebhookDeliveryResult(headers, payload, success, response, startTime)); |
220 | 256 | } |
221 | 257 |
|
222 | 258 | protected void updateResponseFromRequest(HttpEntity entity) { |
@@ -271,16 +307,19 @@ protected boolean delivery(int attempt) { |
271 | 307 | MAX_REDIRECT_HOPS); |
272 | 308 | return false; |
273 | 309 | } |
274 | | - currentUri = WebhookUrlValidator.validateWebhookDestinationURI( |
275 | | - currentUri.resolve(locationHeader.getValue()), |
276 | | - allowHttp,destinationBlocklist, blockLocalAddresses); |
| 310 | + currentUri = currentUri.resolve(locationHeader.getValue()); |
| 311 | + WebhookUrlValidator.validateScheme(currentUri, allowHttp); |
277 | 312 | } |
278 | 313 | } |
| 314 | + } catch (WebhookUrlValidator.BlockedDestinationException e) { |
| 315 | + LOGGER.warn("Failed to deliver {}, in attempt #{} due to security policy: {}", |
| 316 | + webhook, attempt, e.getMessage()); |
| 317 | + response = String.format("Failed due to : %s", e.getMessage()); |
279 | 318 | } catch (IOException | DecoderException | NoSuchAlgorithmException | InvalidKeyException e) { |
280 | 319 | LOGGER.warn("Failed to deliver {}, in attempt #{} due to: {}", |
281 | 320 | webhook, attempt, e.getMessage()); |
282 | 321 | response = String.format("Failed due to : %s", e.getMessage()); |
283 | | - } catch (InvalidParameterValueException e) { |
| 322 | + } catch (InvalidParameterValueException | IllegalArgumentException e) { |
284 | 323 | LOGGER.warn("Failed to deliver {}, in attempt #{} due to security policy: {}", |
285 | 324 | webhook, attempt, e.getMessage()); |
286 | 325 | response = String.format("Failed due to : %s", e.getMessage()); |
|
0 commit comments