Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions libs/server/src/ecflow/server/ServerEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,20 +327,7 @@ bool ServerEnvironment::valid(std::string& errorMsg) const {
/// read in the ecf white list file that specifies valid users and their access rights
/// If the file can't be opened returns false and an error message and false;
/// Automatically add server admin(user) with write access, as this will allow admin reload
if (auto loaded = load_whitelist_file(errorMsg); loaded) {
if (auto result = AuthorisationService::load_permissions_from_whitelist(this->white_list_file_); result.ok()) {
authorisation_service_ = result.value();
std::cout << "Loaded server permissions based on Whitelist file\n";
return true;
}
else {
std::cout << "Unable to load server permissions, due to: " << result.reason() << '\n';
return false;
}
}
else {
return false;
}
return load_whitelist_file(errorMsg);
}

std::pair<std::string, std::string> ServerEnvironment::hostPort() const {
Expand Down Expand Up @@ -426,7 +413,16 @@ bool ServerEnvironment::load_whitelist_file(std::string& errorMsg) const {
// (Requires terminate, modify white list, restart to fix)
// Hence always allow server user write access *IF* required for non-empty file
white_list_file_.allow_write_access_for_server_user();
return true;

if (auto result = AuthorisationService::load_permissions_from_whitelist(this->white_list_file_); result.ok()) {
authorisation_service_ = result.value();
std::cout << "Loaded server permissions based on Whitelist file\n";
return true;
}
else {
std::cout << "Unable to load server permissions, due to: " << result.reason() << '\n';
return false;
}
}
return false;
}
Expand Down
2 changes: 2 additions & 0 deletions libs/test/foolproof/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,7 @@ ecbuild_add_test(
DEPENDS
ecflow_server
ecflow_client
ARGS
--random=1
)
target_clangformat(s_foolproof CONDITION ENABLE_TESTS)
126 changes: 125 additions & 1 deletion libs/test/foolproof/TestFoolproof.PasswordsAndWhiteLists.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ BOOST_AUTO_TEST_CASE(test_e2e_reload_whitelist) {
/*
* Description
*
* This test case ensures that the 'reloadwsfile' command effectively reloads the content of white list.
* This test case ensures that the 'reloadwsfile' command effectively reloads the content of a white list file.
*
* Requirements
*
Expand Down Expand Up @@ -449,6 +449,130 @@ endsuite;
}
}

BOOST_AUTO_TEST_CASE(test_e2e_reload_whitelist_created_after_server_is_launched) {
ECF_NAME_THIS_TEST();

/*
* Description
*
* This test case ensures that the 'reloadwsfile' command effectively reloads the content of a white list file,
* created after the server is launched.
*
* Requirements
*
* - The 'reloadwsfile' command loads the content of the whitelist file, created after the server is launched.
*
*/

using namespace foolproof::scaffold;

auto cwd = MakeDirectory{}.create();

auto user_a = User{"alice", "somesecret", "rw"};
auto user_b = User{"bob", "anothersecret", "r"};

auto host = MakeHost{}.create();
auto port = MakePort{}.with(AutomaticPortValue{}).create();

auto authentication = MakeTestFile{}
.with(SpecificFileLocation{"custom.passwds", cwd})
.with(PasswordsFile{host, port, user_a, user_b}.data())
.create();

auto authorisation_file = fs::path{"custom.lists"};

auto server_environment_cfg =
MakeTestFile{}
.with(SpecificFileLocation{"server_environment.cfg", cwd})
.with(ServerEnvironmentFile{std::make_tuple("ECF_PASSWD", authentication.filename()),
std::make_tuple("ECF_CUSTOM_PASSWD", authentication.filename()),
std::make_tuple("ECF_LISTS", authorisation_file)}
.data())
.create();

const auto server = MakeServer{}.with(host).with(port).with(cwd).launch();
{
BOOST_REQUIRE(server.ok());
auto& s = server.value();
BOOST_CHECK(s.pid() > 0);
BOOST_CHECK(s.port().value() == port.value());
BOOST_CHECK(s.host().is_valid());
}

auto defs = MakeTestFile{}
.with(SpecificFileLocation{"suite.def", cwd})
.with(R"--(
suite s
family f
task task
label l "original_value"
endfamily
endsuite;
)--")
.create();

{ // #authorisation, perform write operation (without whitelist) -- load defs file % [success]
auto client =
RunClient{}.with(host).with(port).with(user_a).with(cwd).execute(RunClient::CommandLoad{defs.path()});
BOOST_REQUIRE(client.ok());
auto& c = client.value();

ECF_TEST_DBG("Output of --load:\n" << c.stdout_buffer);
}

{ // #authorisation, perform write operation (without whitelist) -- update label value % [success]
auto client = RunClient{}.with(host).with(port).with(user_a).with(cwd).execute(
RunClient::CommandUpdateLabel{"/s/f/task", "l", "updated_value"});
BOOST_REQUIRE(client.ok());
auto c = client.value();

ECF_TEST_DBG("Output of --alter label:\n" << c.stdout_buffer);
}

{ // #authorisation, perform write operation (without whitelist) -- update label value % [success]
auto client = RunClient{}.with(host).with(port).with(user_b).with(cwd).execute(
RunClient::CommandUpdateLabel{"/s/f/task", "l", "another_updated_value"});
BOOST_REQUIRE(client.ok());
auto c = client.value();

ECF_TEST_DBG("Output of --alter label:\n" << c.stdout_buffer);
}

auto authorisation = MakeTestFile{}
.with(SpecificFileLocation{authorisation_file, cwd})
.with(WhitelistFile{user_a, user_b}.data())
.create();

{ // #authorisation, perform write operation (without whitelist) -- reload whitelist file % [success]
auto client =
RunClient{}.with(host).with(port).with(user_a).with(cwd).execute(RunClient::CommandReloadWhitelist{});
BOOST_REQUIRE(client.ok());
auto c = client.value();

ECF_TEST_DBG("Output of --reloadwsfile:\n" << c.stdout_buffer);
}

{ // #authorisation, perform write operation with "rw" access -- update label value % [success]
auto client = RunClient{}.with(host).with(port).with(user_a).with(cwd).execute(
RunClient::CommandUpdateLabel{"/s/f/task", "l", "updated_value"});
BOOST_REQUIRE(client.ok());
auto c = client.value();

ECF_TEST_DBG("Output of --alter label:\n" << c.stdout_buffer);
}

{ // #authorisation, perform write operation with only "r" access -- update label value % [failure]
auto client = RunClient{}.with(host).with(port).with(user_b).with(cwd).execute(
RunClient::CommandUpdateLabel{"/s/f/task", "l", "another_updated_value"});
BOOST_REQUIRE(!client.ok());

BOOST_CHECK(
client.reason().find(
"Command not accepted, due to: Authorisation (user) failed, due to: Insufficient permissions") !=
std::string::npos);
}
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()
Loading