This is an automated email from the ASF dual-hosted git repository.

szaszm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit 4b6a0aff7fb356cb6b4a68b76a1226bdfccb2a42
Author: Gabor Gyimesi <[email protected]>
AuthorDate: Wed Apr 20 17:54:23 2022 +0200

    MINIFICPP-1794 Remove sensitive properties from agent manifest
    
    Closes #1296
    Signed-off-by: Marton Szasz <[email protected]>
---
 encrypt-config/ConfigFile.cpp                      | 39 ++----------------
 encrypt-config/ConfigFile.h                        |  3 --
 encrypt-config/tests/ConfigFileTests.cpp           | 44 --------------------
 .../tests/C2DescribeCoreComponentStateTest.cpp     | 17 +++++---
 .../http-curl/tests/C2DescribeManifestTest.cpp     | 18 +++++++--
 extensions/http-curl/tests/C2JstackTest.cpp        | 13 +-----
 extensions/http-curl/tests/HTTPHandlers.h          |  6 +++
 extensions/http-curl/tests/HTTPIntegrationBase.h   | 13 ++++--
 .../tests/unit/ConfigurationTests.cpp              | 47 ++++++++++++++++++++++
 libminifi/include/core/Property.h                  |  3 +-
 libminifi/include/properties/Configuration.h       |  7 +++-
 libminifi/src/Configuration.cpp                    | 32 +++++++++++++++
 .../src/core/state/nodes/SupportedOperations.cpp   | 10 +++--
 13 files changed, 140 insertions(+), 112 deletions(-)

diff --git a/encrypt-config/ConfigFile.cpp b/encrypt-config/ConfigFile.cpp
index 9b01746cf..d4abed332 100644
--- a/encrypt-config/ConfigFile.cpp
+++ b/encrypt-config/ConfigFile.cpp
@@ -25,24 +25,10 @@
 #include "utils/StringUtils.h"
 #include "properties/Configuration.h"
 
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace encrypt_config {
-
-constexpr std::array<const char*, 2> 
DEFAULT_SENSITIVE_PROPERTIES{Configuration::nifi_security_client_pass_phrase,
-                                                                  
Configuration::nifi_rest_api_password};
-constexpr const char* ADDITIONAL_SENSITIVE_PROPS_PROPERTY_NAME = 
Configuration::nifi_sensitive_props_additional_keys;
+namespace org::apache::nifi::minifi::encrypt_config {
 
 std::vector<std::string> ConfigFile::getSensitiveProperties() const {
-  std::vector<std::string> 
sensitive_properties(DEFAULT_SENSITIVE_PROPERTIES.begin(), 
DEFAULT_SENSITIVE_PROPERTIES.end());
-  const std::optional<std::string> additional_sensitive_props_list = 
getValue(ADDITIONAL_SENSITIVE_PROPS_PROPERTY_NAME);
-  if (additional_sensitive_props_list) {
-    std::vector<std::string> additional_sensitive_properties = 
utils::StringUtils::split(*additional_sensitive_props_list, ",");
-    sensitive_properties = mergeProperties(sensitive_properties, 
additional_sensitive_properties);
-  }
-
+  auto sensitive_properties = 
Configuration::getSensitiveProperties([this](const std::string& 
sensitive_props) { return getValue(sensitive_props); });
   const auto not_found = [this](const std::string& property_name) { return 
!hasValue(property_name); };
   const auto new_end = std::remove_if(sensitive_properties.begin(), 
sensitive_properties.end(), not_found);
   sensitive_properties.erase(new_end, sensitive_properties.end());
@@ -50,23 +36,4 @@ std::vector<std::string> 
ConfigFile::getSensitiveProperties() const {
   return sensitive_properties;
 }
 
-std::vector<std::string> ConfigFile::mergeProperties(std::vector<std::string> 
properties,
-                                                     const 
std::vector<std::string>& additional_properties) {
-  for (const auto& property_name : additional_properties) {
-    std::string property_name_trimmed = 
utils::StringUtils::trim(property_name);
-    if (!property_name_trimmed.empty()) {
-      properties.push_back(std::move(property_name_trimmed));
-    }
-  }
-
-  std::sort(properties.begin(), properties.end());
-  auto new_end = std::unique(properties.begin(), properties.end());
-  properties.erase(new_end, properties.end());
-  return properties;
-}
-
-}  // namespace encrypt_config
-}  // namespace minifi
-}  // namespace nifi
-}  // namespace apache
-}  // namespace org
+}  // namespace org::apache::nifi::minifi::encrypt_config
diff --git a/encrypt-config/ConfigFile.h b/encrypt-config/ConfigFile.h
index 53b7e58b0..634c9a89c 100644
--- a/encrypt-config/ConfigFile.h
+++ b/encrypt-config/ConfigFile.h
@@ -35,10 +35,7 @@ class ConfigFile : public PropertiesFile {
   [[nodiscard]] std::vector<std::string> getSensitiveProperties() const;
 
  private:
-  friend class ConfigFileTestAccessor;
   friend bool operator==(const ConfigFile&, const ConfigFile&);
-  static std::vector<std::string> mergeProperties(std::vector<std::string> 
properties,
-                                                  const 
std::vector<std::string>& additional_properties);
 };
 
 }  // namespace encrypt_config
