Improve ProcessorHelper (FINERACT-1211)

This commit is contained in:
Michael Vorburger
2020-10-18 20:55:04 +03:00
committed by Petri Tuomola
parent d83bdc4166
commit e054a6f0a2
4 changed files with 71 additions and 58 deletions
@@ -31,23 +31,56 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import retrofit.Callback; import retrofit.Callback;
import retrofit.RestAdapter; import retrofit.RestAdapter;
import retrofit.RetrofitError; import retrofit.RetrofitError;
import retrofit.client.OkClient; import retrofit.client.OkClient;
import retrofit.client.Response; import retrofit.client.Response;
@SuppressWarnings("unused") @Service
public final class ProcessorHelper { public final class ProcessorHelper {
private ProcessorHelper() {
}
private static final Logger LOG = LoggerFactory.getLogger(ProcessorHelper.class); 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() { final TrustManager[] certs = new TrustManager[] { new X509TrustManager() {
@Override @Override
@@ -62,62 +95,30 @@ public final class ProcessorHelper {
public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {} public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {}
} }; } };
SSLContext ctx = null; SSLContext insecureSSLContext = SSLContext.getInstance("TLS");
try { insecureSSLContext.init(null, certs, new SecureRandom());
ctx = SSLContext.getInstance("TLS"); return insecureSSLContext;
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);
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static Callback createCallback(final String url) { public Callback createCallback(final String url) {
return new Callback() { return new Callback() {
@Override @Override
public void success(final Object o, final Response response) { public void success(final Object o, final Response response) {
LOG.info("URL: {}\tStatus: {}", url, response.getStatus()); LOG.info("URL: {} - Status: {}", url, response.getStatus());
} }
@Override @Override
public void failure(final RetrofitError retrofitError) { 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) { public WebHookService createWebHookService(final String url) {
final OkHttpClient client = createClient();
final OkHttpClient client = ProcessorHelper.createClient();
final RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(url).setClient(new OkClient(client)).build(); final RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(url).setClient(new OkClient(client)).build();
return restAdapter.create(WebHookService.class); return restAdapter.create(WebHookService.class);
} }
} }
@@ -45,16 +45,20 @@ import retrofit.Callback;
public class TwilioHookProcessor implements HookProcessor { public class TwilioHookProcessor implements HookProcessor {
private static final Logger LOG = LoggerFactory.getLogger(TwilioHookProcessor.class); private static final Logger LOG = LoggerFactory.getLogger(TwilioHookProcessor.class);
private final HookConfigurationRepository hookConfigurationRepository; private final HookConfigurationRepository hookConfigurationRepository;
private final TemplateMergeService templateMergeService; private final TemplateMergeService templateMergeService;
private final ClientRepositoryWrapper clientRepositoryWrapper; private final ClientRepositoryWrapper clientRepositoryWrapper;
private final ProcessorHelper processorHelper;
@Autowired @Autowired
public TwilioHookProcessor(final HookConfigurationRepository hookConfigurationRepository, public TwilioHookProcessor(final HookConfigurationRepository hookConfigurationRepository,
final TemplateMergeService templateMergeService, final ClientRepositoryWrapper clientRepositoryWrapper) { final TemplateMergeService templateMergeService, final ClientRepositoryWrapper clientRepositoryWrapper,
ProcessorHelper processorHelper) {
this.hookConfigurationRepository = hookConfigurationRepository; this.hookConfigurationRepository = hookConfigurationRepository;
this.templateMergeService = templateMergeService; this.templateMergeService = templateMergeService;
this.clientRepositoryWrapper = clientRepositoryWrapper; this.clientRepositoryWrapper = clientRepositoryWrapper;
this.processorHelper = processorHelper;
} }
@Override @Override
@@ -70,10 +74,10 @@ public class TwilioHookProcessor implements HookProcessor {
private void sendRequest(final SmsProviderData smsProviderData, final String payload, String entityName, String actionName, private void sendRequest(final SmsProviderData smsProviderData, final String payload, String entityName, String actionName,
final String tenantIdentifier, final String authToken, final Hook hook) { 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") @SuppressWarnings("rawtypes")
final Callback callback = ProcessorHelper.createCallback(smsProviderData.getUrl()); final Callback callback = processorHelper.createCallback(smsProviderData.getUrl());
String apiKey = this.hookConfigurationRepository.findOneByHookIdAndFieldName(hook.getId(), apiKeyName); String apiKey = this.hookConfigurationRepository.findOneByHookIdAndFieldName(hook.getId(), apiKeyName);
if (apiKey == null) { if (apiKey == null) {
@@ -30,12 +30,20 @@ import java.util.Set;
import org.apache.fineract.infrastructure.hooks.domain.Hook; import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration; import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import retrofit.Callback; import retrofit.Callback;
@Service @Service
public class WebHookProcessor implements HookProcessor { public class WebHookProcessor implements HookProcessor {
private final ProcessorHelper processorHelper;
@Autowired
public WebHookProcessor(ProcessorHelper processorHelper) {
this.processorHelper = processorHelper;
}
@Override @Override
public void process(final Hook hook, @SuppressWarnings("unused") final AppUser appUser, final String payload, final String entityName, 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) { 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); sendRequest(url, contentType, payload, entityName, actionName, tenantIdentifier, authToken);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -64,10 +71,10 @@ public class WebHookProcessor implements HookProcessor {
final String actionName, final String tenantIdentifier, @SuppressWarnings("unused") final String authToken) { final String actionName, final String tenantIdentifier, @SuppressWarnings("unused") final String authToken) {
final String fineractEndpointUrl = System.getProperty("baseUrl"); final String fineractEndpointUrl = System.getProperty("baseUrl");
final WebHookService service = ProcessorHelper.createWebHookService(url); final WebHookService service = processorHelper.createWebHookService(url);
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
final Callback callback = ProcessorHelper.createCallback(url); final Callback callback = processorHelper.createCallback(url);
if (contentType.equalsIgnoreCase("json") || contentType.contains("json")) { if (contentType.equalsIgnoreCase("json") || contentType.contains("json")) {
final JsonObject json = JsonParser.parseString(payload).getAsJsonObject(); final JsonObject json = JsonParser.parseString(payload).getAsJsonObject();
@@ -77,7 +84,5 @@ public class WebHookProcessor implements HookProcessor {
map = new Gson().fromJson(payload, map.getClass()); map = new Gson().fromJson(payload, map.getClass());
service.sendFormRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, map, callback); service.sendFormRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, map, callback);
} }
} }
} }
@@ -78,17 +78,20 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf
private final TemplateRepository ugdTemplateRepository; private final TemplateRepository ugdTemplateRepository;
private final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
private final ProcessorHelper processorHelper;
@Autowired @Autowired
public HookWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final HookRepository hookRepository, public HookWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final HookRepository hookRepository,
final HookTemplateRepository hookTemplateRepository, final TemplateRepository ugdTemplateRepository, final HookTemplateRepository hookTemplateRepository, final TemplateRepository ugdTemplateRepository,
final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer, final FromJsonHelper fromApiJsonHelper) { final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer, final FromJsonHelper fromApiJsonHelper,
ProcessorHelper processorHelper) {
this.context = context; this.context = context;
this.hookRepository = hookRepository; this.hookRepository = hookRepository;
this.hookTemplateRepository = hookTemplateRepository; this.hookTemplateRepository = hookTemplateRepository;
this.ugdTemplateRepository = ugdTemplateRepository; this.ugdTemplateRepository = ugdTemplateRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
this.processorHelper = processorHelper;
} }
@Transactional @Transactional
@@ -270,7 +273,7 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf
for (final HookConfiguration conf : config) { for (final HookConfiguration conf : config) {
final String fieldValue = conf.getFieldValue(); final String fieldValue = conf.getFieldValue();
if (conf.getFieldName().equals(contentTypeName)) { 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"; final String errorMessage = "content.type.must.be.json.or.form";
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage);
} }
@@ -278,7 +281,7 @@ public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatf
if (conf.getFieldName().equals(payloadURLName)) { if (conf.getFieldName().equals(payloadURLName)) {
try { try {
final WebHookService service = ProcessorHelper.createWebHookService(fieldValue); final WebHookService service = processorHelper.createWebHookService(fieldValue);
service.sendEmptyRequest(); service.sendEmptyRequest();
} catch (RetrofitError re) { } catch (RetrofitError re) {
// Swallow error if it's because of method not supported or // Swallow error if it's because of method not supported or