mirror of https://github.com/apache/nifi.git
NIFI-6019 Removes "trusted hostname" property.
NIFI-6019 Adds support for excluded HTTP headers. This closes #3452. Signed-off-by: Andy LoPresto <alopresto@apache.org>
This commit is contained in:
parent
9194726b35
commit
1cadc72222
|
@ -30,7 +30,6 @@ import okhttp3.Request;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import okhttp3.ResponseBody;
|
import okhttp3.ResponseBody;
|
||||||
import okhttp3.internal.tls.OkHostnameVerifier;
|
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
import org.apache.commons.io.input.TeeInputStream;
|
import org.apache.commons.io.input.TeeInputStream;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -54,6 +53,7 @@ import org.apache.nifi.logging.ComponentLog;
|
||||||
import org.apache.nifi.processor.AbstractProcessor;
|
import org.apache.nifi.processor.AbstractProcessor;
|
||||||
import org.apache.nifi.processor.DataUnit;
|
import org.apache.nifi.processor.DataUnit;
|
||||||
import org.apache.nifi.processor.ProcessContext;
|
import org.apache.nifi.processor.ProcessContext;
|
||||||
|
import org.apache.nifi.processor.ProcessorInitializationContext;
|
||||||
import org.apache.nifi.processor.ProcessSession;
|
import org.apache.nifi.processor.ProcessSession;
|
||||||
import org.apache.nifi.processor.Relationship;
|
import org.apache.nifi.processor.Relationship;
|
||||||
import org.apache.nifi.processor.exception.ProcessException;
|
import org.apache.nifi.processor.exception.ProcessException;
|
||||||
|
@ -155,6 +155,9 @@ public final class InvokeHTTP extends AbstractProcessor {
|
||||||
EXCEPTION_CLASS, EXCEPTION_MESSAGE,
|
EXCEPTION_CLASS, EXCEPTION_MESSAGE,
|
||||||
"uuid", "filename", "path")));
|
"uuid", "filename", "path")));
|
||||||
|
|
||||||
|
// Set of HTTP header names explicitly excluded from requests.
|
||||||
|
private static final Map<String, String> excludedHeaders = new HashMap<String, String>();
|
||||||
|
|
||||||
public static final String HTTP = "http";
|
public static final String HTTP = "http";
|
||||||
public static final String HTTPS = "https";
|
public static final String HTTPS = "https";
|
||||||
|
|
||||||
|
@ -360,15 +363,6 @@ public final class InvokeHTTP extends AbstractProcessor {
|
||||||
.allowableValues("true", "false")
|
.allowableValues("true", "false")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final PropertyDescriptor PROP_TRUSTED_HOSTNAME = new PropertyDescriptor.Builder()
|
|
||||||
.name("Trusted Hostname")
|
|
||||||
.description("Bypass the normal truststore hostname verifier to allow the specified remote hostname as trusted. "
|
|
||||||
+ "Enabling this property has MITM security implications, use wisely. Will still accept other connections based "
|
|
||||||
+ "on the normal truststore hostname verifier. Only valid with SSL (HTTPS) connections.")
|
|
||||||
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
|
|
||||||
.required(false)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public static final PropertyDescriptor PROP_ADD_HEADERS_TO_REQUEST = new PropertyDescriptor.Builder()
|
public static final PropertyDescriptor PROP_ADD_HEADERS_TO_REQUEST = new PropertyDescriptor.Builder()
|
||||||
.name("Add Response Headers to Request")
|
.name("Add Response Headers to Request")
|
||||||
.description("Enabling this property saves all the response headers to the original request. This may be when the response headers are needed "
|
.description("Enabling this property saves all the response headers to the original request. This may be when the response headers are needed "
|
||||||
|
@ -438,7 +432,6 @@ public final class InvokeHTTP extends AbstractProcessor {
|
||||||
PROP_PUT_ATTRIBUTE_MAX_LENGTH,
|
PROP_PUT_ATTRIBUTE_MAX_LENGTH,
|
||||||
PROP_DIGEST_AUTH,
|
PROP_DIGEST_AUTH,
|
||||||
PROP_OUTPUT_RESPONSE_REGARDLESS,
|
PROP_OUTPUT_RESPONSE_REGARDLESS,
|
||||||
PROP_TRUSTED_HOSTNAME,
|
|
||||||
PROP_ADD_HEADERS_TO_REQUEST,
|
PROP_ADD_HEADERS_TO_REQUEST,
|
||||||
PROP_CONTENT_TYPE,
|
PROP_CONTENT_TYPE,
|
||||||
PROP_SEND_BODY,
|
PROP_SEND_BODY,
|
||||||
|
@ -492,6 +485,13 @@ public final class InvokeHTTP extends AbstractProcessor {
|
||||||
|
|
||||||
private final AtomicReference<OkHttpClient> okHttpClientAtomicReference = new AtomicReference<>();
|
private final AtomicReference<OkHttpClient> okHttpClientAtomicReference = new AtomicReference<>();
|
||||||
|
|
||||||
|
protected void init(ProcessorInitializationContext context) {
|
||||||
|
excludedHeaders.put("Trusted Hostname", "HTTP request header '{}' excluded. " +
|
||||||
|
"Update processor to use the SSLContextService instead. " +
|
||||||
|
"See the Access Policies section in the System Administrator's Guide.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
|
protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
|
||||||
return PROPERTIES;
|
return PROPERTIES;
|
||||||
|
@ -573,6 +573,14 @@ public final class InvokeHTTP extends AbstractProcessor {
|
||||||
|
|
||||||
ProxyConfiguration.validateProxySpec(validationContext, results, PROXY_SPECS);
|
ProxyConfiguration.validateProxySpec(validationContext, results, PROXY_SPECS);
|
||||||
|
|
||||||
|
for (String headerKey : validationContext.getProperties().values()) {
|
||||||
|
if (excludedHeaders.containsKey(headerKey)) {
|
||||||
|
// We're not using the header message format string here, just this
|
||||||
|
// static validation message string:
|
||||||
|
results.add(new ValidationResult.Builder().subject(headerKey).valid(false).explanation("Matches excluded HTTP header name").build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,12 +639,6 @@ public final class InvokeHTTP extends AbstractProcessor {
|
||||||
setSslSocketFactory(okHttpClientBuilder, sslService, sslContext, isHttpsProxy);
|
setSslSocketFactory(okHttpClientBuilder, sslService, sslContext, isHttpsProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the trusted hostname property and override the HostnameVerifier
|
|
||||||
String trustedHostname = trimToEmpty(context.getProperty(PROP_TRUSTED_HOSTNAME).getValue());
|
|
||||||
if (!trustedHostname.isEmpty()) {
|
|
||||||
okHttpClientBuilder.hostnameVerifier(new OverrideHostnameVerifier(trustedHostname, OkHostnameVerifier.INSTANCE));
|
|
||||||
}
|
|
||||||
|
|
||||||
setAuthenticator(okHttpClientBuilder, context);
|
setAuthenticator(okHttpClientBuilder, context);
|
||||||
|
|
||||||
useChunked = context.getProperty(PROP_USE_CHUNKED_ENCODING).asBoolean();
|
useChunked = context.getProperty(PROP_USE_CHUNKED_ENCODING).asBoolean();
|
||||||
|
@ -1021,8 +1023,15 @@ public final class InvokeHTTP extends AbstractProcessor {
|
||||||
requestBuilder = requestBuilder.addHeader("Date", DATE_FORMAT.print(System.currentTimeMillis()));
|
requestBuilder = requestBuilder.addHeader("Date", DATE_FORMAT.print(System.currentTimeMillis()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ComponentLog logger = getLogger();
|
||||||
for (String headerKey : dynamicPropertyNames) {
|
for (String headerKey : dynamicPropertyNames) {
|
||||||
String headerValue = context.getProperty(headerKey).evaluateAttributeExpressions(requestFlowFile).getValue();
|
String headerValue = context.getProperty(headerKey).evaluateAttributeExpressions(requestFlowFile).getValue();
|
||||||
|
|
||||||
|
// don't include any of the excluded headers, log instead
|
||||||
|
if (excludedHeaders.containsKey(headerKey)) {
|
||||||
|
logger.warn(excludedHeaders.get(headerKey), new Object[]{headerKey});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
requestBuilder = requestBuilder.addHeader(headerKey, headerValue);
|
requestBuilder = requestBuilder.addHeader(headerKey, headerValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1448,6 +1448,32 @@ public abstract class TestInvokeHttpCommon {
|
||||||
Assert.assertEquals("chunked",header);
|
Assert.assertEquals("chunked",header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrustedHostname() throws Exception {
|
||||||
|
addHandler(new GetOrHeadHandler());
|
||||||
|
|
||||||
|
runner.setProperty(InvokeHTTP.PROP_URL, url + "/status/200");
|
||||||
|
runner.setProperty("Trusted Hostname", "https://example.com/");
|
||||||
|
runner.assertValid();
|
||||||
|
|
||||||
|
runner.setProperty(InvokeHTTP.PROP_METHOD, "GET");
|
||||||
|
runner.setProperty(InvokeHTTP.PROP_OUTPUT_RESPONSE_REGARDLESS,"true");
|
||||||
|
runner.setProperty(InvokeHTTP.PROP_PUT_OUTPUT_IN_ATTRIBUTE,"outputBody");
|
||||||
|
runner.assertValid();
|
||||||
|
|
||||||
|
createFlowFiles(runner);
|
||||||
|
runner.run();
|
||||||
|
|
||||||
|
runner.assertValid();
|
||||||
|
|
||||||
|
runner.assertTransferCount(InvokeHTTP.REL_SUCCESS_REQ, 1);
|
||||||
|
runner.assertTransferCount(InvokeHTTP.REL_RESPONSE, 1);
|
||||||
|
runner.assertTransferCount(InvokeHTTP.REL_RETRY, 0);
|
||||||
|
runner.assertTransferCount(InvokeHTTP.REL_NO_RETRY,0);
|
||||||
|
runner.assertTransferCount(InvokeHTTP.REL_FAILURE, 0);
|
||||||
|
runner.assertPenalizeCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void createFlowFiles(final TestRunner testRunner) throws UnsupportedEncodingException {
|
public static void createFlowFiles(final TestRunner testRunner) throws UnsupportedEncodingException {
|
||||||
final Map<String, String> attributes = new HashMap<>();
|
final Map<String, String> attributes = new HashMap<>();
|
||||||
|
|
Loading…
Reference in New Issue