diff --git a/encrypt-config/tests/ConfigFileTests.cpp 
b/encrypt-config/tests/ConfigFileTests.cpp
index 894cd3a40..ab5d9bd78 100644
--- a/encrypt-config/tests/ConfigFileTests.cpp
+++ b/encrypt-config/tests/ConfigFileTests.cpp
@@ -29,27 +29,7 @@
 #include "Catch.h"
 #include "utils/file/FileUtils.h"
 
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace encrypt_config {
-
-class ConfigFileTestAccessor {
- public:
-  static std::vector<std::string> mergeProperties(std::vector<std::string> 
left, const std::vector<std::string>& right) {
-    return ConfigFile::mergeProperties(left, right);
-  }
-};
-
-}  // namespace encrypt_config
-}  // namespace minifi
-}  // namespace nifi
-}  // namespace apache
-}  // namespace org
-
 using org::apache::nifi::minifi::encrypt_config::ConfigFile;
-using org::apache::nifi::minifi::encrypt_config::ConfigFileTestAccessor;
 using org::apache::nifi::minifi::Configuration;
 
 TEST_CASE("ConfigLine can be constructed from a line", 
"[encrypt-config][constructor]") {
@@ -205,30 +185,6 @@ TEST_CASE("ConfigFile will throw if we try to write to an 
invalid file name", "[
   REQUIRE_THROWS(test_file.writeTo(file_path));
 }
 
-TEST_CASE("ConfigFile can merge lists of property names", 
"[encrypt-config][mergeProperties]") {
-  using vector = std::vector<std::string>;
-
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{}, vector{}) == 
vector{});
-
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a"}, vector{}) == 
vector{"a"});
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a"}, vector{"a"}) == 
vector{"a"});
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a"}, vector{"b"}) == 
(vector{"a", "b"}));
-
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"c"}) == (vector{"a", "b", "c"}));
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"a", "b"}) == (vector{"a", "b"}));
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"a", "c"}) == (vector{"a", "b", "c"}));
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"b", "c"}) == (vector{"a", "b", "c"}));
-
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a"}, vector{" a"}) 
== vector{"a"});
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a"}, vector{"a "}) 
== vector{"a"});
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a"}, vector{" a "}) 
== vector{"a"});
-
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"\tc"}) == (vector{"a", "b", "c"}));
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"a\n", "b"}) == (vector{"a", "b"}));
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"a", "c\r\n"}) == (vector{"a", "b", "c"}));
-  REQUIRE(ConfigFileTestAccessor::mergeProperties(vector{"a", "b"}, 
vector{"b\n", "\t c"}) == (vector{"a", "b", "c"}));
-}
-
 TEST_CASE("ConfigFile can find the list of sensitive properties", 
"[encrypt-config][getSensitiveProperties]") {
   SECTION("default properties") {
     ConfigFile test_file{std::ifstream{"resources/minifi.properties"}};
diff --git a/extensions/http-curl/tests/C2DescribeCoreComponentStateTest.cpp 
b/extensions/http-curl/tests/C2DescribeCoreComponentStateTest.cpp
index cf2f619e9..8754bfa0f 100644
--- a/extensions/http-curl/tests/C2DescribeCoreComponentStateTest.cpp
+++ b/extensions/http-curl/tests/C2DescribeCoreComponentStateTest.cpp
@@ -28,7 +28,8 @@
 
 class VerifyC2DescribeCoreComponentState : public VerifyC2Describe {
  public:
-  VerifyC2DescribeCoreComponentState() {
+  explicit VerifyC2DescribeCoreComponentState(std::atomic_bool& verified)
+    : VerifyC2Describe(verified) {
     temp_dir_ = testController.createTempDirectory();
 
     test_file_1_ = utils::file::FileUtils::concat_path(temp_dir_, "test1.txt");
@@ -62,8 +63,9 @@ class VerifyC2DescribeCoreComponentState : public 
VerifyC2Describe {
 
 class DescribeCoreComponentStateHandler: public HeartbeatHandler {
  public:
-  explicit 
DescribeCoreComponentStateHandler(std::shared_ptr<minifi::Configure> 
configuration)
-    : HeartbeatHandler(std::move(configuration)) {
+  explicit 
DescribeCoreComponentStateHandler(std::shared_ptr<minifi::Configure> 
configuration, std::atomic_bool& verified)
+    : HeartbeatHandler(std::move(configuration)),
+      verified_(verified) {
   }
 
   void handleHeartbeat(const rapidjson::Document&, struct mg_connection * 
conn) override {
@@ -86,14 +88,19 @@ class DescribeCoreComponentStateHandler: public 
HeartbeatHandler {
 
     assertExpectedTailFileState("2438e3c8-015a-1000-79ca-83af40ec1993", 
"test1.txt", "4");
     assertExpectedTailFileState("2438e3c8-015a-1000-79ca-83af40ec1994", 
"test2.txt", "7");
+    verified_ = true;
   }
+
+ private:
+  std::atomic_bool& verified_;
 };
 
 int main(int argc, char **argv) {
+  std::atomic_bool verified{false};
   const cmd_args args = parse_cmdline_args(argc, argv, "api/heartbeat");
-  VerifyC2DescribeCoreComponentState harness;
+  VerifyC2DescribeCoreComponentState harness(verified);
   harness.setKeyDir(args.key_dir);
-  DescribeCoreComponentStateHandler handler(harness.getConfiguration());
+  DescribeCoreComponentStateHandler handler(harness.getConfiguration(), 
verified);
   harness.setUrl(args.url, &handler);
   harness.run(args.test_file);
   return 0;
diff --git a/extensions/http-curl/tests/C2DescribeManifestTest.cpp 
b/extensions/http-curl/tests/C2DescribeManifestTest.cpp
index a6a9a38c6..242800ee4 100644
--- a/extensions/http-curl/tests/C2DescribeManifestTest.cpp
+++ b/extensions/http-curl/tests/C2DescribeManifestTest.cpp
@@ -26,8 +26,9 @@
 
 class DescribeManifestHandler: public HeartbeatHandler {
  public:
-  explicit DescribeManifestHandler(std::shared_ptr<minifi::Configure> 
configuration)
-    : HeartbeatHandler(std::move(configuration)) {
+  explicit DescribeManifestHandler(std::shared_ptr<minifi::Configure> 
configuration, std::atomic<bool>& verified)
+    : HeartbeatHandler(std::move(configuration)),
+      verified_(verified) {
   }
 
   void handleHeartbeat(const rapidjson::Document&, struct mg_connection * 
conn) override {
@@ -36,22 +37,31 @@ class DescribeManifestHandler: public HeartbeatHandler {
 
   void handleAcknowledge(const rapidjson::Document& root) override {
     verifyJsonHasAgentManifest(root, {"InvokeHTTP", "LogAttribute"}, 
{"nifi.extension.path", "nifi.python.processor.dir"});
+    verified_ = true;
   }
+
+ private:
+  std::atomic<bool>& verified_;
 };
 
 int main(int argc, char **argv) {
   const cmd_args args = parse_cmdline_args(argc, argv, "heartbeat");
-  VerifyC2Describe harness;
+  std::atomic_bool verified{false};
+  VerifyC2Describe harness(verified);
   utils::crypto::Bytes encryption_key = 
utils::StringUtils::from_hex("4024b327fdc987ce3eb43dd1f690b9987e4072e0020e3edf4349ce1ad91a4e38");
   minifi::Decryptor 
decryptor{utils::crypto::EncryptionProvider{encryption_key}};
   std::string encrypted_value = 
"l3WY1V27knTiPa6jVX0jrq4qjmKsySOu||ErntqZpHP1M+6OkA14p5sdnqJhuNHWHDVUU5EyMloTtSytKk9a5xNKo=";
 
   harness.setConfiguration(std::make_shared<minifi::Configure>(decryptor));
   harness.setKeyDir(args.key_dir);
-  DescribeManifestHandler responder(harness.getConfiguration());
+  DescribeManifestHandler responder(harness.getConfiguration(), verified);
 
   
harness.getConfiguration()->set(minifi::Configuration::nifi_rest_api_password, 
encrypted_value);
   
harness.getConfiguration()->set(std::string(minifi::Configuration::nifi_rest_api_password)
 + ".protected", utils::crypto::EncryptionType::name());
+  harness.getConfiguration()->set(minifi::Configuration::nifi_server_name, 
"server_name");
+  harness.getConfiguration()->set(minifi::Configuration::nifi_framework_dir, 
"framework_path");
+  
harness.getConfiguration()->set(minifi::Configuration::nifi_sensitive_props_additional_keys,
+    std::string(minifi::Configuration::nifi_framework_dir) + ", " + 
std::string(minifi::Configuration::nifi_server_name));
 
   harness.setUrl(args.url, &responder);
   harness.run(args.test_file);
diff --git a/extensions/http-curl/tests/C2JstackTest.cpp 
b/extensions/http-curl/tests/C2JstackTest.cpp
index b7cfb8aeb..f1b9b4521 100644
--- a/extensions/http-curl/tests/C2JstackTest.cpp
+++ b/extensions/http-curl/tests/C2JstackTest.cpp
@@ -25,17 +25,6 @@
 #include "HTTPHandlers.h"
 #include "utils/IntegrationTestUtils.h"
 
-class VerifyC2DescribeJstack : public VerifyC2Describe {
- public:
-  explicit VerifyC2DescribeJstack(const std::atomic_bool& 
acknowledgement_received) : VerifyC2Describe(), 
acknowledgement_received_(acknowledgement_received) {}
-  void runAssertions() override {
-    using org::apache::nifi::minifi::utils::verifyEventHappenedInPollTime;
-    
assert(verifyEventHappenedInPollTime(std::chrono::milliseconds(wait_time_), [&] 
{ return acknowledgement_received_.load(); }));
-  }
- protected:
-  const std::atomic_bool& acknowledgement_received_;
-};
-
 class DescribeJstackHandler : public HeartbeatHandler {
  public:
   explicit DescribeJstackHandler(std::atomic_bool& acknowledgement_received, 
std::shared_ptr<minifi::Configure> configuration)
@@ -58,7 +47,7 @@ class DescribeJstackHandler : public HeartbeatHandler {
 int main(int argc, char **argv) {
   const cmd_args args = parse_cmdline_args(argc, argv, "heartbeat");
   std::atomic_bool acknowledgement_received{ false };
-  VerifyC2DescribeJstack harness{acknowledgement_received};
+  VerifyC2Describe harness{acknowledgement_received};
   harness.setKeyDir(args.key_dir);
   DescribeJstackHandler responder{acknowledgement_received, 
harness.getConfiguration()};
   harness.setUrl(args.url, &responder);
diff --git a/extensions/http-curl/tests/HTTPHandlers.h 
b/extensions/http-curl/tests/HTTPHandlers.h
index c136ab179..92478a00a 100644
--- a/extensions/http-curl/tests/HTTPHandlers.h
+++ b/extensions/http-curl/tests/HTTPHandlers.h
@@ -552,7 +552,13 @@ class HeartbeatHandler : public ServerAwareHandler {
       }
       case minifi::c2::Operation::UPDATE: {
         std::vector<std::unordered_map<std::string, std::string>> 
config_properties;
+        const auto prop_reader = [this](const std::string& sensitive_props) { 
return configuration_->getString(sensitive_props); };
+        const auto sensitive_props = 
minifi::Configuration::getSensitiveProperties(prop_reader);
         for (const auto& property : 
minifi::Configuration::CONFIGURATION_PROPERTIES) {
+          if (ranges::find(sensitive_props, property.name) != 
ranges::end(sensitive_props)) {
+            continue;
+          }
+
           std::unordered_map<std::string, std::string> config_property;
           if (ranges::find(disallowed_properties, property.name) == 
ranges::end(disallowed_properties)) {
             config_property.emplace("propertyName", property.name);
diff --git a/extensions/http-curl/tests/HTTPIntegrationBase.h 
b/extensions/http-curl/tests/HTTPIntegrationBase.h
index 407399f0a..1136f217b 100644
--- a/extensions/http-curl/tests/HTTPIntegrationBase.h
+++ b/extensions/http-curl/tests/HTTPIntegrationBase.h
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <string>
+#include <atomic>
 
 #include "CivetServer.h"
 #include "integration/IntegrationBase.h"
@@ -146,6 +147,10 @@ class VerifyC2Base : public HTTPIntegrationBase {
 
 class VerifyC2Describe : public VerifyC2Base {
  public:
+  explicit VerifyC2Describe(std::atomic<bool>& verified)
+    : verified_(verified) {
+  }
+
   void testSetup() override {
     LogTestController::getInstance().setTrace<minifi::c2::C2Agent>();
     LogTestController::getInstance().setDebug<minifi::c2::RESTSender>();
@@ -158,10 +163,12 @@ class VerifyC2Describe : public VerifyC2Base {
   }
 
   void runAssertions() override {
-    // This class is never used for running assertions, but we are forced to 
wait for DescribeManifestHandler to verifyJsonHasAgentManifest
-    // if we were to log something on finished verification, we could poll on 
finding it
-    std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_));
+    using org::apache::nifi::minifi::utils::verifyEventHappenedInPollTime;
+    
assert(verifyEventHappenedInPollTime(std::chrono::milliseconds(wait_time_), [&] 
{ return verified_.load(); }));
   }
+
+ protected:
+  std::atomic<bool>& verified_;
 };
 
 class VerifyC2Update : public HTTPIntegrationBase {
diff --git a/extensions/standard-processors/tests/unit/ConfigurationTests.cpp 
b/extensions/standard-processors/tests/unit/ConfigurationTests.cpp
new file mode 100644
index 000000000..eb8d95dc9
--- /dev/null
+++ b/extensions/standard-processors/tests/unit/ConfigurationTests.cpp
@@ -0,0 +1,47 @@
+/**
+ *
+ * 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.
+ */
+#include "TestBase.h"
+#include "Catch.h"
+
+#include "properties/Configuration.h"
+
+using org::apache::nifi::minifi::Configuration;
+
+TEST_CASE("Configuration can merge lists of property names", 
"[mergeProperties]") {
+  using vector = std::vector<std::string>;
+
+  REQUIRE(Configuration::mergeProperties(vector{}, vector{}) == vector{});
+
+  REQUIRE(Configuration::mergeProperties(vector{"a"}, vector{}) == 
vector{"a"});
+  REQUIRE(Configuration::mergeProperties(vector{"a"}, vector{"a"}) == 
vector{"a"});
+  REQUIRE(Configuration::mergeProperties(vector{"a"}, vector{"b"}) == 
(vector{"a", "b"}));
+
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"c"}) == 
(vector{"a", "b", "c"}));
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"a", "b"}) 
== (vector{"a", "b"}));
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"a", "c"}) 
== (vector{"a", "b", "c"}));
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"b", "c"}) 
== (vector{"a", "b", "c"}));
+
+  REQUIRE(Configuration::mergeProperties(vector{"a"}, vector{" a"}) == 
vector{"a"});
+  REQUIRE(Configuration::mergeProperties(vector{"a"}, vector{"a "}) == 
vector{"a"});
+  REQUIRE(Configuration::mergeProperties(vector{"a"}, vector{" a "}) == 
vector{"a"});
+
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"\tc"}) == 
(vector{"a", "b", "c"}));
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"a\n", "b"}) 
== (vector{"a", "b"}));
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"a", 
"c\r\n"}) == (vector{"a", "b", "c"}));
+  REQUIRE(Configuration::mergeProperties(vector{"a", "b"}, vector{"b\n", "\t 
c"}) == (vector{"a", "b", "c"}));
+}
diff --git a/libminifi/include/core/Property.h 
b/libminifi/include/core/Property.h
index 00e6dd11a..0ca55efca 100644
--- a/libminifi/include/core/Property.h
+++ b/libminifi/include/core/Property.h
@@ -469,7 +469,8 @@ class ConstrainedProperty : public 
std::enable_shared_from_this<ConstrainedPrope
 };
 
 struct ConfigurationProperty {
-  explicit ConfigurationProperty(std::string_view name, 
gsl::not_null<PropertyValidator*> validator = 
gsl::make_not_null(StandardValidators::get().VALID_VALIDATOR.get()))
+  explicit ConfigurationProperty(std::string_view name,
+      gsl::not_null<PropertyValidator*> validator = 
gsl::make_not_null(StandardValidators::get().VALID_VALIDATOR.get()))
     : name(name),
       validator(validator) {
   }
diff --git a/libminifi/include/properties/Configuration.h 
b/libminifi/include/properties/Configuration.h
index 840953e05..6f7a3394c 100644
--- a/libminifi/include/properties/Configuration.h
+++ b/libminifi/include/properties/Configuration.h
@@ -17,8 +17,8 @@
 
 #pragma once
 
-#include <mutex>
 #include <vector>
+#include <string>
 
 #include "properties/Properties.h"
 #include "utils/OptionalUtils.h"
@@ -163,6 +163,11 @@ class Configuration : public Properties {
   static constexpr const char *nifi_log_compression_compressed_log_max_size = 
"nifi.log.compression.compressed.log.max.size";
 
   MINIFIAPI static const std::vector<core::ConfigurationProperty> 
CONFIGURATION_PROPERTIES;
+  MINIFIAPI static const std::array<const char*, 2> 
DEFAULT_SENSITIVE_PROPERTIES;
+
+  static std::vector<std::string> mergeProperties(std::vector<std::string> 
properties,
+                                                  const 
std::vector<std::string>& additional_properties);
+  static std::vector<std::string> 
getSensitiveProperties(std::function<std::optional<std::string>(const 
std::string&)> reader);
 };
 
 }  // namespace minifi
diff --git a/libminifi/src/Configuration.cpp b/libminifi/src/Configuration.cpp
index 3e916ec7a..91a50cff0 100644
--- a/libminifi/src/Configuration.cpp
+++ b/libminifi/src/Configuration.cpp
@@ -14,6 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <algorithm>
+
 #include "properties/Configuration.h"
 #include "core/Property.h"
 
@@ -129,4 +131,34 @@ const std::vector<core::ConfigurationProperty> 
Configuration::CONFIGURATION_PROP
   
core::ConfigurationProperty{Configuration::nifi_log_compression_compressed_log_max_size,
 gsl::make_not_null(core::StandardValidators::get().DATA_SIZE_VALIDATOR.get())}
 };
 
