File: TestCustomUser.cpp

package info (click to toggle)
ecflow 5.15.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 51,868 kB
  • sloc: cpp: 269,341; python: 22,756; sh: 3,609; perl: 770; xml: 333; f90: 204; ansic: 141; makefile: 70
file content (162 lines) | stat: -rw-r--r-- 7,999 bytes parent folder | download
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()