1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
/*
* Copyright 2009- ECMWF.
*
* This software is licensed under the terms of the Apache Licence version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/
#include <boost/test/unit_test.hpp>
#include "InvokeServer.hpp"
#include "SCPort.hpp"
#include "ecflow/client/ClientEnvironment.hpp"
#include "ecflow/client/ClientInvoker.hpp"
#include "ecflow/core/PasswdFile.hpp"
#include "ecflow/core/User.hpp"
#include "ecflow/test/scaffold/Naming.hpp"
using namespace std;
using namespace ecf;
BOOST_AUTO_TEST_SUITE(S_Client)
BOOST_AUTO_TEST_SUITE(T_CustomUser)
// ************************************************************************************
// Note: If you make edits to node tree, they will have no effect until the server is rebuilt
//
// Note: To test HPUX->Linux, invoke serve on (Linux/HPUX) and the client cmds on other system
// On the client side set ECF_HOST to machine name. To allow further testing if ECF_HOST
// is specified then *don't* shutdown the server
// ************************************************************************************
class Add_ECF_CUSTOM_PASSWD_and_ECF_USER_env {
public:
explicit Add_ECF_CUSTOM_PASSWD_and_ECF_USER_env(const std::string& passwd_file)
: ecf_passwd_("ECF_CUSTOM_PASSWD="),
ecf_user_("ECF_USER=") {
ecf_passwd_ += passwd_file;
auto* put = const_cast<char*>(ecf_passwd_.c_str());
BOOST_CHECK_MESSAGE(putenv(put) == 0, "putenv failed for " << put);
ecf_user_ += get_login_name();
auto* put2 = const_cast<char*>(ecf_user_.c_str());
BOOST_CHECK_MESSAGE(putenv(put2) == 0, "putenv failed for " << put2);
}
~Add_ECF_CUSTOM_PASSWD_and_ECF_USER_env() {
putenv(const_cast<char*>("ECF_CUSTOM_PASSWD")); // remove from env, otherwise valgrind complains
putenv(const_cast<char*>("ECF_USER")); // remove from env, otherwise valgrind complains
}
private:
std::string ecf_passwd_;
std::string ecf_user_;
};
BOOST_AUTO_TEST_CASE(test_custom_user) {
ECF_NAME_THIS_TEST();
Host the_host;
std::string host = ClientEnvironment::hostSpecified();
std::string port = SCPort::next();
std::string passwd_file = the_host.ecf_custom_passwd_file(port);
std::string passwd = "xxxx";
if (host.empty()) {
// make sure NO passed file is present before the server is started.
// Only do this locally, as passwd file on remote machine may not be accessible
fs::remove(passwd_file);
}
else {
// The test only works if server is started locally.
std::cout << "...Client:: ...test_custom_user ignoring when HOST specified\n";
return;
}
{
// Create a valid passwd file; Before server start; make sure server closes before password file is deleted:
// cout << "\nCreating CUSTOM passwd_file " << passwd_file << "\n\n";
std::string errorMsg;
BOOST_REQUIRE_MESSAGE(PasswdFile::createWithAccess(passwd_file, the_host.name(), port, passwd, errorMsg),
errorMsg);
BOOST_REQUIRE_MESSAGE(fs::exists(passwd_file), "passwd file NOT created");
}
{ // *** Need a separate scope so that server shuts down whilst password file is *STILL* present
// *** Otherwise terminate of server will fail. i.e ECF_PASSWORD is still valid
// Set ECF_USER and ECF_PASSWD environment variable. Use same file for client and server
// add on construction, and remove at destruction.
Add_ECF_CUSTOM_PASSWD_and_ECF_USER_env custom_user(passwd_file);
// This will remove check pt and backup file before server start,
// to avoid the server from loading previous test data
// make sure server closes before password file is deleted:
InvokeServer invokeServer("Client:: ...test_custom_user", port);
BOOST_REQUIRE_MESSAGE(invokeServer.server_started(),
"Server failed to start on " << invokeServer.host() << ":" << invokeServer.port());
ClientInvoker theClient(invokeServer.host(), invokeServer.port());
theClient.set_throw_on_error(false);
// Invoking a client request that requires authorisation
BOOST_REQUIRE_MESSAGE(theClient.reloadcustompasswdfile() == 0,
CtsApi::reloadcustompasswdfile() << " should return 0\n"
<< theClient.errorMsg());
BOOST_REQUIRE_MESSAGE(theClient.delete_all() == 0,
CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n"
<< theClient.errorMsg());
BOOST_REQUIRE_MESSAGE(theClient.shutdownServer() == 0,
CtsApi::shutdownServer() << " should return 0\n"
<< theClient.errorMsg());
BOOST_REQUIRE_MESSAGE(theClient.haltServer() == 0,
CtsApi::haltServer() << " should return 0\n"
<< theClient.errorMsg());
BOOST_REQUIRE_MESSAGE(theClient.restartServer() == 0,
CtsApi::restartServer() << " should return 0\n"
<< theClient.errorMsg());
// Change to a user not in password file
theClient.set_user_name(
"dodgy_geezer"); // this should clear password, so that its reloaded when *next* cmd runs
// all client command should now *FAIL*.
BOOST_CHECK_MESSAGE(theClient.reloadcustompasswdfile() == 1,
CtsApi::reloadcustompasswdfile() << " should return 1\n");
BOOST_CHECK_MESSAGE(theClient.delete_all() == 1,
CtsApi::to_string(CtsApi::delete_node()) << " should return 0\n"
<< theClient.errorMsg());
BOOST_CHECK_MESSAGE(theClient.shutdownServer() == 1,
CtsApi::shutdownServer() << " should return 0\n"
<< theClient.errorMsg());
BOOST_CHECK_MESSAGE(theClient.haltServer() == 1,
CtsApi::haltServer() << " should return 0\n"
<< theClient.errorMsg());
BOOST_CHECK_MESSAGE(theClient.restartServer() == 1,
CtsApi::restartServer() << " should return 0\n"
<< theClient.errorMsg());
// reset to a valid user again:
theClient.set_user_name(
get_login_name()); // this should clear password, so that its reloaded when *next* cmd runs
// all client command should now pass. Invoking a client request that requires authorisation
BOOST_CHECK_MESSAGE(theClient.reloadcustompasswdfile() == 0,
CtsApi::reloadcustompasswdfile() << " should return 0\n");
BOOST_CHECK_MESSAGE(theClient.shutdownServer() == 0, "should return 0\n" << theClient.errorMsg());
BOOST_CHECK_MESSAGE(theClient.getDefs() == 0, "should return 0\n" << theClient.errorMsg());
BOOST_CHECK_MESSAGE(theClient.sync_local() == 0, "should return 0\n" << theClient.errorMsg());
BOOST_CHECK_MESSAGE(theClient.news_local() == 0, "should return 0\n" << theClient.errorMsg());
// terminate server with a valid valid user since ECF_PASSWORD/ECF_USER is still in effect.
}
// Remove the white list file. Comment out for debug
fs::remove(passwd_file);
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
|