From e054a6f0a24ccff367ea6229d03aa90a7b3e4bcc Mon Sep 17 00:00:00 2001 From: Michael Vorburger Date: Sat, 17 Oct 2020 17:18:09 +0200 Subject: [PATCH] Improve ProcessorHelper (FINERACT-1211) --- .../hooks/processor/ProcessorHelper.java | 95 ++++++++++--------- .../hooks/processor/TwilioHookProcessor.java | 10 +- .../hooks/processor/WebHookProcessor.java | 15 ++- ...WritePlatformServiceJpaRepositoryImpl.java | 9 +- 4 files changed, 71 insertions(+), 58 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java index de56ae8bb..29392c1d3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/ProcessorHelper.java @@ -31,23 +31,56 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; import retrofit.Callback; import retrofit.RestAdapter; import retrofit.RetrofitError; import retrofit.client.OkClient; import retrofit.client.Response; -@SuppressWarnings("unused") +@Service public final class ProcessorHelper { - private ProcessorHelper() { - - } - private static final Logger LOG = LoggerFactory.getLogger(ProcessorHelper.class); - @SuppressWarnings("null") - public static OkHttpClient configureClient(final OkHttpClient client) { + /** + * Configure HTTP client to be "insecure", as in skipping host SSL certificate verification. While this can be + * useful during development e.g. when using self-signed certificates, it should never be enabled in production (due + * to "man in the middle"). + */ + private final boolean insecureHttpClient = Boolean.getBoolean("fineract.insecureHttpClient"); + private final SSLContext insecureSSLContext; + + public ProcessorHelper() throws KeyManagementException, NoSuchAlgorithmException { + if (insecureHttpClient) { + insecureSSLContext = createInsecureSSLContext(); + } else { + insecureSSLContext = null; + } + } + + private OkHttpClient createClient() { + final OkHttpClient client = new OkHttpClient(); + if (insecureHttpClient) { + configureInsecureClient(client); + } + return client; + } + + private void configureInsecureClient(final OkHttpClient client) { + client.setSslSocketFactory(insecureSSLContext.getSocketFactory()); + + final HostnameVerifier hostnameVerifier = new HostnameVerifier() { + + @Override + public boolean verify(final String hostname, final SSLSession session) { + return true; + } + }; + client.setHostnameVerifier(hostnameVerifier); + } + + private SSLContext createInsecureSSLContext() throws NoSuchAlgorithmException, KeyManagementException { final TrustManager[] certs = new TrustManager[] { new X509TrustManager() { @Override @@ -62,62 +95,30 @@ public final class ProcessorHelper { public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {} } }; - SSLContext ctx = null; - try { - ctx = SSLContext.getInstance("TLS"); - ctx.init(null, certs, new SecureRandom()); - } catch (KeyManagementException ex) { - LOG.error("Problem occurred in configureClient function", ex); - } catch (NoSuchAlgorithmException e) { - LOG.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol.", e); - } - - try { - final HostnameVerifier hostnameVerifier = new HostnameVerifier() { - - @Override - public boolean verify(final String hostname, final SSLSession session) { - return true; - } - }; - client.setHostnameVerifier(hostnameVerifier); - client.setSslSocketFactory(ctx.getSocketFactory()); - } catch (final Exception e) { - LOG.error("Problem occurred in configureClient function", e); - } - - return client; - } - - public static OkHttpClient createClient() { - final OkHttpClient client = new OkHttpClient(); - return configureClient(client); + SSLContext insecureSSLContext = SSLContext.getInstance("TLS"); + insecureSSLContext.init(null, certs, new SecureRandom()); + return insecureSSLContext; } @SuppressWarnings("rawtypes") - public static Callback createCallback(final String url) { - + public Callback createCallback(final String url) { return new Callback() { @Override public void success(final Object o, final Response response) { - LOG.info("URL: {}\tStatus: {}", url, response.getStatus()); + LOG.info("URL: {} - Status: {}", url, response.getStatus()); } @Override public void failure(final RetrofitError retrofitError) { - LOG.info("Error occured.", retrofitError); + LOG.error("URL: {} - RetrofitError occured", url, retrofitError); } }; } - public static WebHookService createWebHookService(final String url) { - - final OkHttpClient client = ProcessorHelper.createClient(); - + public WebHookService createWebHookService(final String url) { + final OkHttpClient client = createClient(); final RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(url).setClient(new OkClient(client)).build(); - return restAdapter.create(WebHookService.class); } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java index 79fa317e5..7f7234b1b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java @@ -45,16 +45,20 @@ import retrofit.Callback; public class TwilioHookProcessor implements HookProcessor { private static final Logger LOG = LoggerFactory.getLogger(TwilioHookProcessor.class); + private final HookConfigurationRepository hookConfigurationRepository; private final TemplateMergeService templateMergeService; private final ClientRepositoryWrapper clientRepositoryWrapper; + private final ProcessorHelper processorHelper; @Autowired public TwilioHookProcessor(final HookConfigurationRepository hookConfigurationRepository, - final TemplateMergeService templateMergeService, final ClientRepositoryWrapper clientRepositoryWrapper) { + final TemplateMergeService templateMergeService, final ClientRepositoryWrapper clientRepositoryWrapper, + ProcessorHelper processorHelper) { this.hookConfigurationRepository = hookConfigurationRepository; this.templateMergeService = templateMergeService; this.clientRepositoryWrapper = clientRepositoryWrapper; + this.processorHelper = processorHelper; } @Override @@ -70,10 +74,10 @@ public class TwilioHookProcessor implements HookProcessor { private void sendRequest(final SmsProviderData smsProviderData, final String payload, String entityName, String actionName, final String tenantIdentifier, final String authToken, final Hook hook) { - final WebHookService service = ProcessorHelper.createWebHookService(smsProviderData.getUrl()); + final WebHookService service = processorHelper.createWebHookService(smsProviderData.getUrl()); @SuppressWarnings("rawtypes") - final Callback callback = ProcessorHelper.createCallback(smsProviderData.getUrl()); + final Callback callback = processorHelper.createCallback(smsProviderData.getUrl()); String apiKey = this.hookConfigurationRepository.findOneByHookIdAndFieldName(hook.getId(), apiKeyName); if (apiKey == null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java index f9753b74a..556e2cc84 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookProcessor.java @@ -30,12 +30,20 @@ import java.util.Set; import org.apache.fineract.infrastructure.hooks.domain.Hook; import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration; import org.apache.fineract.useradministration.domain.AppUser; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import retrofit.Callback; @Service public class WebHookProcessor implements HookProcessor { + private final ProcessorHelper processorHelper; + + @Autowired + public WebHookProcessor(ProcessorHelper processorHelper) { + this.processorHelper = processorHelper; + } + @Override public void process(final Hook hook, @SuppressWarnings("unused") final AppUser appUser, final String payload, final String entityName, final String actionName, final String tenantIdentifier, final String authToken) { @@ -56,7 +64,6 @@ public class WebHookProcessor implements HookProcessor { } sendRequest(url, contentType, payload, entityName, actionName, tenantIdentifier, authToken); - } @SuppressWarnings("unchecked") @@ -64,10 +71,10 @@ public class WebHookProcessor implements HookProcessor { final String actionName, final String tenantIdentifier, @SuppressWarnings("unused") final String authToken) { final String fineractEndpointUrl = System.getProperty("baseUrl"); - final WebHookService service = ProcessorHelper.createWebHookService(url); + final WebHookService service = processorHelper.createWebHookService(url); @SuppressWarnings("rawtypes") - final Callback callback = ProcessorHelper.createCallback(url); + final Callback callback = processorHelper.createCallback(url); if (contentType.equalsIgnoreCase("json") || contentType.contains("json")) { final JsonObject json = JsonParser.parseString(payload).getAsJsonObject(); @@ -77,7 +84,5 @@ public class WebHookProcessor implements HookProcessor { map = new Gson().fromJson(payload, map.getClass()); service.sendFormRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, map, callback); } - } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java index 94df98760..eebea943e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java @@ -78,17 +78,20 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf private final TemplateRepository ugdTemplateRepository; private final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final FromJsonHelper fromApiJsonHelper; + private final ProcessorHelper processorHelper; @Autowired public HookWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final HookRepository hookRepository, final HookTemplateRepository hookTemplateRepository, final TemplateRepository ugdTemplateRepository, - final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer, final FromJsonHelper fromApiJsonHelper) { + final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer, final FromJsonHelper fromApiJsonHelper, + ProcessorHelper processorHelper) { this.context = context; this.hookRepository = hookRepository; this.hookTemplateRepository = hookTemplateRepository; this.ugdTemplateRepository = ugdTemplateRepository; this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fromApiJsonHelper = fromApiJsonHelper; + this.processorHelper = processorHelper; } @Transactional @@ -270,7 +273,7 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf for (final HookConfiguration conf : config) { final String fieldValue = conf.getFieldValue(); if (conf.getFieldName().equals(contentTypeName)) { - if (!(fieldValue.equalsIgnoreCase("json") || fieldValue.equalsIgnoreCase("form"))) { + if ((!fieldValue.equalsIgnoreCase("json") && !fieldValue.equalsIgnoreCase("form"))) { final String errorMessage = "content.type.must.be.json.or.form"; baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); } @@ -278,7 +281,7 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf if (conf.getFieldName().equals(payloadURLName)) { try { - final WebHookService service = ProcessorHelper.createWebHookService(fieldValue); + final WebHookService service = processorHelper.createWebHookService(fieldValue); service.sendEmptyRequest(); } catch (RetrofitError re) { // Swallow error if it's because of method not supported or