http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFTP.java index 1dd8dbf..79d7914 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFTP.java @@ -17,6 +17,7 @@ package org.apache.nifi.processors.standard; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -28,6 +29,8 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.SeeAlso; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessorInitializationContext; import org.apache.nifi.processors.standard.util.FTPTransfer; @@ -76,6 +79,7 @@ public class GetFTP extends GetFileTransfer { properties.add(FTPTransfer.MAX_SELECTS); properties.add(FTPTransfer.REMOTE_POLL_BATCH_SIZE); properties.add(FTPTransfer.USE_NATURAL_ORDERING); + properties.add(FTPTransfer.PROXY_CONFIGURATION_SERVICE); properties.add(FTPTransfer.PROXY_TYPE); properties.add(FTPTransfer.PROXY_HOST); properties.add(FTPTransfer.PROXY_PORT); @@ -95,4 +99,11 @@ public class GetFTP extends GetFileTransfer { protected FileTransfer getFileTransfer(final ProcessContext context) { return new FTPTransfer(context, getLogger()); } + + @Override + protected Collection<ValidationResult> customValidate(ValidationContext validationContext) { + final List<ValidationResult> results = new ArrayList<>(); + FTPTransfer.validateProxySpec(validationContext, results); + return results; + } }
http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java index ec5fc2c..315bb2b 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetHTTP.java @@ -42,7 +42,6 @@ import java.util.regex.Pattern; import javax.net.ssl.SSLContext; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; -import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -93,6 +92,7 @@ import org.apache.nifi.processor.ProcessSessionFactory; import org.apache.nifi.processor.ProcessorInitializationContext; import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.processors.standard.util.HTTPUtils; import org.apache.nifi.security.util.KeyStoreUtils; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.ssl.SSLContextService; @@ -100,6 +100,9 @@ import org.apache.nifi.ssl.SSLContextService.ClientAuth; import org.apache.nifi.util.StopWatch; import org.apache.nifi.util.Tuple; +import static org.apache.nifi.processors.standard.util.HTTPUtils.PROXY_HOST; +import static org.apache.nifi.processors.standard.util.HTTPUtils.PROXY_PORT; + @Tags({"get", "fetch", "poll", "http", "https", "ingest", "source", "input"}) @InputRequirement(Requirement.INPUT_FORBIDDEN) @CapabilityDescription("Fetches data from an HTTP or HTTPS URL and writes the data to the content of a FlowFile. Once the content has been fetched, the ETag and Last Modified " @@ -195,18 +198,6 @@ public class GetHTTP extends AbstractSessionFactoryProcessor { .required(false) .identifiesControllerService(SSLContextService.class) .build(); - public static final PropertyDescriptor PROXY_HOST = new PropertyDescriptor.Builder() - .name("Proxy Host") - .description("The fully qualified hostname or IP address of the proxy server") - .required(false) - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .build(); - public static final PropertyDescriptor PROXY_PORT = new PropertyDescriptor.Builder() - .name("Proxy Port") - .description("The port of the proxy server") - .required(false) - .addValidator(StandardValidators.PORT_VALIDATOR) - .build(); public static final String DEFAULT_COOKIE_POLICY_STR = "default"; public static final String STANDARD_COOKIE_POLICY_STR = "standard"; @@ -268,6 +259,7 @@ public class GetHTTP extends AbstractSessionFactoryProcessor { properties.add(ACCEPT_CONTENT_TYPE); properties.add(FOLLOW_REDIRECTS); properties.add(REDIRECT_COOKIE_POLICY); + properties.add(HTTPUtils.PROXY_CONFIGURATION_SERVICE); properties.add(PROXY_HOST); properties.add(PROXY_PORT); this.properties = Collections.unmodifiableList(properties); @@ -315,13 +307,7 @@ public class GetHTTP extends AbstractSessionFactoryProcessor { .build()); } - if (context.getProperty(PROXY_HOST).isSet() && !context.getProperty(PROXY_PORT).isSet()) { - results.add(new ValidationResult.Builder() - .explanation("Proxy Host was set but no Proxy Port was specified") - .valid(false) - .subject("Proxy server configuration") - .build()); - } + HTTPUtils.validateProxyProperties(context, results); return results; } @@ -456,22 +442,18 @@ public class GetHTTP extends AbstractSessionFactoryProcessor { final String password = context.getProperty(PASSWORD).getValue(); // set the credentials if appropriate + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + clientBuilder.setDefaultCredentialsProvider(credentialsProvider); if (username != null) { - final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); if (password == null) { credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username)); } else { credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); } - clientBuilder.setDefaultCredentialsProvider(credentialsProvider); } // Set the proxy if specified - if (context.getProperty(PROXY_HOST).isSet() && context.getProperty(PROXY_PORT).isSet()) { - final String host = context.getProperty(PROXY_HOST).getValue(); - final int port = context.getProperty(PROXY_PORT).asInteger(); - clientBuilder.setProxy(new HttpHost(host, port)); - } + HTTPUtils.setProxy(context, clientBuilder, credentialsProvider); // create request final HttpGet get = new HttpGet(url); http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetSFTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetSFTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetSFTP.java index e155019..6b891c7 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetSFTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetSFTP.java @@ -33,6 +33,7 @@ import org.apache.nifi.components.ValidationContext; import org.apache.nifi.components.ValidationResult; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessorInitializationContext; +import org.apache.nifi.processors.standard.util.FTPTransfer; import org.apache.nifi.processors.standard.util.FileTransfer; import org.apache.nifi.processors.standard.util.SFTPTransfer; @@ -81,6 +82,12 @@ public class GetSFTP extends GetFileTransfer { properties.add(SFTPTransfer.USE_KEEPALIVE_ON_TIMEOUT); properties.add(SFTPTransfer.USE_COMPRESSION); properties.add(SFTPTransfer.USE_NATURAL_ORDERING); + properties.add(SFTPTransfer.PROXY_CONFIGURATION_SERVICE); + properties.add(FTPTransfer.PROXY_TYPE); + properties.add(FTPTransfer.PROXY_HOST); + properties.add(FTPTransfer.PROXY_PORT); + properties.add(FTPTransfer.HTTP_PROXY_USERNAME); + properties.add(FTPTransfer.HTTP_PROXY_PASSWORD); this.properties = Collections.unmodifiableList(properties); } @@ -102,6 +109,8 @@ public class GetSFTP extends GetFileTransfer { .build()); } + SFTPTransfer.validateProxySpec(context, results); + return results; } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/InvokeHTTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/InvokeHTTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/InvokeHTTP.java index c750bde..7d04698 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/InvokeHTTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/InvokeHTTP.java @@ -59,6 +59,8 @@ import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.processors.standard.util.ProxyAuthenticator; import org.apache.nifi.processors.standard.util.SoftLimitBoundedByteArrayOutputStream; +import org.apache.nifi.proxy.ProxyConfiguration; +import org.apache.nifi.proxy.ProxySpec; import org.apache.nifi.ssl.SSLContextService; import org.apache.nifi.ssl.SSLContextService.ClientAuth; import org.apache.nifi.stream.io.StreamUtils; @@ -79,7 +81,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.InetSocketAddress; import java.net.Proxy; import java.net.Proxy.Type; import java.net.URL; @@ -412,6 +413,10 @@ public final class InvokeHTTP extends AbstractProcessor { .addValidator(StandardValidators.DATA_SIZE_VALIDATOR) .build(); + private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP_AUTH, ProxySpec.SOCKS}; + public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE + = ProxyConfiguration.createProxyConfigPropertyDescriptor(true, PROXY_SPECS); + public static final List<PropertyDescriptor> PROPERTIES = Collections.unmodifiableList(Arrays.asList( PROP_METHOD, PROP_URL, @@ -423,6 +428,7 @@ public final class InvokeHTTP extends AbstractProcessor { PROP_ATTRIBUTES_TO_SEND, PROP_BASIC_AUTH_USERNAME, PROP_BASIC_AUTH_PASSWORD, + PROXY_CONFIGURATION_SERVICE, PROP_PROXY_HOST, PROP_PROXY_PORT, PROP_PROXY_TYPE, @@ -565,6 +571,8 @@ public final class InvokeHTTP extends AbstractProcessor { results.add(new ValidationResult.Builder().subject("SSL Context Service").valid(false).explanation("If Proxy Type is HTTPS, SSL Context Service must be set").build()); } + ProxyConfiguration.validateProxySpec(validationContext, results, PROXY_SPECS); + return results; } @@ -575,14 +583,30 @@ public final class InvokeHTTP extends AbstractProcessor { OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient().newBuilder(); // Add a proxy if set - final String proxyHost = context.getProperty(PROP_PROXY_HOST).evaluateAttributeExpressions().getValue(); - final Integer proxyPort = context.getProperty(PROP_PROXY_PORT).evaluateAttributeExpressions().asInteger(); - final String proxyType = context.getProperty(PROP_PROXY_TYPE).evaluateAttributeExpressions().getValue(); - boolean isHttpsProxy = false; - if (proxyHost != null && proxyPort != null) { - final Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); + boolean isHttpsProxy = HTTPS.equals(context.getProperty(PROP_PROXY_TYPE).evaluateAttributeExpressions().getValue()); + final ProxyConfiguration proxyConfig = ProxyConfiguration.getConfiguration(context, () -> { + final ProxyConfiguration componentProxyConfig = new ProxyConfiguration(); + final String proxyHost = context.getProperty(PROP_PROXY_HOST).evaluateAttributeExpressions().getValue(); + final Integer proxyPort = context.getProperty(PROP_PROXY_PORT).evaluateAttributeExpressions().asInteger(); + if (proxyHost != null && proxyPort != null) { + componentProxyConfig.setProxyType(Type.HTTP); + componentProxyConfig.setProxyServerHost(proxyHost); + componentProxyConfig.setProxyServerPort(proxyPort); + final String proxyUsername = trimToEmpty(context.getProperty(PROP_PROXY_USER).evaluateAttributeExpressions().getValue()); + final String proxyPassword = context.getProperty(PROP_PROXY_PASSWORD).evaluateAttributeExpressions().getValue(); + componentProxyConfig.setProxyUserName(proxyUsername); + componentProxyConfig.setProxyUserPassword(proxyPassword); + } + return componentProxyConfig; + }); + + final Proxy proxy = proxyConfig.createProxy(); + if (!Type.DIRECT.equals(proxy.type())) { okHttpClientBuilder.proxy(proxy); - isHttpsProxy = HTTPS.equals(proxyType); + if (proxyConfig.hasCredential()) { + ProxyAuthenticator proxyAuthenticator = new ProxyAuthenticator(proxyConfig.getProxyUserName(), proxyConfig.getProxyUserPassword()); + okHttpClientBuilder.proxyAuthenticator(proxyAuthenticator); + } } // configure ETag cache if enabled @@ -691,7 +715,6 @@ public final class InvokeHTTP extends AbstractProcessor { private void setAuthenticator(OkHttpClient.Builder okHttpClientBuilder, ProcessContext context) { final String authUser = trimToEmpty(context.getProperty(PROP_BASIC_AUTH_USERNAME).getValue()); - final String proxyUsername = trimToEmpty(context.getProperty(PROP_PROXY_USER).evaluateAttributeExpressions().getValue()); // If the username/password properties are set then check if digest auth is being used if (!authUser.isEmpty() && "true".equalsIgnoreCase(context.getProperty(PROP_DIGEST_AUTH).getValue())) { @@ -706,23 +729,8 @@ public final class InvokeHTTP extends AbstractProcessor { com.burgstaller.okhttp.digest.Credentials credentials = new com.burgstaller.okhttp.digest.Credentials(authUser, authPass); final DigestAuthenticator digestAuthenticator = new DigestAuthenticator(credentials); - if(!proxyUsername.isEmpty()) { - final String proxyPassword = context.getProperty(PROP_PROXY_PASSWORD).evaluateAttributeExpressions().getValue(); - ProxyAuthenticator proxyAuthenticator = new ProxyAuthenticator(proxyUsername, proxyPassword); - - okHttpClientBuilder.proxyAuthenticator(proxyAuthenticator); - } - okHttpClientBuilder.interceptors().add(new AuthenticationCacheInterceptor(authCache)); okHttpClientBuilder.authenticator(new CachingAuthenticatorDecorator(digestAuthenticator, authCache)); - } else { - // Add proxy authentication only - if(!proxyUsername.isEmpty()) { - final String proxyPassword = context.getProperty(PROP_PROXY_PASSWORD).evaluateAttributeExpressions().getValue(); - ProxyAuthenticator proxyAuthenticator = new ProxyAuthenticator(proxyUsername, proxyPassword); - - okHttpClientBuilder.proxyAuthenticator(proxyAuthenticator); - } } } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFTP.java index 8deadb2..79a4177 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFTP.java @@ -18,6 +18,7 @@ package org.apache.nifi.processors.standard; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.apache.nifi.annotation.behavior.InputRequirement; import org.apache.nifi.annotation.behavior.Stateful; @@ -29,6 +30,8 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.SeeAlso; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.components.state.Scope; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processors.standard.util.FileTransfer; @@ -79,6 +82,7 @@ public class ListFTP extends ListFileTransfer { properties.add(FTPTransfer.DATA_TIMEOUT); properties.add(FTPTransfer.CONNECTION_MODE); properties.add(FTPTransfer.TRANSFER_MODE); + properties.add(FTPTransfer.PROXY_CONFIGURATION_SERVICE); properties.add(FTPTransfer.PROXY_TYPE); properties.add(FTPTransfer.PROXY_HOST); properties.add(FTPTransfer.PROXY_PORT); @@ -105,4 +109,11 @@ public class ListFTP extends ListFileTransfer { // pick up where it left off, even if the Primary Node changes. return Scope.CLUSTER; } + + @Override + protected Collection<ValidationResult> customValidate(ValidationContext validationContext) { + final List<ValidationResult> results = new ArrayList<>(); + FTPTransfer.validateProxySpec(validationContext, results); + return results; + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListSFTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListSFTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListSFTP.java index b7805e9..ac1a42d 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListSFTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListSFTP.java @@ -18,6 +18,7 @@ package org.apache.nifi.processors.standard; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.apache.nifi.annotation.behavior.InputRequirement; @@ -30,8 +31,11 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.SeeAlso; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.components.state.Scope; import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processors.standard.util.FTPTransfer; import org.apache.nifi.processors.standard.util.FileTransfer; import org.apache.nifi.processors.standard.util.SFTPTransfer; @@ -83,6 +87,12 @@ public class ListSFTP extends ListFileTransfer { properties.add(SFTPTransfer.DATA_TIMEOUT); properties.add(SFTPTransfer.USE_KEEPALIVE_ON_TIMEOUT); properties.add(TARGET_SYSTEM_TIMESTAMP_PRECISION); + properties.add(SFTPTransfer.PROXY_CONFIGURATION_SERVICE); + properties.add(FTPTransfer.PROXY_TYPE); + properties.add(FTPTransfer.PROXY_HOST); + properties.add(FTPTransfer.PROXY_PORT); + properties.add(FTPTransfer.HTTP_PROXY_USERNAME); + properties.add(FTPTransfer.HTTP_PROXY_PASSWORD); return properties; } @@ -102,4 +112,11 @@ public class ListSFTP extends ListFileTransfer { // pick up where it left off, even if the Primary Node changes. return Scope.CLUSTER; } + + @Override + protected Collection<ValidationResult> customValidate(ValidationContext validationContext) { + final Collection<ValidationResult> results = new ArrayList<>(); + SFTPTransfer.validateProxySpec(validationContext, results); + return results; + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PostHTTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PostHTTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PostHTTP.java index 8bb24bf..ac30830 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PostHTTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PostHTTP.java @@ -19,7 +19,6 @@ package org.apache.nifi.processors.standard; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpException; -import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpResponseInterceptor; import org.apache.http.auth.AuthScope; @@ -75,6 +74,7 @@ import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.io.InputStreamCallback; import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.processors.standard.util.HTTPUtils; import org.apache.nifi.security.util.CertificateUtils; import org.apache.nifi.security.util.KeyStoreUtils; import org.apache.nifi.ssl.SSLContextService; @@ -127,6 +127,9 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; +import static org.apache.nifi.processors.standard.util.HTTPUtils.PROXY_HOST; +import static org.apache.nifi.processors.standard.util.HTTPUtils.PROXY_PORT; + @SupportsBatching @InputRequirement(Requirement.INPUT_REQUIRED) @Tags({"http", "https", "remote", "copy", "archive"}) @@ -243,18 +246,6 @@ public class PostHTTP extends AbstractProcessor { .required(false) .identifiesControllerService(SSLContextService.class) .build(); - public static final PropertyDescriptor PROXY_HOST = new PropertyDescriptor.Builder() - .name("Proxy Host") - .description("The fully qualified hostname or IP address of the proxy server") - .required(false) - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .build(); - public static final PropertyDescriptor PROXY_PORT = new PropertyDescriptor.Builder() - .name("Proxy Port") - .description("The port of the proxy server") - .required(false) - .addValidator(StandardValidators.PORT_VALIDATOR) - .build(); public static final PropertyDescriptor CONTENT_TYPE = new PropertyDescriptor.Builder() .name("Content-Type") .description("The Content-Type to specify for the content of the FlowFile being POSTed if " + SEND_AS_FLOWFILE.getName() + " is false. " @@ -302,6 +293,7 @@ public class PostHTTP extends AbstractProcessor { properties.add(DATA_TIMEOUT); properties.add(ATTRIBUTES_AS_HEADERS_REGEX); properties.add(USER_AGENT); + properties.add(HTTPUtils.PROXY_CONFIGURATION_SERVICE); properties.add(PROXY_HOST); properties.add(PROXY_PORT); properties.add(CONTENT_TYPE); @@ -328,14 +320,6 @@ public class PostHTTP extends AbstractProcessor { .valid(false).subject("SSL Context").build()); } - if (context.getProperty(PROXY_HOST).isSet() && !context.getProperty(PROXY_PORT).isSet()) { - results.add(new ValidationResult.Builder() - .explanation("Proxy Host was set but no Proxy Port was specified") - .valid(false) - .subject("Proxy server configuration") - .build()); - } - boolean sendAsFlowFile = context.getProperty(SEND_AS_FLOWFILE).asBoolean(); int compressionLevel = context.getProperty(COMPRESSION_LEVEL).asInteger(); boolean chunkedSet = context.getProperty(CHUNKED_ENCODING).isSet(); @@ -345,6 +329,8 @@ public class PostHTTP extends AbstractProcessor { .explanation("if compression level is 0 and not sending as a FlowFile, then the \'" + CHUNKED_ENCODING.getName() + "\' property must be set").build()); } + HTTPUtils.validateProxyProperties(context, results); + return results; } @@ -535,22 +521,18 @@ public class PostHTTP extends AbstractProcessor { final String username = context.getProperty(USERNAME).getValue(); final String password = context.getProperty(PASSWORD).getValue(); // set the credentials if appropriate + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + clientBuilder.setDefaultCredentialsProvider(credentialsProvider); if (username != null) { - final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); if (password == null) { credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username)); } else { credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); } - clientBuilder.setDefaultCredentialsProvider(credentialsProvider); } // Set the proxy if specified - if (context.getProperty(PROXY_HOST).isSet() && context.getProperty(PROXY_PORT).isSet()) { - final String host = context.getProperty(PROXY_HOST).getValue(); - final int port = context.getProperty(PROXY_PORT).asInteger(); - clientBuilder.setProxy(new HttpHost(host, port)); - } + HTTPUtils.setProxy(context, clientBuilder, credentialsProvider); client = clientBuilder.build(); http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFTP.java index d4b11fc..50ae599 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFTP.java @@ -18,6 +18,7 @@ package org.apache.nifi.processors.standard; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -36,6 +37,8 @@ import org.apache.nifi.annotation.documentation.SeeAlso; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessorInitializationContext; @@ -89,6 +92,7 @@ public class PutFTP extends PutFileTransfer<FTPTransfer> { properties.add(FTPTransfer.LAST_MODIFIED_TIME); properties.add(FTPTransfer.PERMISSIONS); properties.add(FTPTransfer.USE_COMPRESSION); + properties.add(FTPTransfer.PROXY_CONFIGURATION_SERVICE); properties.add(FTPTransfer.PROXY_TYPE); properties.add(FTPTransfer.PROXY_HOST); properties.add(FTPTransfer.PROXY_PORT); @@ -163,4 +167,11 @@ public class PutFTP extends PutFileTransfer<FTPTransfer> { return cmds; } + + @Override + protected Collection<ValidationResult> customValidate(ValidationContext validationContext) { + final List<ValidationResult> results = new ArrayList<>(); + FTPTransfer.validateProxySpec(validationContext, results); + return results; + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutSFTP.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutSFTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutSFTP.java index fbaeba4..35bb174 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutSFTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutSFTP.java @@ -17,6 +17,7 @@ package org.apache.nifi.processors.standard; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -28,8 +29,11 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.SeeAlso; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessorInitializationContext; +import org.apache.nifi.processors.standard.util.FTPTransfer; import org.apache.nifi.processors.standard.util.SFTPTransfer; @SupportsBatching @@ -70,6 +74,12 @@ public class PutSFTP extends PutFileTransfer<SFTPTransfer> { properties.add(SFTPTransfer.STRICT_HOST_KEY_CHECKING); properties.add(SFTPTransfer.USE_KEEPALIVE_ON_TIMEOUT); properties.add(SFTPTransfer.USE_COMPRESSION); + properties.add(SFTPTransfer.PROXY_CONFIGURATION_SERVICE); + properties.add(FTPTransfer.PROXY_TYPE); + properties.add(FTPTransfer.PROXY_HOST); + properties.add(FTPTransfer.PROXY_PORT); + properties.add(FTPTransfer.HTTP_PROXY_USERNAME); + properties.add(FTPTransfer.HTTP_PROXY_PASSWORD); this.properties = Collections.unmodifiableList(properties); } @@ -83,4 +93,10 @@ public class PutSFTP extends PutFileTransfer<SFTPTransfer> { return new SFTPTransfer(context, getLogger()); } + @Override + protected Collection<ValidationResult> customValidate(ValidationContext validationContext) { + final Collection<ValidationResult> results = new ArrayList<>(); + SFTPTransfer.validateProxySpec(validationContext, results); + return results; + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPTransfer.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPTransfer.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPTransfer.java index 91a5ac2..e2ddf6b 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPTransfer.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPTransfer.java @@ -28,10 +28,12 @@ import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import java.util.regex.Pattern; import org.apache.commons.net.ftp.FTPClient; @@ -39,6 +41,9 @@ import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPHTTPClient; import org.apache.commons.net.ftp.FTPReply; import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.context.PropertyContext; import org.apache.nifi.expression.ExpressionLanguageScope; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.logging.ComponentLog; @@ -46,6 +51,8 @@ import org.apache.nifi.processor.DataUnit; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.proxy.ProxyConfiguration; +import org.apache.nifi.proxy.ProxySpec; public class FTPTransfer implements FileTransfer { @@ -88,22 +95,26 @@ public class FTPTransfer implements FileTransfer { .name("Proxy Host") .description("The fully qualified hostname or IP address of the proxy server") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) .build(); public static final PropertyDescriptor PROXY_PORT = new PropertyDescriptor.Builder() .name("Proxy Port") .description("The port of the proxy server") .addValidator(StandardValidators.PORT_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) .build(); public static final PropertyDescriptor HTTP_PROXY_USERNAME = new PropertyDescriptor.Builder() .name("Http Proxy Username") .description("Http Proxy Username") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) .required(false) .build(); public static final PropertyDescriptor HTTP_PROXY_PASSWORD = new PropertyDescriptor.Builder() .name("Http Proxy Password") .description("Http Proxy Password") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) .required(false) .sensitive(true) .build(); @@ -123,6 +134,10 @@ public class FTPTransfer implements FileTransfer { .addValidator(StandardValidators.BOOLEAN_VALIDATOR) .build(); + private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP_AUTH, ProxySpec.SOCKS}; + public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE + = ProxyConfiguration.createProxyConfigPropertyDescriptor(true, PROXY_SPECS); + private final ComponentLog logger; private final ProcessContext ctx; @@ -136,6 +151,10 @@ public class FTPTransfer implements FileTransfer { this.logger = logger; } + public static void validateProxySpec(ValidationContext context, Collection<ValidationResult> results) { + ProxyConfiguration.validateProxySpec(context, results, PROXY_SPECS); + } + @Override public String getProtocolName() { return "ftp"; @@ -522,12 +541,15 @@ public class FTPTransfer implements FileTransfer { } } - final Proxy.Type proxyType = Proxy.Type.valueOf(ctx.getProperty(PROXY_TYPE).getValue()); - final String proxyHost = ctx.getProperty(PROXY_HOST).getValue(); - final Integer proxyPort = ctx.getProperty(PROXY_PORT).asInteger(); + final ProxyConfiguration proxyConfig = ProxyConfiguration.getConfiguration(ctx, createComponentProxyConfigSupplier(ctx)); + + final Proxy.Type proxyType = proxyConfig.getProxyType(); + final String proxyHost = proxyConfig.getProxyServerHost(); + final Integer proxyPort = proxyConfig.getProxyServerPort(); + FTPClient client; if (proxyType == Proxy.Type.HTTP) { - client = new FTPHTTPClient(proxyHost, proxyPort, ctx.getProperty(HTTP_PROXY_USERNAME).getValue(), ctx.getProperty(HTTP_PROXY_PASSWORD).getValue()); + client = new FTPHTTPClient(proxyHost, proxyPort, proxyConfig.getProxyUserName(), proxyConfig.getProxyUserPassword()); } else { client = new FTPClient(); if (proxyType == Proxy.Type.SOCKS) { @@ -627,4 +649,17 @@ public class FTPTransfer implements FileTransfer { } return number; } + + public static Supplier<ProxyConfiguration> createComponentProxyConfigSupplier(final PropertyContext ctx) { + return () -> { + final ProxyConfiguration componentProxyConfig = new ProxyConfiguration(); + componentProxyConfig.setProxyType(Proxy.Type.valueOf(ctx.getProperty(PROXY_TYPE).getValue())); + componentProxyConfig.setProxyServerHost(ctx.getProperty(PROXY_HOST).evaluateAttributeExpressions().getValue()); + componentProxyConfig.setProxyServerPort(ctx.getProperty(PROXY_PORT).evaluateAttributeExpressions().asInteger()); + componentProxyConfig.setProxyUserName(ctx.getProperty(HTTP_PROXY_USERNAME).evaluateAttributeExpressions().getValue()); + componentProxyConfig.setProxyUserPassword(ctx.getProperty(HTTP_PROXY_PASSWORD).evaluateAttributeExpressions().getValue()); + return componentProxyConfig; + }; + } + } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPUtils.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPUtils.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPUtils.java index d9aeb67..dcbad7d 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPUtils.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FTPUtils.java @@ -297,4 +297,5 @@ public class FTPUtils { } } + } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/HTTPUtils.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/HTTPUtils.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/HTTPUtils.java index 937554d..6916fa7 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/HTTPUtils.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/HTTPUtils.java @@ -16,6 +16,21 @@ */ package org.apache.nifi.processors.standard.util; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.proxy.ProxyConfiguration; +import org.apache.nifi.proxy.ProxySpec; + +import java.net.Proxy; +import java.util.Collection; import java.util.Map; public class HTTPUtils { @@ -39,4 +54,63 @@ public class HTTPUtils { } } + public static final PropertyDescriptor PROXY_HOST = new PropertyDescriptor.Builder() + .name("Proxy Host") + .description("The fully qualified hostname or IP address of the proxy server") + .required(false) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .build(); + + public static final PropertyDescriptor PROXY_PORT = new PropertyDescriptor.Builder() + .name("Proxy Port") + .description("The port of the proxy server") + .required(false) + .addValidator(StandardValidators.PORT_VALIDATOR) + .build(); + + private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP_AUTH}; + public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE + = ProxyConfiguration.createProxyConfigPropertyDescriptor(true, PROXY_SPECS); + + + public static void setProxy(final ProcessContext context, final HttpClientBuilder clientBuilder, final CredentialsProvider credentialsProvider) { + // Set the proxy if specified + final ProxyConfiguration proxyConfig = ProxyConfiguration.getConfiguration(context, () -> { + if (context.getProperty(PROXY_HOST).isSet() && context.getProperty(PROXY_PORT).isSet()) { + final ProxyConfiguration componentProxyConfig = new ProxyConfiguration(); + final String host = context.getProperty(PROXY_HOST).getValue(); + final int port = context.getProperty(PROXY_PORT).asInteger(); + componentProxyConfig.setProxyType(Proxy.Type.HTTP); + componentProxyConfig.setProxyServerHost(host); + componentProxyConfig.setProxyServerPort(port); + return componentProxyConfig; + } + return ProxyConfiguration.DIRECT_CONFIGURATION; + }); + + if (Proxy.Type.HTTP.equals(proxyConfig.getProxyType())) { + final String host = proxyConfig.getProxyServerHost(); + final int port = proxyConfig.getProxyServerPort(); + clientBuilder.setProxy(new HttpHost(host, port)); + + if (proxyConfig.hasCredential()) { + final AuthScope proxyAuthScope = new AuthScope(host, port); + final UsernamePasswordCredentials proxyCredential + = new UsernamePasswordCredentials(proxyConfig.getProxyUserName(), proxyConfig.getProxyUserPassword()); + credentialsProvider.setCredentials(proxyAuthScope, proxyCredential); + } + } + } + + public static void validateProxyProperties(ValidationContext context, Collection<ValidationResult> results) { + if (context.getProperty(PROXY_HOST).isSet() && !context.getProperty(PROXY_PORT).isSet()) { + results.add(new ValidationResult.Builder() + .explanation("Proxy Host was set but no Proxy Port was specified") + .valid(false) + .subject("Proxy server configuration") + .build()); + } + + ProxyConfiguration.validateProxySpec(context, results, PROXY_SPECS); + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java index c11a53b..4fc94ec 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/SFTPTransfer.java @@ -25,6 +25,7 @@ import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; @@ -33,13 +34,18 @@ import java.util.Vector; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +import com.jcraft.jsch.ProxySOCKS5; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.PropertyValue; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.expression.ExpressionLanguageScope; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.logging.ComponentLog; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.proxy.ProxyConfiguration; +import org.apache.nifi.proxy.ProxySpec; import org.slf4j.LoggerFactory; import com.jcraft.jsch.ChannelSftp; @@ -47,9 +53,12 @@ import com.jcraft.jsch.ChannelSftp.LsEntry; import com.jcraft.jsch.ChannelSftp.LsEntrySelector; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.ProxyHTTP; import com.jcraft.jsch.Session; import com.jcraft.jsch.SftpException; +import static org.apache.nifi.processors.standard.util.FTPTransfer.createComponentProxyConfigSupplier; + public class SFTPTransfer implements FileTransfer { public static final PropertyDescriptor PRIVATE_KEY_PATH = new PropertyDescriptor.Builder() @@ -96,6 +105,7 @@ public class SFTPTransfer implements FileTransfer { .required(true) .build(); + /** * Property which is used to decide if the {@link #ensureDirectoryExists(FlowFile, File)} method should perform a {@link ChannelSftp#ls(String)} before calling * {@link ChannelSftp#mkdir(String)}. In most cases, the code should call ls before mkdir, but some weird permission setups (chmod 100) on a directory would cause the 'ls' to throw a permission @@ -116,6 +126,10 @@ public class SFTPTransfer implements FileTransfer { .defaultValue("false") .build(); + private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP_AUTH, ProxySpec.SOCKS_AUTH}; + public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE + = ProxyConfiguration.createProxyConfigPropertyDescriptor(true, PROXY_SPECS); + private final ComponentLog logger; private final ProcessContext ctx; @@ -134,6 +148,10 @@ public class SFTPTransfer implements FileTransfer { disableDirectoryListing = disableListing == null ? false : Boolean.TRUE.equals(disableListing.asBoolean()); } + public static void validateProxySpec(ValidationContext context, Collection<ValidationResult> results) { + ProxyConfiguration.validateProxySpec(context, results, PROXY_SPECS); + } + @Override public String getProtocolName() { return "sftp"; @@ -418,6 +436,26 @@ public class SFTPTransfer implements FileTransfer { ctx.getProperty(HOSTNAME).evaluateAttributeExpressions(flowFile).getValue(), ctx.getProperty(PORT).evaluateAttributeExpressions(flowFile).asInteger().intValue()); + final ProxyConfiguration proxyConfig = ProxyConfiguration.getConfiguration(ctx, createComponentProxyConfigSupplier(ctx)); + switch (proxyConfig.getProxyType()) { + case HTTP: + final ProxyHTTP proxyHTTP = new ProxyHTTP(proxyConfig.getProxyServerHost(), proxyConfig.getProxyServerPort()); + // Check if Username is set and populate the proxy accordingly + if (proxyConfig.hasCredential()) { + proxyHTTP.setUserPasswd(proxyConfig.getProxyUserName(), proxyConfig.getProxyUserPassword()); + } + session.setProxy(proxyHTTP); + break; + case SOCKS: + final ProxySOCKS5 proxySOCKS5 = new ProxySOCKS5(proxyConfig.getProxyServerHost(), proxyConfig.getProxyServerPort()); + if (proxyConfig.hasCredential()) { + proxySOCKS5.setUserPasswd(proxyConfig.getProxyUserName(), proxyConfig.getProxyUserPassword()); + } + session.setProxy(proxySOCKS5); + break; + + } + final String hostKeyVal = ctx.getProperty(HOST_KEY_FILE).getValue(); if (hostKeyVal != null) { jsch.setKnownHosts(hostKeyVal); http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/pom.xml new file mode 100644 index 0000000..2a8ac03 --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/pom.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>nifi-standard-services</artifactId> + <groupId>org.apache.nifi</groupId> + <version>1.7.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>nifi-proxy-configuration-api</artifactId> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-mock</artifactId> + <version>1.7.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + </dependencies> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfiguration.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfiguration.java b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfiguration.java new file mode 100644 index 0000000..e6d498c --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfiguration.java @@ -0,0 +1,207 @@ +/* + * 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.nifi.proxy; + +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.context.PropertyContext; + +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static org.apache.nifi.proxy.ProxyConfigurationService.PROXY_CONFIGURATION_SERVICE; +import static org.apache.nifi.proxy.ProxySpec.HTTP; +import static org.apache.nifi.proxy.ProxySpec.HTTP_AUTH; +import static org.apache.nifi.proxy.ProxySpec.SOCKS; +import static org.apache.nifi.proxy.ProxySpec.SOCKS_AUTH; + +public class ProxyConfiguration { + + public static final ProxyConfiguration DIRECT_CONFIGURATION = new ProxyConfiguration(); + + public static PropertyDescriptor createProxyConfigPropertyDescriptor(final boolean hasComponentProxyConfigs, final ProxySpec ... _specs) { + + final Set<ProxySpec> specs = getUniqueProxySpecs(_specs); + + final StringBuilder description = new StringBuilder("Specifies the Proxy Configuration Controller Service to proxy network requests."); + if (hasComponentProxyConfigs) { + description.append(" If set, it supersedes proxy settings configured per component."); + } + description.append(" Supported proxies: "); + description.append(specs.stream().map(ProxySpec::getDisplayName).collect(Collectors.joining(", "))); + + return new PropertyDescriptor.Builder() + .fromPropertyDescriptor(ProxyConfigurationService.PROXY_CONFIGURATION_SERVICE) + .description(description.toString()) + .build(); + } + + /** + * Remove redundancy. If X_AUTH is supported, then X should be supported, too. + * @param _specs original specs + * @return sorted unique specs + */ + private static Set<ProxySpec> getUniqueProxySpecs(ProxySpec ... _specs) { + final Set<ProxySpec> specs = Arrays.stream(_specs).sorted().collect(Collectors.toSet()); + if (specs.contains(HTTP_AUTH)) { + specs.remove(HTTP); + } + if (specs.contains(SOCKS_AUTH)) { + specs.remove(SOCKS); + } + return specs; + } + + /** + * This method can be used from customValidate method of components using this Controller Service + * to validate the service is configured with the supported proxy types. + * @param context the validation context + * @param results if validation fails, an invalid validation result will be added to this collection + * @param _specs specify supported proxy specs + */ + public static void validateProxySpec(ValidationContext context, Collection<ValidationResult> results, final ProxySpec ... _specs) { + + final Set<ProxySpec> specs = getUniqueProxySpecs(_specs); + final Set<Proxy.Type> supportedProxyTypes = specs.stream().map(ProxySpec::getProxyType).collect(Collectors.toSet()); + + if (!context.getProperty(PROXY_CONFIGURATION_SERVICE).isSet()) { + return; + } + + final ProxyConfigurationService proxyService = context.getProperty(PROXY_CONFIGURATION_SERVICE).asControllerService(ProxyConfigurationService.class); + final ProxyConfiguration proxyConfiguration = proxyService.getConfiguration(); + final Proxy.Type proxyType = proxyConfiguration.getProxyType(); + + if (proxyType.equals(Proxy.Type.DIRECT)) { + return; + } + + if (!supportedProxyTypes.contains(proxyType)) { + results.add(new ValidationResult.Builder() + .explanation(String.format("Proxy type %s is not supported.", proxyType)) + .valid(false) + .subject(PROXY_CONFIGURATION_SERVICE.getDisplayName()) + .build()); + + // If the proxy type is not supported, no need to do further validation. + return; + } + + if (proxyConfiguration.hasCredential()) { + // If credential is set, check whether the component is capable to use it. + if (!specs.contains(Proxy.Type.HTTP.equals(proxyType) ? HTTP_AUTH : SOCKS_AUTH)) { + results.add(new ValidationResult.Builder() + .explanation(String.format("Proxy type %s with Authentication is not supported.", proxyType)) + .valid(false) + .subject(PROXY_CONFIGURATION_SERVICE.getDisplayName()) + .build()); + } + } + + + } + + /** + * A convenient method to get ProxyConfiguration instance from a PropertyContext. + * @param context the process context + * @return The proxy configurations at Controller Service if set, or DIRECT_CONFIGURATION + */ + public static ProxyConfiguration getConfiguration(PropertyContext context) { + return getConfiguration(context, () -> DIRECT_CONFIGURATION); + } + + /** + * This method can be used by Components those originally have per component proxy configurations + * to implement ProxyConfiguration Controller Service with backward compatibility. + * @param context the process context + * @param perComponentSetting the function to supply ProxyConfiguration based on per component settings, + * only called when Proxy Configuration Service is not set + * @return The proxy configurations at Controller Service if set, or per component settings otherwise + */ + public static ProxyConfiguration getConfiguration(PropertyContext context, Supplier<ProxyConfiguration> perComponentSetting) { + if (context.getProperty(PROXY_CONFIGURATION_SERVICE).isSet()) { + final ProxyConfigurationService proxyService = context.getProperty(PROXY_CONFIGURATION_SERVICE).asControllerService(ProxyConfigurationService.class); + return proxyService.getConfiguration(); + } else { + return perComponentSetting.get(); + } + } + + private Proxy.Type proxyType = Proxy.Type.DIRECT; + private String proxyServerHost; + private Integer proxyServerPort; + private String proxyUserName; + private String proxyUserPassword; + + public Proxy.Type getProxyType() { + return proxyType; + } + + public void setProxyType(Proxy.Type proxyType) { + this.proxyType = proxyType; + } + + public String getProxyServerHost() { + return proxyServerHost; + } + + public void setProxyServerHost(String proxyServerHost) { + this.proxyServerHost = proxyServerHost; + } + + public Integer getProxyServerPort() { + return proxyServerPort; + } + + public void setProxyServerPort(Integer proxyServerPort) { + this.proxyServerPort = proxyServerPort; + } + + public boolean hasCredential() { + return proxyUserName != null && !proxyUserName.isEmpty(); + } + + public String getProxyUserName() { + return proxyUserName; + } + + public void setProxyUserName(String proxyUserName) { + this.proxyUserName = proxyUserName; + } + + public String getProxyUserPassword() { + return proxyUserPassword; + } + + public void setProxyUserPassword(String proxyUserPassword) { + this.proxyUserPassword = proxyUserPassword; + } + + /** + * Create a Proxy instance based on proxy type, proxy server host and port. + */ + public Proxy createProxy() { + return Proxy.Type.DIRECT.equals(proxyType) ? Proxy.NO_PROXY : new Proxy(proxyType, new InetSocketAddress(proxyServerHost, proxyServerPort)); + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfigurationService.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfigurationService.java b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfigurationService.java new file mode 100644 index 0000000..8e6594b --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxyConfigurationService.java @@ -0,0 +1,44 @@ +/* + * 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.nifi.proxy; + +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.controller.ControllerService; + +/** + * Provides configurations to access a Proxy server. + */ +public interface ProxyConfigurationService extends ControllerService { + + PropertyDescriptor PROXY_CONFIGURATION_SERVICE = new PropertyDescriptor.Builder() + .name("proxy-configuration-service") + .displayName("Proxy Configuration Service") + .description("Specifies the Proxy Configuration Controller Service to proxy network requests." + + " If set, it supersedes proxy settings configured per component.") + .identifiesControllerService(ProxyConfigurationService.class) + .required(false) + .build(); + + /** + * Returns proxy configurations. + * Implementations should return a non-null ProxyConfiguration instance which returns DIRECT proxy type instead of returning null, + * when underlying configuration or initialization is not done yet. + * @return A ProxyConfiguration instance. + */ + ProxyConfiguration getConfiguration(); + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxySpec.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxySpec.java b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxySpec.java new file mode 100644 index 0000000..06783c2 --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/main/java/org/apache/nifi/proxy/ProxySpec.java @@ -0,0 +1,43 @@ +/* + * 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.nifi.proxy; + +import java.net.Proxy; + +public enum ProxySpec { + + HTTP(Proxy.Type.HTTP, "HTTP"), + HTTP_AUTH(Proxy.Type.HTTP, "HTTP + AuthN"), + SOCKS(Proxy.Type.SOCKS, "SOCKS"), + SOCKS_AUTH(Proxy.Type.SOCKS, "SOCKS + AuthN"); + + private Proxy.Type proxyType; + private String displayName; + + ProxySpec(Proxy.Type type, String displayName) { + this.proxyType = type; + this.displayName = displayName; + } + + public Proxy.Type getProxyType() { + return proxyType; + } + + public String getDisplayName() { + return displayName; + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/test/java/org/apache/nifi/proxy/TestProxyConfiguration.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/test/java/org/apache/nifi/proxy/TestProxyConfiguration.java b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/test/java/org/apache/nifi/proxy/TestProxyConfiguration.java new file mode 100644 index 0000000..2cd4fb2 --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-api/src/test/java/org/apache/nifi/proxy/TestProxyConfiguration.java @@ -0,0 +1,166 @@ +/* + * 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.nifi.proxy; + +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.processor.AbstractProcessor; +import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processor.ProcessSession; +import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.reporting.InitializationException; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; +import org.junit.Test; + +import java.net.Proxy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.apache.nifi.proxy.ProxyConfiguration.DIRECT_CONFIGURATION; +import static org.apache.nifi.proxy.ProxyConfiguration.createProxyConfigPropertyDescriptor; +import static org.apache.nifi.proxy.ProxyConfigurationService.PROXY_CONFIGURATION_SERVICE; +import static org.apache.nifi.proxy.ProxySpec.HTTP; +import static org.apache.nifi.proxy.ProxySpec.HTTP_AUTH; +import static org.apache.nifi.proxy.ProxySpec.SOCKS; +import static org.apache.nifi.proxy.ProxySpec.SOCKS_AUTH; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class TestProxyConfiguration { + + private static class ComponentUsingProxy extends AbstractProcessor { + + private ProxySpec[] proxySpecs; + + private void setProxySpecs(ProxySpec ... proxySpecs) { + this.proxySpecs = proxySpecs; + } + + @Override + protected List<PropertyDescriptor> getSupportedPropertyDescriptors() { + return Collections.singletonList(createProxyConfigPropertyDescriptor(true, proxySpecs)); + } + + @Override + public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException { + + } + + @Override + protected Collection<ValidationResult> customValidate(ValidationContext validationContext) { + final List<ValidationResult> results = new ArrayList<>(); + ProxyConfiguration.validateProxySpec(validationContext, results, proxySpecs); + return results; + } + } + + private static final ProxyConfiguration HTTP_CONFIG = new ProxyConfiguration(); + private static final ProxyConfiguration SOCKS_CONFIG = new ProxyConfiguration(); + private static final ProxyConfiguration HTTP_AUTH_CONFIG = new ProxyConfiguration(); + private static final ProxyConfiguration SOCKS_AUTH_CONFIG = new ProxyConfiguration(); + + static { + HTTP_CONFIG.setProxyType(Proxy.Type.HTTP); + + HTTP_AUTH_CONFIG.setProxyType(Proxy.Type.HTTP); + HTTP_AUTH_CONFIG.setProxyUserName("proxy-user"); + HTTP_AUTH_CONFIG.setProxyUserPassword("proxy-password"); + + SOCKS_CONFIG.setProxyType(Proxy.Type.SOCKS); + + SOCKS_AUTH_CONFIG.setProxyType(Proxy.Type.SOCKS); + SOCKS_AUTH_CONFIG.setProxyUserName("proxy-user"); + SOCKS_AUTH_CONFIG.setProxyUserPassword("proxy-password"); + } + + private void testValidateProxySpec(final boolean[] expectations, ProxySpec ... specs) throws InitializationException { + final String serviceId = "proxyConfigurationService"; + final ProxyConfigurationService service = mock(ProxyConfigurationService.class); + when(service.getIdentifier()).thenReturn(serviceId); + when(service.getConfiguration()).thenReturn(DIRECT_CONFIGURATION, HTTP_CONFIG, HTTP_AUTH_CONFIG, SOCKS_CONFIG, SOCKS_AUTH_CONFIG); + + + final ComponentUsingProxy processor = new ComponentUsingProxy(); + processor.setProxySpecs(specs); + + final TestRunner testRunner = TestRunners.newTestRunner(processor); + testRunner.addControllerService(serviceId, service); + testRunner.enableControllerService(service); + testRunner.setProperty(PROXY_CONFIGURATION_SERVICE, serviceId); + + for (boolean expectation : expectations) { + if (expectation) { + testRunner.assertValid(); + } else { + testRunner.assertNotValid(); + } + } + } + + @Test + public void testHTTP() throws Exception { + // DEFAULT, HTTP + testValidateProxySpec(new boolean[] {true, true, false, false, false}, HTTP); + + } + + @Test + public void testHTTPAuth() throws Exception { + // DEFAULT, HTTP, HTTP_AUTH + testValidateProxySpec(new boolean[] {true, true, true, false, false}, HTTP_AUTH); + } + + @Test + public void testHTTP_HTTPAuth() throws Exception { + // DEFAULT, HTTP, HTTP_AUTH + testValidateProxySpec(new boolean[] {true, true, true, false, false}, HTTP, HTTP_AUTH); + } + + @Test + public void testSOCKS() throws Exception { + // DEFAULT, SOCKS + testValidateProxySpec(new boolean[] {true, false, false, true, false}, SOCKS); + } + + @Test + public void testSOCKSAuth() throws Exception { + // DEFAULT, SOCKS, SOCKS_AUTH + testValidateProxySpec(new boolean[] {true, false, false, true, true}, SOCKS_AUTH); + } + + @Test + public void testSOCKS_SOCKSAuth() throws Exception { + // DEFAULT, SOCKS, SOCKS_AUTH + testValidateProxySpec(new boolean[] {true, false, false, true, true}, SOCKS, SOCKS_AUTH); + } + + @Test + public void testHTTPAuth_SOCKS() throws Exception { + // DEFAULT, HTTP, HTTP_AUTH, SOCKS + testValidateProxySpec(new boolean[] {true, true, true, true, false}, HTTP_AUTH, SOCKS); + } + + @Test + public void testHTTPAuth_SOCKSAuth() throws Exception { + // DEFAULT, HTTP, HTTP_AUTH, SOCKS, SOCKS_AUTH + testValidateProxySpec(new boolean[] {true, true, true, true, true}, HTTP_AUTH, SOCKS_AUTH); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration-nar/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration-nar/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration-nar/pom.xml new file mode 100644 index 0000000..6d1cab8 --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration-nar/pom.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>nifi-proxy-configuration-bundle</artifactId> + <groupId>org.apache.nifi</groupId> + <version>1.7.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>nifi-proxy-configuration-nar</artifactId> + <packaging>nar</packaging> + + <dependencies> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-standard-services-api-nar</artifactId> + <version>1.7.0-SNAPSHOT</version> + <type>nar</type> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-proxy-configuration</artifactId> + <version>1.7.0-SNAPSHOT</version> + </dependency> + </dependencies> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/pom.xml new file mode 100644 index 0000000..0186277 --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/pom.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>nifi-proxy-configuration-bundle</artifactId> + <groupId>org.apache.nifi</groupId> + <version>1.7.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>nifi-proxy-configuration</artifactId> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-api</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-proxy-configuration-api</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-standard-utils</artifactId> + <version>1.7.0-SNAPSHOT</version> + </dependency> + </dependencies> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/2834fa4c/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/src/main/java/org/apache/nifi/proxy/StandardProxyConfigurationService.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/src/main/java/org/apache/nifi/proxy/StandardProxyConfigurationService.java b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/src/main/java/org/apache/nifi/proxy/StandardProxyConfigurationService.java new file mode 100644 index 0000000..a3b3f51 --- /dev/null +++ b/nifi-nar-bundles/nifi-standard-services/nifi-proxy-configuration-bundle/nifi-proxy-configuration/src/main/java/org/apache/nifi/proxy/StandardProxyConfigurationService.java @@ -0,0 +1,128 @@ +/* + * 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.nifi.proxy; + +import org.apache.nifi.annotation.documentation.CapabilityDescription; +import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnEnabled; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.controller.AbstractControllerService; +import org.apache.nifi.controller.ConfigurationContext; +import org.apache.nifi.expression.ExpressionLanguageScope; +import org.apache.nifi.processor.util.StandardValidators; + +import java.net.Proxy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@CapabilityDescription("Provides a set of configurations for different NiFi components to use a proxy server.") +@Tags({"Proxy"}) +public class StandardProxyConfigurationService extends AbstractControllerService implements ProxyConfigurationService { + + static final PropertyDescriptor PROXY_TYPE = new PropertyDescriptor.Builder() + .name("proxy-type") + .displayName("Proxy Type") + .description("Proxy type.") + .allowableValues(Proxy.Type.values()) + .defaultValue(Proxy.Type.DIRECT.name()) + .required(true) + .build(); + + static final PropertyDescriptor PROXY_SERVER_HOST = new PropertyDescriptor.Builder() + .name("proxy-server-host") + .displayName("Proxy Server Host") + .description("Proxy server hostname or ip-address.") + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .build(); + + static final PropertyDescriptor PROXY_SERVER_PORT = new PropertyDescriptor.Builder() + .name("proxy-server-port") + .displayName("Proxy Server Port") + .description("Proxy server port number.") + .addValidator(StandardValidators.PORT_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .build(); + + static final PropertyDescriptor PROXY_USER_NAME = new PropertyDescriptor.Builder() + .name("proxy-user-name") + .displayName("Proxy User Name") + .description("The name of the proxy client for user authentication.") + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .build(); + + static final PropertyDescriptor PROXY_USER_PASSWORD = new PropertyDescriptor.Builder() + .name("proxy-user-password") + .displayName("Proxy User Password") + .description("The password of the proxy client for user authentication.") + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) + .sensitive(true) + .build(); + + private volatile ProxyConfiguration configuration = ProxyConfiguration.DIRECT_CONFIGURATION; + + @Override + protected List<PropertyDescriptor> getSupportedPropertyDescriptors() { + final List<PropertyDescriptor> properties = new ArrayList<>(); + properties.add(PROXY_TYPE); + properties.add(PROXY_SERVER_HOST); + properties.add(PROXY_SERVER_PORT); + properties.add(PROXY_USER_NAME); + properties.add(PROXY_USER_PASSWORD); + return properties; + } + + @OnEnabled + public void setConfiguredValues(final ConfigurationContext context) { + configuration = new ProxyConfiguration(); + configuration.setProxyType(Proxy.Type.valueOf(context.getProperty(PROXY_TYPE).getValue())); + configuration.setProxyServerHost(context.getProperty(PROXY_SERVER_HOST).evaluateAttributeExpressions().getValue()); + configuration.setProxyServerPort(context.getProperty(PROXY_SERVER_PORT).evaluateAttributeExpressions().asInteger()); + configuration.setProxyUserName(context.getProperty(PROXY_USER_NAME).evaluateAttributeExpressions().getValue()); + configuration.setProxyUserPassword(context.getProperty(PROXY_USER_PASSWORD).evaluateAttributeExpressions().getValue()); + } + + @Override + protected Collection<ValidationResult> customValidate(ValidationContext validationContext) { + final Proxy.Type proxyType = Proxy.Type.valueOf(validationContext.getProperty(PROXY_TYPE).getValue()); + if (Proxy.Type.DIRECT.equals(proxyType)) { + return Collections.emptyList(); + } + + final List<ValidationResult> results = new ArrayList<>(); + if (!validationContext.getProperty(PROXY_SERVER_HOST).isSet()) { + results.add(new ValidationResult.Builder().subject(PROXY_SERVER_HOST.getDisplayName()) + .explanation("required").valid(false).build()); + } + if (!validationContext.getProperty(PROXY_SERVER_PORT).isSet()) { + results.add(new ValidationResult.Builder().subject(PROXY_SERVER_PORT.getDisplayName()) + .explanation("required").valid(false).build()); + } + return results; + } + + @Override + public ProxyConfiguration getConfiguration() { + return configuration; + } +}