diff --git a/nifi/Dockerfile b/nifi/Dockerfile index 877f02483..208181a9e 100644 --- a/nifi/Dockerfile +++ b/nifi/Dockerfile @@ -107,8 +107,8 @@ COPY --chown=${STACKABLE_USER_UID}:0 nifi/nifi-iceberg-bundle/stackable/patches/ RUN < +Date: Mon, 17 Feb 2025 17:26:20 +0100 +Subject: no zip assembly + +--- + nifi-assembly/pom.xml | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml +index fa08b8b4af..5db9e3c08f 100644 +--- a/nifi-assembly/pom.xml ++++ b/nifi-assembly/pom.xml +@@ -66,7 +66,6 @@ language governing permissions and limitations under the License. --> + posix + + dir +- zip + + + diff --git a/nifi/stackable/patches/2.7.2/0002-add-cyclonedx-plugin.patch b/nifi/stackable/patches/2.7.2/0002-add-cyclonedx-plugin.patch new file mode 100644 index 000000000..2277ec1dc --- /dev/null +++ b/nifi/stackable/patches/2.7.2/0002-add-cyclonedx-plugin.patch @@ -0,0 +1,38 @@ +From 720ac307ebbf577e01c7b0365582284ede86933a Mon Sep 17 00:00:00 2001 +From: Nick Larsen +Date: Mon, 17 Feb 2025 17:31:17 +0100 +Subject: add cyclonedx plugin + +--- + pom.xml | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/pom.xml b/pom.xml +index e6fa490bc1..e8a6249f53 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -1038,6 +1038,24 @@ + + + ++ ++ org.cyclonedx ++ cyclonedx-maven-plugin ++ 2.8.0 ++ ++ application ++ 1.5 ++ false ++ ++ ++ ++ package ++ ++ makeBom ++ ++ ++ ++ + + + diff --git a/nifi/stackable/patches/2.7.2/0003-disable-host-port-validation-if-list-of-allowed-host.patch b/nifi/stackable/patches/2.7.2/0003-disable-host-port-validation-if-list-of-allowed-host.patch new file mode 100644 index 000000000..bcf46c627 --- /dev/null +++ b/nifi/stackable/patches/2.7.2/0003-disable-host-port-validation-if-list-of-allowed-host.patch @@ -0,0 +1,48 @@ +From b8c61bd2e862eef615b2a4c8c2e4aa7d1756e469 Mon Sep 17 00:00:00 2001 +From: Benedikt Labrenz +Date: Thu, 22 May 2025 14:47:24 +0200 +Subject: disable host port validation if list of allowed hosts only contains + '*' + +--- + .../connector/FrameworkServerConnectorFactory.java | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java +index 1b28722a3f..72986669d5 100644 +--- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java ++++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java +@@ -54,6 +54,8 @@ public class FrameworkServerConnectorFactory extends StandardServerConnectorFact + + private final String excludeCipherSuites; + ++ private final boolean disableHostPortValidator; ++ + private final Set validPorts; + + private SslContextFactory.Server sslContextFactory; +@@ -72,6 +74,11 @@ public class FrameworkServerConnectorFactory extends StandardServerConnectorFact + headerSize = DataUnit.parseDataSize(properties.getWebMaxHeaderSize(), DataUnit.B).intValue(); + validPorts = getValidPorts(properties); + ++ // Check if the property for allowed hosts has only the wildcard entry and ++ // if so store this in disableHostPortValidator for later use ++ List configuredHostNames = properties.getAllowedHostsAsList(); ++ disableHostPortValidator = configuredHostNames.size() == 1 && configuredHostNames.contains("*"); ++ + if (properties.isHTTPSConfigured()) { + if (properties.isClientAuthRequiredForRestApi()) { + setNeedClientAuth(true); +@@ -102,8 +109,10 @@ public class FrameworkServerConnectorFactory extends StandardServerConnectorFact + // Add HostHeaderCustomizer to set Host Header for HTTP/2 and HostHeaderHandler + httpConfiguration.addCustomizer(new HostHeaderCustomizer()); + +- final HostPortValidatorCustomizer hostPortValidatorCustomizer = new HostPortValidatorCustomizer(validPorts); +- httpConfiguration.addCustomizer(hostPortValidatorCustomizer); ++ if (!disableHostPortValidator) { ++ final HostPortValidatorCustomizer hostPortValidatorCustomizer = new HostPortValidatorCustomizer(validPorts); ++ httpConfiguration.addCustomizer(hostPortValidatorCustomizer); ++ } + + return httpConfiguration; + } diff --git a/nifi/stackable/patches/2.7.2/0004-NIFI-14858-Make-SNI-checking-configurable.patch b/nifi/stackable/patches/2.7.2/0004-NIFI-14858-Make-SNI-checking-configurable.patch new file mode 100644 index 000000000..948abe567 --- /dev/null +++ b/nifi/stackable/patches/2.7.2/0004-NIFI-14858-Make-SNI-checking-configurable.patch @@ -0,0 +1,108 @@ +From bad76f4eb8703301b6233d8057e3157305a85e2e Mon Sep 17 00:00:00 2001 +From: Lars Francke +Date: Wed, 13 Aug 2025 14:16:55 +0200 +Subject: NIFI-14858: Make SNI checking configurable + +Introduces two new properties: +- nifi.web.https.sni.required (default: false) +- nifi.web.https.sni.host.check (default: true) + +These defaults mean that SNI is not required (this is the current behavior already) but if SNI is provided then the host has to match. +--- + .../StandardServerConnectorFactory.java | 24 +++++++++++++++++++ + .../org/apache/nifi/util/NiFiProperties.java | 10 ++++++++ + .../FrameworkServerConnectorFactory.java | 4 ++++ + 3 files changed, 38 insertions(+) + +diff --git a/nifi-commons/nifi-jetty-configuration/src/main/java/org/apache/nifi/jetty/configuration/connector/StandardServerConnectorFactory.java b/nifi-commons/nifi-jetty-configuration/src/main/java/org/apache/nifi/jetty/configuration/connector/StandardServerConnectorFactory.java +index 26d09706a1..132973cad5 100644 +--- a/nifi-commons/nifi-jetty-configuration/src/main/java/org/apache/nifi/jetty/configuration/connector/StandardServerConnectorFactory.java ++++ b/nifi-commons/nifi-jetty-configuration/src/main/java/org/apache/nifi/jetty/configuration/connector/StandardServerConnectorFactory.java +@@ -70,6 +70,10 @@ public class StandardServerConnectorFactory implements ServerConnectorFactory { + + private int requestHeaderSize = 8192; + ++ private boolean sniRequired = false; ++ ++ private boolean sniHostCheck = true; ++ + /** + * Standard Server Connector Factory Constructor with required properties + * +@@ -181,6 +185,24 @@ public class StandardServerConnectorFactory implements ServerConnectorFactory { + this.requestHeaderSize = requestHeaderSize; + } + ++ /** ++ * Set to true if a SNI certificate is required, else requests will be rejected with 400 response. ++ * ++ * @param sniRequired SNI Required status ++ */ ++ public void setSniRequired(final boolean sniRequired) { ++ this.sniRequired = sniRequired; ++ } ++ ++ /** ++ * Set to true if the SNI Host name must match when there is an SNI certificate. ++ * ++ * @param sniHostCheck SNI Host Check status ++ */ ++ public void setSniHostCheck(final boolean sniHostCheck) { ++ this.sniHostCheck = sniHostCheck; ++ } ++ + protected Server getServer() { + return server; + } +@@ -195,6 +217,8 @@ public class StandardServerConnectorFactory implements ServerConnectorFactory { + httpConfiguration.setSendServerVersion(SEND_SERVER_VERSION); + + final SecureRequestCustomizer secureRequestCustomizer = new SecureRequestCustomizer(); ++ secureRequestCustomizer.setSniRequired(sniRequired); ++ secureRequestCustomizer.setSniHostCheck(sniHostCheck); + httpConfiguration.addCustomizer(secureRequestCustomizer); + } + +diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java +index b9456a98a0..45262a8f4f 100644 +--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java ++++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java +@@ -203,6 +203,8 @@ public class NiFiProperties extends ApplicationProperties { + public static final String WEB_HTTPS_CIPHERSUITES_INCLUDE = "nifi.web.https.ciphersuites.include"; + public static final String WEB_HTTPS_CIPHERSUITES_EXCLUDE = "nifi.web.https.ciphersuites.exclude"; + public static final String WEB_HTTPS_NETWORK_INTERFACE_PREFIX = "nifi.web.https.network.interface."; ++ public static final String WEB_HTTPS_SNI_REQUIRED = "nifi.web.https.sni.required"; ++ public static final String WEB_HTTPS_SNI_HOST_CHECK = "nifi.web.https.sni.host.check"; + public static final String WEB_WORKING_DIR = "nifi.web.jetty.working.directory"; + public static final String WEB_THREADS = "nifi.web.jetty.threads"; + public static final String WEB_MAX_HEADER_SIZE = "nifi.web.max.header.size"; +@@ -706,6 +708,14 @@ public class NiFiProperties extends ApplicationProperties { + return Arrays.stream(protocols.split("\\s+")).collect(Collectors.toSet()); + } + ++ public boolean isWebHttpsSniRequired() { ++ return Boolean.parseBoolean(getProperty(WEB_HTTPS_SNI_REQUIRED, "false")); ++ } ++ ++ public boolean isWebHttpsSniHostCheck() { ++ return Boolean.parseBoolean(getProperty(WEB_HTTPS_SNI_HOST_CHECK, "true")); ++ } ++ + public String getWebMaxHeaderSize() { + return getProperty(WEB_MAX_HEADER_SIZE, DEFAULT_WEB_MAX_HEADER_SIZE); + } +diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java +index 72986669d5..993b23889c 100644 +--- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java ++++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java +@@ -90,6 +90,10 @@ public class FrameworkServerConnectorFactory extends StandardServerConnectorFact + + // Set Transport Layer Security Protocols based on platform configuration + setIncludeSecurityProtocols(TlsPlatform.getPreferredProtocols().toArray(new String[0])); ++ ++ // Set SNI configuration from properties ++ setSniRequired(properties.isWebHttpsSniRequired()); ++ setSniHostCheck(properties.isWebHttpsSniHostCheck()); + } + } + diff --git a/nifi/stackable/patches/2.7.2/0005-replace-process-groups-root-with-root-ID.patch b/nifi/stackable/patches/2.7.2/0005-replace-process-groups-root-with-root-ID.patch new file mode 100644 index 000000000..0089b6fff --- /dev/null +++ b/nifi/stackable/patches/2.7.2/0005-replace-process-groups-root-with-root-ID.patch @@ -0,0 +1,212 @@ +From 7821ce72d3ee572955828f90a96b8107a961b4c3 Mon Sep 17 00:00:00 2001 +From: Andrew Kenworthy +Date: Fri, 23 Jan 2026 12:41:58 +0100 +Subject: replace process groups root with root ID + +--- + .../org/apache/nifi/util/NiFiProperties.java | 3 ++ + .../nifi/flow/FlowInitializationCallback.java | 11 ++++ + .../FileAccessPolicyProvider.java | 53 +++++++++++++++++++ + .../FileAuthorizerInitializer.java | 25 +++++++++ + .../nifi/controller/StandardFlowService.java | 17 ++++++ + 5 files changed, 109 insertions(+) + create mode 100644 nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java + create mode 100644 nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java + +diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java +index 45262a8f4f..e86f29b569 100644 +--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java ++++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java +@@ -332,6 +332,9 @@ public class NiFiProperties extends ApplicationProperties { + // performance tracking defaults + public static final int DEFAULT_TRACK_PERFORMANCE_PERCENTAGE = 0; + ++ // root process group replacement ++ public static final String ROOT_PROCESS_GROUP_PLACEHOLDER ="nifi.process.group.root.placeholder"; ++ + // defaults + public static final Boolean DEFAULT_AUTO_RESUME_STATE = true; + public static final String DEFAULT_AUTHORIZER_CONFIGURATION_FILE = "conf/authorizers.xml"; +diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java +new file mode 100644 +index 0000000000..7f81967537 +--- /dev/null ++++ b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java +@@ -0,0 +1,11 @@ ++package org.apache.nifi.flow; ++ ++/** ++ * Simple callback interface invoked when the root process group has been ++ * loaded and the flow is fully initialized for the first time. ++ */ ++public interface FlowInitializationCallback { ++ void onRootGroupLoaded(); ++} ++ ++ +diff --git a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java +index 3d271dd394..f153cea1ae 100644 +--- a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java ++++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java +@@ -16,6 +16,7 @@ + */ + package org.apache.nifi.authorization; + ++import jakarta.xml.bind.JAXBException; + import org.apache.commons.lang3.StringUtils; + import org.apache.nifi.authorization.annotation.AuthorizerContext; + import org.apache.nifi.authorization.exception.AuthorizationAccessException; +@@ -26,6 +27,7 @@ import org.apache.nifi.authorization.resource.ResourceType; + import org.apache.nifi.authorization.util.IdentityMapping; + import org.apache.nifi.authorization.util.IdentityMappingUtil; + import org.apache.nifi.components.PropertyValue; ++import org.apache.nifi.controller.StandardFlowService; + import org.apache.nifi.util.FlowInfo; + import org.apache.nifi.util.FlowParser; + import org.apache.nifi.util.NiFiProperties; +@@ -58,6 +60,8 @@ import java.util.concurrent.atomic.AtomicReference; + import java.util.regex.Matcher; + import java.util.regex.Pattern; + ++import static org.apache.nifi.util.NiFiProperties.ROOT_PROCESS_GROUP_PLACEHOLDER; ++ + import static org.apache.nifi.authorization.RequestAction.READ; + import static org.apache.nifi.authorization.RequestAction.WRITE; + +@@ -92,6 +96,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide + @Override + public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException { + userGroupProviderLookup = initializationContext.getUserGroupProviderLookup(); ++ ++ // Register flow initialization hook ++ StandardFlowService.registerInitializationCallback(new FileAuthorizerInitializer(this)); + } + + @Override +@@ -588,6 +595,52 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide + } + } + ++ /** ++ * Replaces process group root references with the process group ID. ++ * Relevant when a static authorizations file is provided, which can ++ * then use "root" as a placeholder. ++ */ ++ public void replaceWithRootGroupId() throws JAXBException { ++ String placeholder = this.properties.getProperty(ROOT_PROCESS_GROUP_PLACEHOLDER, ""); ++ ++ if (StringUtils.isNotBlank(placeholder)) { ++ if (rootGroupId == null) { ++ logger.info("Parsing flow as rootGroupId is not yet defined"); ++ parseFlow(); ++ } ++ if (rootGroupId != null) { ++ logger.info("Parsing root group with {}", rootGroupId); ++ ++ final AuthorizationsHolder holder = authorizationsHolder.get(); ++ final List currentPolicies = holder.getPolicies(); ++ final ListIterator accessPolicies = currentPolicies.listIterator(); ++ ++ boolean authorizationsChanged = false; ++ ++ while (accessPolicies.hasNext()) { ++ final AccessPolicy accessPolicy = accessPolicies.next(); ++ String resource = accessPolicy.getResource(); ++ String processGroupRoot = ResourceType.ProcessGroup.getValue() + "/" + placeholder; ++ if (resource.endsWith(processGroupRoot)) { ++ int pos = resource.indexOf(processGroupRoot); ++ accessPolicies.remove(); ++ final AccessPolicy updatedPolicy = new AccessPolicy.Builder(accessPolicy).resource(resource.substring(0, pos) + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId).build(); ++ accessPolicies.add(updatedPolicy); ++ authorizationsChanged = true; ++ } ++ } ++ ++ if (authorizationsChanged) { ++ saveAndRefreshHolder(currentPolicies); ++ } ++ } else { ++ // this is not expected as this is called from the flow service ++ // once it has been configured ++ logger.info("rootGroupId still not established!"); ++ } ++ } ++ } ++ + /** + * Creates and adds an access policy for the given resource, identity, and actions to the specified authorizations. + * +diff --git a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java +new file mode 100644 +index 0000000000..f67328ef84 +--- /dev/null ++++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java +@@ -0,0 +1,25 @@ ++package org.apache.nifi.authorization; ++ ++import org.apache.nifi.flow.FlowInitializationCallback; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; ++ ++ ++public class FileAuthorizerInitializer implements FlowInitializationCallback { ++ private static final Logger logger = LoggerFactory.getLogger(FileAuthorizerInitializer.class); ++private FileAccessPolicyProvider fileAccessPolicyProvider; ++ ++ public FileAuthorizerInitializer(FileAccessPolicyProvider fileAccessPolicyProvider) { ++ this.fileAccessPolicyProvider = fileAccessPolicyProvider; ++ } ++ ++ @Override ++ public void onRootGroupLoaded() { ++ try { ++ logger.info("Flow initialized; ensuring root group ID is recorded in authorizations.xml"); ++ this.fileAccessPolicyProvider.replaceWithRootGroupId(); ++ } catch (Exception e) { ++ logger.warn("Unable to update authorizations.xml with root group ID", e); ++ } ++ } ++} +\ No newline at end of file +diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java +index 5de3486164..2873b26644 100644 +--- a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java ++++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java +@@ -55,6 +55,7 @@ import org.apache.nifi.controller.serialization.FlowSynchronizationException; + import org.apache.nifi.controller.status.ProcessGroupStatus; + import org.apache.nifi.engine.FlowEngine; + import org.apache.nifi.events.BulletinFactory; ++import org.apache.nifi.flow.FlowInitializationCallback; + import org.apache.nifi.groups.BundleUpdateStrategy; + import org.apache.nifi.groups.ProcessGroup; + import org.apache.nifi.groups.RemoteProcessGroup; +@@ -148,6 +149,13 @@ public class StandardFlowService implements FlowService, ProtocolHandler { + private static final String CONNECTION_EXCEPTION_MSG_PREFIX = "Failed to connect node to cluster"; + private static final Logger logger = LoggerFactory.getLogger(StandardFlowService.class); + ++ // Static callback registration for post-initialization hooks ++ private static volatile FlowInitializationCallback initializationCallback; ++ ++ public static void registerInitializationCallback(FlowInitializationCallback callback) { ++ initializationCallback = callback; ++ } ++ + public static StandardFlowService createStandaloneInstance( + final FlowController controller, + final NiFiProperties nifiProperties, +@@ -935,6 +943,15 @@ public class StandardFlowService implements FlowService, ProtocolHandler { + // start the processors as indicated by the dataflow + controller.onFlowInitialized(autoResumeState); + ++ // this should be done once the flow has been initialized ++ if (initializationCallback != null) { ++ try { ++ initializationCallback.onRootGroupLoaded(); ++ } catch (Exception e) { ++ logger.warn("Error invoking FlowInitializationCallback", e); ++ } ++ } ++ + loadSnippets(dataFlow.getSnippets()); + + controller.startHeartbeating(); diff --git a/nifi/stackable/patches/2.7.2/0006-NIFI-15524-Added-Endpoint-URL-and-Path-Style-Access-.patch b/nifi/stackable/patches/2.7.2/0006-NIFI-15524-Added-Endpoint-URL-and-Path-Style-Access-.patch new file mode 100644 index 000000000..729c932b6 --- /dev/null +++ b/nifi/stackable/patches/2.7.2/0006-NIFI-15524-Added-Endpoint-URL-and-Path-Style-Access-.patch @@ -0,0 +1,66 @@ +From 45651d4c698dee673a2f55536691467a304bcea5 Mon Sep 17 00:00:00 2001 +From: Sebastian Bernauer +Date: Mon, 2 Feb 2026 08:42:38 +0100 +Subject: NIFI-15524 Added Endpoint URL and Path Style Access to S3 FileIO + Iceberg Provider (#10825) + +Signed-off-by: David Handermann +--- + .../iceberg/aws/S3IcebergFileIOProvider.java | 32 ++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +diff --git a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-aws/src/main/java/org/apache/nifi/services/iceberg/aws/S3IcebergFileIOProvider.java b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-aws/src/main/java/org/apache/nifi/services/iceberg/aws/S3IcebergFileIOProvider.java +index 6581993c22..58feed8518 100644 +--- a/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-aws/src/main/java/org/apache/nifi/services/iceberg/aws/S3IcebergFileIOProvider.java ++++ b/nifi-extension-bundles/nifi-iceberg-bundle/nifi-iceberg-aws/src/main/java/org/apache/nifi/services/iceberg/aws/S3IcebergFileIOProvider.java +@@ -102,12 +102,35 @@ public class S3IcebergFileIOProvider extends AbstractControllerService implement + ) + .build(); + ++ static final PropertyDescriptor ENDPOINT_URL = new PropertyDescriptor.Builder() ++ .name("Endpoint URL") ++ .description(""" ++ Endpoint URL to use instead of the AWS default including scheme, host, port, and path. ++ The AWS libraries select an endpoint URL based on the AWS region, but this property overrides ++ the selected endpoint URL, allowing use with other S3-compatible endpoints.""") ++ .required(false) ++ .addValidator(StandardValidators.URL_VALIDATOR) ++ .build(); ++ ++ static final PropertyDescriptor PATH_STYLE_ACCESS = new PropertyDescriptor.Builder() ++ .name("Path Style Access") ++ .description(""" ++ Path-style access can be enforced by setting this property to true. Set it to true if the configured ++ endpoint does not support virtual-hosted-style requests, only path-style requests.""") ++ .allowableValues(Boolean.TRUE.toString(), Boolean.FALSE.toString()) ++ .defaultValue(String.valueOf(S3FileIOProperties.PATH_STYLE_ACCESS_DEFAULT)) ++ .required(true) ++ .addValidator(StandardValidators.BOOLEAN_VALIDATOR) ++ .build(); ++ + private static final List PROPERTY_DESCRIPTORS = List.of( + AUTHENTICATION_STRATEGY, + ACCESS_KEY_ID, + SECRET_ACCESS_KEY, + SESSION_TOKEN, +- CLIENT_REGION ++ CLIENT_REGION, ++ ENDPOINT_URL, ++ PATH_STYLE_ACCESS + ); + + private final Map standardProperties = new ConcurrentHashMap<>(); +@@ -159,6 +182,13 @@ public class S3IcebergFileIOProvider extends AbstractControllerService implement + } + } + ++ if (context.getProperty(ENDPOINT_URL).isSet()) { ++ final String endpoint = context.getProperty(ENDPOINT_URL).getValue(); ++ contextProperties.put(S3FileIOProperties.ENDPOINT, endpoint); ++ } ++ final String pathStyleAccess = context.getProperty(PATH_STYLE_ACCESS).getValue(); ++ contextProperties.put(S3FileIOProperties.PATH_STYLE_ACCESS, pathStyleAccess); ++ + // HttpURLConnection Client Type avoids additional dependencies + contextProperties.put(HttpClientProperties.CLIENT_TYPE, HttpClientProperties.CLIENT_TYPE_URLCONNECTION); + diff --git a/nifi/stackable/patches/2.7.2/patchable.toml b/nifi/stackable/patches/2.7.2/patchable.toml new file mode 100644 index 000000000..6f7c72d11 --- /dev/null +++ b/nifi/stackable/patches/2.7.2/patchable.toml @@ -0,0 +1,2 @@ +mirror = "https://github.com/stackabletech/nifi.git" +base = "098c97460988449ef4fba5508a83b20cc65ce9ab" diff --git a/shared/logback/boil-config.toml b/shared/logback/boil-config.toml index ab980a5ec..8a5a32242 100644 --- a/shared/logback/boil-config.toml +++ b/shared/logback/boil-config.toml @@ -9,3 +9,6 @@ java-devel = "21" [versions."1.5.18".local-images] java-devel = "21" + +[versions."1.5.24".local-images] +java-devel = "21" diff --git a/shared/logback/stackable/patches/1.5.24/patchable.toml b/shared/logback/stackable/patches/1.5.24/patchable.toml new file mode 100644 index 000000000..451b1877f --- /dev/null +++ b/shared/logback/stackable/patches/1.5.24/patchable.toml @@ -0,0 +1,2 @@ +mirror = "https://github.com/stackabletech/logback.git" +base = "62bc5fc245dd3a52f3dd45e232733f4cefb4806d"