This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new a85ef2c1f4 NIFI-11536 Corrected Keystore and Truststore auto-reloading
a85ef2c1f4 is described below
commit a85ef2c1f49780be93b49ec6cb077a61c8cc063e
Author: Emilio Setiadarma <[email protected]>
AuthorDate: Mon Jun 26 18:00:06 2023 -0700
NIFI-11536 Corrected Keystore and Truststore auto-reloading
- Replaced Jetty KeyStoreScanner and custom TrustStoreScanner with shared
StoreScanner
- New StoreScanner uses TLS Configuration to reload SSLContext instead of
relying on Jetty SslContextFactory properties
This closes #7446
Signed-off-by: David Handermann <[email protected]>
---
.../connector/FrameworkServerConnectorFactory.java | 7 +-
.../apache/nifi/web/server/util/StoreScanner.java | 158 +++++++++++++++++++++
.../nifi/web/server/util/TrustStoreScanner.java | 151 --------------------
.../FrameworkServerConnectorFactoryTest.java | 11 +-
.../nifi/web/server/util/StoreScannerTest.java | 143 +++++++++++++++++++
.../web/server/util/TrustStoreScannerTest.java | 85 -----------
6 files changed, 308 insertions(+), 247 deletions(-)
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
index c434010f3d..829a5578f6 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
@@ -27,10 +27,9 @@ import org.apache.nifi.security.util.TlsException;
import org.apache.nifi.security.util.TlsPlatform;
import org.apache.nifi.util.FormatUtils;
import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.server.util.TrustStoreScanner;
+import org.apache.nifi.web.server.util.StoreScanner;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.util.ssl.KeyStoreScanner;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import javax.net.ssl.SSLContext;
@@ -149,12 +148,12 @@ public class FrameworkServerConnectorFactory extends
StandardServerConnectorFact
if (storeScanInterval != null) {
sslContextFactory.setKeyStorePath(tlsConfiguration.getKeystorePath());
- final KeyStoreScanner keyStoreScanner = new
KeyStoreScanner(sslContextFactory);
+ final StoreScanner keyStoreScanner = new
StoreScanner(sslContextFactory, tlsConfiguration,
sslContextFactory.getKeyStoreResource());
keyStoreScanner.setScanInterval(storeScanInterval);
getServer().addBean(keyStoreScanner);
sslContextFactory.setTrustStorePath(tlsConfiguration.getTruststorePath());
- final TrustStoreScanner trustStoreScanner = new
TrustStoreScanner(sslContextFactory);
+ final StoreScanner trustStoreScanner = new
StoreScanner(sslContextFactory, tlsConfiguration,
sslContextFactory.getTrustStoreResource());
trustStoreScanner.setScanInterval(storeScanInterval);
getServer().addBean(trustStoreScanner);
}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/StoreScanner.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/StoreScanner.java
new file mode 100644
index 0000000000..daf7c02db4
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/StoreScanner.java
@@ -0,0 +1,158 @@
+/*
+ * 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.web.server.util;
+
+import org.apache.nifi.security.util.TlsConfiguration;
+import org.apache.nifi.security.util.TlsException;
+import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedOperation;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.apache.nifi.security.util.SslContextFactory.createSslContext;
+
+/**
+ * File Scanner for Keystore or Truststore reloading using provided TLS
Configuration
+ */
+public class StoreScanner extends ContainerLifeCycle implements
Scanner.DiscreteListener {
+ private static final Logger LOG = Log.getLogger(StoreScanner.class);
+
+ private final SslContextFactory sslContextFactory;
+ private final TlsConfiguration tlsConfiguration;
+ private final File file;
+ private final Scanner scanner;
+ private final String resourceName;
+
+ public StoreScanner(final SslContextFactory sslContextFactory,
+ final TlsConfiguration tlsConfiguration,
+ final Resource resource) {
+ this.sslContextFactory = sslContextFactory;
+ this.tlsConfiguration = tlsConfiguration;
+ this.resourceName = resource.getName();
+ try {
+ File monitoredFile = resource.getFile();
+ if (monitoredFile == null || !monitoredFile.exists()) {
+ throw new IllegalArgumentException(String.format("%s file does
not exist", resourceName));
+ }
+ if (monitoredFile.isDirectory()) {
+ throw new IllegalArgumentException(String.format("expected %s
file not directory", resourceName));
+ }
+
+ if (resource.getAlias() != null) {
+ // this resource has an alias, use the alias, as that's what's
returned in the Scanner
+ monitoredFile = new File(resource.getAlias());
+ }
+
+ file = monitoredFile;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("File monitoring started {} [{}]", resourceName,
monitoredFile);
+ }
+ } catch (final IOException e) {
+ throw new IllegalArgumentException(String.format("could not obtain
%s file", resourceName), e);
+ }
+
+ File parentFile = file.getParentFile();
+ if (!parentFile.exists() || !parentFile.isDirectory()) {
+ throw new IllegalArgumentException(String.format("error obtaining
%s dir", resourceName));
+ }
+
+ scanner = new Scanner();
+ scanner.setScanDirs(Collections.singletonList(parentFile));
+ scanner.setScanInterval(1);
+ scanner.setReportDirs(false);
+ scanner.setReportExistingFilesOnStartup(false);
+ scanner.setScanDepth(1);
+ scanner.addListener(this);
+ addBean(scanner);
+ }
+
+ @Override
+ public void fileAdded(final String filename) {
+ LOG.debug("Resource [{}] File [{}] added", resourceName, filename);
+ reloadMatched(filename);
+ }
+
+ @Override
+ public void fileChanged(final String filename) {
+ LOG.debug("Resource [{}] File [{}] changed", resourceName, filename);
+ reloadMatched(filename);
+ }
+
+ @Override
+ public void fileRemoved(final String filename) {
+ LOG.debug("Resource [{}] File [{}] removed", resourceName, filename);
+ reloadMatched(filename);
+ }
+
+ @ManagedOperation(
+ value = "Scan for changes in the SSL Keystore/Truststore",
+ impact = "ACTION"
+ )
+ public void scan() {
+ LOG.debug("Resource [{}] scanning started", resourceName);
+
+ this.scanner.scan();
+ this.scanner.scan();
+ }
+
+ @ManagedOperation(
+ value = "Reload the SSL Keystore/Truststore",
+ impact = "ACTION"
+ )
+ public void reload() {
+ LOG.debug("File [{}] reload started", file);
+
+ try {
+ this.sslContextFactory.reload(contextFactory ->
contextFactory.setSslContext(createContext()));
+ LOG.info("File [{}] reload completed", file);
+ } catch (final Throwable t) {
+ LOG.warn("File [{}] reload failed", file, t);
+ }
+ }
+
+ @ManagedAttribute("scanning interval to detect changes which need
reloaded")
+ public int getScanInterval() {
+ return this.scanner.getScanInterval();
+ }
+
+ public void setScanInterval(int scanInterval) {
+ this.scanner.setScanInterval(scanInterval);
+ }
+
+ private void reloadMatched(final String filename) {
+ if (file.toPath().toString().equals(filename)) {
+ reload();
+ }
+ }
+
+ private SSLContext createContext() {
+ try {
+ return createSslContext(tlsConfiguration);
+ } catch (final TlsException e) {
+ throw new IllegalArgumentException("Failed to create SSL context
with the TLS configuration", e);
+ }
+ }
+}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/TrustStoreScanner.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/TrustStoreScanner.java
deleted file mode 100644
index 22913ed811..0000000000
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/TrustStoreScanner.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.web.server.util;
-
-import org.eclipse.jetty.util.Scanner;
-import org.eclipse.jetty.util.annotation.ManagedAttribute;
-import org.eclipse.jetty.util.annotation.ManagedOperation;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-
-/**
- * <p>The {@link TrustStoreScanner} is used to monitor the TrustStore file
used by the {@link SslContextFactory}.
- * It will reload the {@link SslContextFactory} if it detects that the
TrustStore file has been modified.</p>
- * <p>
- * Though it would have been more ideal to simply extend KeyStoreScanner and
override the keystore resource
- * with the truststore resource, KeyStoreScanner's constructor was written in
a way that doesn't make this possible.
- */
-public class TrustStoreScanner extends ContainerLifeCycle implements
Scanner.DiscreteListener {
- private static final Logger LOG = Log.getLogger(TrustStoreScanner.class);
-
- private final SslContextFactory sslContextFactory;
- private final File truststoreFile;
- private final Scanner _scanner;
-
- public TrustStoreScanner(SslContextFactory sslContextFactory) {
- this.sslContextFactory = sslContextFactory;
- try {
- Resource truststoreResource =
sslContextFactory.getTrustStoreResource();
- File monitoredFile = truststoreResource.getFile();
- if (monitoredFile == null || !monitoredFile.exists()) {
- throw new IllegalArgumentException("truststore file does not
exist");
- }
- if (monitoredFile.isDirectory()) {
- throw new IllegalArgumentException("expected truststore file
not directory");
- }
-
- if (truststoreResource.getAlias() != null) {
- // this resource has an alias, use the alias, as that's what's
returned in the Scanner
- monitoredFile = new File(truststoreResource.getAlias());
- }
-
- truststoreFile = monitoredFile;
- if (LOG.isDebugEnabled()) {
- LOG.debug("Monitored Truststore File: {}", monitoredFile);
- }
- } catch (IOException e) {
- throw new IllegalArgumentException("could not obtain truststore
file", e);
- }
-
- File parentFile = truststoreFile.getParentFile();
- if (!parentFile.exists() || !parentFile.isDirectory()) {
- throw new IllegalArgumentException("error obtaining truststore
dir");
- }
-
- _scanner = new Scanner();
- _scanner.setScanDirs(Collections.singletonList(parentFile));
- _scanner.setScanInterval(1);
- _scanner.setReportDirs(false);
- _scanner.setReportExistingFilesOnStartup(false);
- _scanner.setScanDepth(1);
- _scanner.addListener(this);
- addBean(_scanner);
- }
-
- @Override
- public void fileAdded(String filename) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("added {}", filename);
- }
-
- if (truststoreFile.toPath().toString().equals(filename)) {
- reload();
- }
- }
-
- @Override
- public void fileChanged(String filename) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("changed {}", filename);
- }
-
- if (truststoreFile.toPath().toString().equals(filename)) {
- reload();
- }
- }
-
- @Override
- public void fileRemoved(String filename) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("removed {}", filename);
- }
-
- if (truststoreFile.toPath().toString().equals(filename)) {
- reload();
- }
- }
-
- @ManagedOperation(value = "Scan for changes in the SSL Truststore", impact
= "ACTION")
- public void scan() {
- if (LOG.isDebugEnabled()) {
- LOG.debug("scanning");
- }
-
- _scanner.scan();
- _scanner.scan();
- }
-
- @ManagedOperation(value = "Reload the SSL Truststore", impact = "ACTION")
- public void reload() {
- if (LOG.isDebugEnabled()) {
- LOG.debug("reloading truststore file {}", truststoreFile);
- }
-
- try {
- sslContextFactory.reload(scf -> {
- });
- } catch (Throwable t) {
- LOG.warn("Truststore Reload Failed", t);
- }
- }
-
- @ManagedAttribute("scanning interval to detect changes which need
reloaded")
- public int getScanInterval() {
- return _scanner.getScanInterval();
- }
-
- public void setScanInterval(int scanInterval) {
- _scanner.setScanInterval(scanInterval);
- }
-}
\ No newline at end of file
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
index e997f25ac6..f4119f76aa 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
@@ -20,17 +20,17 @@ import
org.apache.nifi.jetty.configuration.connector.alpn.ALPNServerConnectionFa
import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
import org.apache.nifi.security.util.TlsConfiguration;
import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.server.util.TrustStoreScanner;
+import org.apache.nifi.web.server.util.StoreScanner;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.util.ssl.KeyStoreScanner;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import java.util.Collection;
import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -182,11 +182,8 @@ class FrameworkServerConnectorFactoryTest {
private void assertAutoReloadEnabled(final ServerConnector
serverConnector) {
final Server server = serverConnector.getServer();
- final KeyStoreScanner keyStoreScanner =
server.getBean(KeyStoreScanner.class);
- assertNotNull(keyStoreScanner);
-
- final TrustStoreScanner trustStoreScanner =
server.getBean(TrustStoreScanner.class);
- assertNotNull(trustStoreScanner);
+ final Collection<StoreScanner> scanners =
server.getBeans(StoreScanner.class);
+ assertEquals(2, scanners.size());
}
private NiFiProperties getProperties(final Properties serverProperties) {
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/StoreScannerTest.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/StoreScannerTest.java
new file mode 100644
index 0000000000..35c971c144
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/StoreScannerTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.web.server.util;
+
+import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
+import org.apache.nifi.security.util.TlsConfiguration;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class StoreScannerTest {
+ private SslContextFactory sslContextFactory;
+ private static TlsConfiguration tlsConfiguration;
+ private static File keyStoreFile;
+ private static File trustStoreFile;
+ private static Map<File, StoreScanner> filesToScannerMap;
+
+ @Captor
+ private ArgumentCaptor<Consumer<SslContextFactory>> consumerArgumentCaptor;
+
+ @BeforeAll
+ public static void initClass() {
+ tlsConfiguration = new TemporaryKeyStoreBuilder().build();
+ keyStoreFile = Paths.get(tlsConfiguration.getKeystorePath()).toFile();
+ trustStoreFile =
Paths.get(tlsConfiguration.getTruststorePath()).toFile();
+ }
+
+ @BeforeEach
+ public void init() throws IOException {
+ sslContextFactory = mock(SslContextFactory.class);
+ Resource keyStoreResource = mock(Resource.class);
+ when(keyStoreResource.getFile()).thenReturn(keyStoreFile);
+
when(sslContextFactory.getKeyStoreResource()).thenReturn(keyStoreResource);
+
+ Resource trustStoreResource = mock(Resource.class);
+ when(trustStoreResource.getFile()).thenReturn(trustStoreFile);
+
when(sslContextFactory.getTrustStoreResource()).thenReturn(trustStoreResource);
+
+ final StoreScanner keyStoreScanner = new
StoreScanner(sslContextFactory, tlsConfiguration,
sslContextFactory.getKeyStoreResource());
+ final StoreScanner trustStoreScanner = new
StoreScanner(sslContextFactory, tlsConfiguration,
sslContextFactory.getTrustStoreResource());
+ filesToScannerMap = new HashMap<>();
+ filesToScannerMap.put(keyStoreFile, keyStoreScanner);
+ filesToScannerMap.put(trustStoreFile, trustStoreScanner);
+ }
+
+ @Test
+ public void testFileAdded() throws Exception {
+ for (final Map.Entry<File, StoreScanner> entry :
filesToScannerMap.entrySet()) {
+ final File file = entry.getKey();
+ final StoreScanner scanner = entry.getValue();
+ scanner.fileAdded(file.getAbsolutePath());
+
+ verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+ final Consumer<SslContextFactory> consumer =
consumerArgumentCaptor.getValue();
+ consumer.accept(sslContextFactory);
+
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+ clearInvocations(sslContextFactory);
+ }
+ }
+
+ @Test
+ public void testFileChanged() throws Exception {
+ for (final Map.Entry<File, StoreScanner> entry :
filesToScannerMap.entrySet()) {
+ final File file = entry.getKey();
+ final StoreScanner scanner = entry.getValue();
+ scanner.fileChanged(file.getAbsolutePath());
+
+ verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+ final Consumer<SslContextFactory> consumer =
consumerArgumentCaptor.getValue();
+ consumer.accept(sslContextFactory);
+
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+ clearInvocations(sslContextFactory);
+ }
+ }
+
+ @Test
+ public void testFileRemoved() throws Exception {
+ for (final Map.Entry<File, StoreScanner> entry :
filesToScannerMap.entrySet()) {
+ final File file = entry.getKey();
+ final StoreScanner scanner = entry.getValue();
+ scanner.fileRemoved(file.getAbsolutePath());
+
+ verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+ final Consumer<SslContextFactory> consumer =
consumerArgumentCaptor.getValue();
+ consumer.accept(sslContextFactory);
+
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+ clearInvocations(sslContextFactory);
+ }
+ }
+
+ @Test
+ public void testReload() throws Exception {
+ for (final Map.Entry<File, StoreScanner> entry :
filesToScannerMap.entrySet()) {
+ final StoreScanner scanner = entry.getValue();
+ scanner.reload();
+
+ verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+ final Consumer<SslContextFactory> consumer =
consumerArgumentCaptor.getValue();
+ consumer.accept(sslContextFactory);
+
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+ clearInvocations(sslContextFactory);
+ }
+ }
+}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/TrustStoreScannerTest.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/TrustStoreScannerTest.java
deleted file mode 100644
index e5ee7df072..0000000000
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/TrustStoreScannerTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.web.server.util;
-
-import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
-import org.apache.nifi.security.util.TlsConfiguration;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mockito;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.function.Consumer;
-
-public class TrustStoreScannerTest {
-
- private TrustStoreScanner scanner;
- private SslContextFactory sslContextFactory;
- private static File keyStoreFile;
- private static File trustStoreFile;
-
- @BeforeAll
- public static void initClass() {
- TlsConfiguration tlsConfiguration = new
TemporaryKeyStoreBuilder().build();
- keyStoreFile = Paths.get(tlsConfiguration.getKeystorePath()).toFile();
- trustStoreFile =
Paths.get(tlsConfiguration.getTruststorePath()).toFile();
- }
-
- @BeforeEach
- public void init() throws IOException {
- sslContextFactory = Mockito.mock(SslContextFactory.class);
- Resource trustStoreResource = Mockito.mock(Resource.class);
- Mockito.when(trustStoreResource.getFile()).thenReturn(trustStoreFile);
-
Mockito.when(sslContextFactory.getTrustStoreResource()).thenReturn(trustStoreResource);
-
- scanner = new TrustStoreScanner(sslContextFactory);
- }
-
- @Test
- public void fileAdded() throws Exception {
- scanner.fileAdded(trustStoreFile.getAbsolutePath());
-
-
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
- }
-
- @Test
- public void fileChanged() throws Exception {
- scanner.fileChanged(trustStoreFile.getAbsolutePath());
-
-
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
- }
-
- @Test
- public void fileRemoved() throws Exception {
- scanner.fileRemoved(trustStoreFile.getAbsolutePath());
-
-
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
- }
-
- @Test
- public void reload() throws Exception {
- scanner.reload();
-
-
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
- }
-}