/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.salesforce; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; import java.util.Optional; import org.apache.camel.NoSuchOptionException; import org.apache.camel.component.salesforce.api.SalesforceException; import org.apache.camel.component.salesforce.api.dto.RestError; import org.apache.camel.component.salesforce.internal.SalesforceSession; import org.apache.camel.component.salesforce.internal.client.DefaultRestClient; import org.apache.camel.impl.verifier.DefaultComponentVerifier; import org.apache.camel.impl.verifier.OptionsGroup; import org.apache.camel.impl.verifier.ResultBuilder; import org.apache.camel.impl.verifier.ResultErrorBuilder; import org.apache.camel.impl.verifier.ResultErrorHelper; import org.apache.camel.util.jsse.SSLContextParameters; import org.eclipse.jetty.client.HttpProxy; import org.eclipse.jetty.client.Origin; import org.eclipse.jetty.client.Socks4Proxy; import org.eclipse.jetty.client.util.BasicAuthentication; import org.eclipse.jetty.client.util.DigestAuthentication; import org.eclipse.jetty.util.ssl.SslContextFactory; public class SalesforceComponentVerifier extends DefaultComponentVerifier { SalesforceComponentVerifier(SalesforceComponent component) { super("salesforce", component.getCamelContext()); } // ********************************* // Parameters validation // ********************************* @Override protected Result verifyParameters(Map<String, Object> parameters) { // Validate mandatory component options, needed to be done here as these // options are not properly marked as mandatory in the catalog. // // Validation rules are borrowed from SalesforceLoginConfig's validate // method, which support 3 workflow: // // - OAuth Username/Password Flow // - OAuth Refresh Token Flow: // - OAuth JWT Flow // ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.PARAMETERS) .errors(ResultErrorHelper.requiresAny(parameters, OptionsGroup.withName(AuthenticationType.USERNAME_PASSWORD) .options("clientId", "clientSecret", "userName", "password", "!refreshToken", "!keystore"), OptionsGroup.withName(AuthenticationType.REFRESH_TOKEN) .options("clientId", "clientSecret", "refreshToken", "!password", "!keystore"), OptionsGroup.withName(AuthenticationType.JWT) .options("clientId", "userName", "keystore", "!password", "!refreshToken"))); // Validate using the catalog super.verifyParametersAgainstCatalog(builder, parameters); return builder.build(); } // ********************************* // Connectivity validation // ********************************* @Override protected Result verifyConnectivity(Map<String, Object> parameters) { // Default is success ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.CONNECTIVITY); try { SalesforceEndpointConfig configuration = new SalesforceEndpointConfig(); setProperties(configuration, parameters); SalesforceLoginConfig loginConfig = new SalesforceLoginConfig(); setProperties(loginConfig, parameters); // Create a dummy SslContextFactory which is needed by SalesforceHttpClient // or the underlying jetty client fails with a NPE SSLContextParameters contextParameters = new SSLContextParameters(); SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setSslContext(contextParameters.createSSLContext(getCamelContext())); SalesforceHttpClient httpClient = new SalesforceHttpClient(sslContextFactory); httpClient.setConnectTimeout(SalesforceComponent.CONNECTION_TIMEOUT); configureHttpProxy(httpClient, parameters); SalesforceSession session = new SalesforceSession(getCamelContext(), httpClient, httpClient.getTimeout(), loginConfig); DefaultRestClient client = new DefaultRestClient(httpClient, configuration.getApiVersion(), configuration.getFormat(), session); httpClient.setSession(session); httpClient.start(); // For authentication check is is enough to use session.start(); client.start(); client.getVersions((response, exception) -> processSalesforceException(builder, Optional.ofNullable(exception))); client.stop(); session.stop(); httpClient.stop(); httpClient.destroy(); } catch (NoSuchOptionException e) { builder.error( ResultErrorBuilder.withMissingOption(e.getOptionName()).build() ); } catch (SalesforceException e) { processSalesforceException(builder, Optional.of(e)); } catch (Exception e) { builder.error( ResultErrorBuilder.withException(e).build() ); } return builder.build(); } // ********************************* // Helpers // ********************************* private void processSalesforceException(ResultBuilder builder, Optional<SalesforceException> exception) { exception.ifPresent(e -> { builder.error( ResultErrorBuilder.withException(e) .detail(VerificationError.HttpAttribute.HTTP_CODE, e.getStatusCode()) .build() ); for (RestError error : e.getErrors()) { builder.error( ResultErrorBuilder.withCode(VerificationError.StandardCode.GENERIC) .description(error.getMessage()) .parameterKeys(error.getFields()) .detail("salesforce_code", error.getErrorCode()) .build() ); } }); } private void configureHttpProxy(SalesforceHttpClient httpClient, Map<String, Object> parameters) throws NoSuchOptionException, URISyntaxException { Optional<String> httpProxyHost = getOption(parameters, "httpProxyHost", String.class); Optional<Integer> httpProxyPort = getOption(parameters, "httpProxyPort", Integer.class); Optional<String> httpProxyUsername = getOption(parameters, "httpProxyUsername", String.class); Optional<String> httpProxyPassword = getOption(parameters, "httpProxyPassword", String.class); if (httpProxyHost.isPresent() && httpProxyPort.isPresent()) { Origin.Address address = new Origin.Address(httpProxyHost.get(), httpProxyPort.get()); Boolean isHttpProxySocks4 = getOption(parameters, "isHttpProxySocks4", Boolean.class, () -> false); Boolean isHttpProxySecure = getOption(parameters, "isHttpProxySecure", Boolean.class, () -> true); if (isHttpProxySocks4) { httpClient.getProxyConfiguration().getProxies().add( new Socks4Proxy(address, isHttpProxySecure) ); } else { httpClient.getProxyConfiguration().getProxies().add( new HttpProxy(address, isHttpProxySecure) ); } } if (httpProxyUsername.isPresent() && httpProxyPassword.isPresent()) { Boolean httpProxyUseDigestAuth = getOption(parameters, "httpProxyUseDigestAuth", Boolean.class, () -> false); String httpProxyAuthUri = getMandatoryOption(parameters, "httpProxyAuthUri", String.class); String httpProxyRealm = getMandatoryOption(parameters, "httpProxyRealm", String.class); if (httpProxyUseDigestAuth) { httpClient.getAuthenticationStore().addAuthentication(new DigestAuthentication( new URI(httpProxyAuthUri), httpProxyRealm, httpProxyUsername.get(), httpProxyPassword.get()) ); } else { httpClient.getAuthenticationStore().addAuthentication(new BasicAuthentication( new URI(httpProxyAuthUri), httpProxyRealm, httpProxyUsername.get(), httpProxyPassword.get()) ); } } } }