+const std::array<const char*, 2> Configuration::DEFAULT_SENSITIVE_PROPERTIES = 
{Configuration::nifi_security_client_pass_phrase,
+                                                                               
 Configuration::nifi_rest_api_password};
+
+std::vector<std::string> 
Configuration::mergeProperties(std::vector<std::string> properties,
+                                                        const 
std::vector<std::string>& additional_properties) {
+  for (const auto& property_name : additional_properties) {
+    std::string property_name_trimmed = 
utils::StringUtils::trim(property_name);
+    if (!property_name_trimmed.empty()) {
+      properties.push_back(std::move(property_name_trimmed));
+    }
+  }
+
+  std::sort(properties.begin(), properties.end());
+  auto new_end = std::unique(properties.begin(), properties.end());
+  properties.erase(new_end, properties.end());
+  return properties;
+}
+
+std::vector<std::string> 
Configuration::getSensitiveProperties(std::function<std::optional<std::string>(const
 std::string&)> reader) {
+  std::vector<std::string> 
sensitive_properties(Configuration::DEFAULT_SENSITIVE_PROPERTIES.begin(), 
Configuration::DEFAULT_SENSITIVE_PROPERTIES.end());
+  if (reader) {
+    const auto additional_sensitive_props_list = 
reader(Configuration::nifi_sensitive_props_additional_keys);
+    if (additional_sensitive_props_list) {
+      std::vector<std::string> additional_sensitive_properties = 
utils::StringUtils::split(*additional_sensitive_props_list, ",");
+      return Configuration::mergeProperties(sensitive_properties, 
additional_sensitive_properties);
+    }
+  }
+  return sensitive_properties;
+}
+
 }  // namespace org::apache::nifi::minifi
diff --git a/libminifi/src/core/state/nodes/SupportedOperations.cpp 
b/libminifi/src/core/state/nodes/SupportedOperations.cpp
index e7ff1f61f..f96e8b2d8 100644
--- a/libminifi/src/core/state/nodes/SupportedOperations.cpp
+++ b/libminifi/src/core/state/nodes/SupportedOperations.cpp
@@ -18,6 +18,7 @@
 
 #include "core/state/nodes/SupportedOperations.h"
 #include "core/Resource.h"
+#include "range/v3/algorithm/find.hpp"
 
 namespace org::apache::nifi::minifi::state::response {
 
@@ -64,9 +65,12 @@ void 
SupportedOperations::addProperty(SerializedResponseNode& properties, const
 
 SupportedOperations::Metadata 
SupportedOperations::buildUpdatePropertiesMetadata() const {
   std::vector<std::unordered_map<std::string, std::string>> 
supported_config_updates;
-  for (const auto& config_property : 
minifi::Configuration::CONFIGURATION_PROPERTIES) {
-    if (!update_policy_controller_ ||
-        (update_policy_controller_ && 
update_policy_controller_->canUpdate(std::string(config_property.name)))) {
+  for (const auto& config_property : Configuration::CONFIGURATION_PROPERTIES) {
+    auto sensitive_properties = 
Configuration::getSensitiveProperties(configuration_reader_);
+    if (ranges::find(sensitive_properties, config_property.name) != 
ranges::end(sensitive_properties)) {
+      continue;
+    }
+    if (!update_policy_controller_ || 
update_policy_controller_->canUpdate(std::string(config_property.name))) {
       std::unordered_map<std::string, std::string> property;
       property.emplace("propertyName", config_property.name);
       property.emplace("validator", config_property.validator->getName());

Reply via email to