blob: 0a19918d78721ff09bb04d42795bc4bae3c6efef [file] [log] [blame]
raviteja-b8cc44052019-02-27 23:29:36 -06001#include "mock_user_mgr.hpp"
Nan Zhoue47c09d2022-10-25 00:06:41 +00002#include "user_mgr.hpp"
Patrick Williams9638afb2021-02-22 17:16:24 -06003
Ravi Teja417c0892020-08-22 08:04:01 -05004#include <sdbusplus/test/sdbus_mock.hpp>
Patrick Williams9638afb2021-02-22 17:16:24 -06005#include <xyz/openbmc_project/Common/error.hpp>
6#include <xyz/openbmc_project/User/Common/error.hpp>
7
8#include <exception>
Nan Zhoue48085d2022-10-25 00:07:04 +00009#include <filesystem>
10#include <fstream>
Nan Zhouda401fe2022-10-25 00:07:18 +000011#include <vector>
Patrick Williams9638afb2021-02-22 17:16:24 -060012
Nan Zhouda401fe2022-10-25 00:07:18 +000013#include <gmock/gmock.h>
Patrick Williams9638afb2021-02-22 17:16:24 -060014#include <gtest/gtest.h>
raviteja-b8cc44052019-02-27 23:29:36 -060015
16namespace phosphor
17{
18namespace user
19{
20
21using ::testing::Return;
Alexander Filippov75626582022-02-09 18:42:37 +030022using ::testing::Throw;
raviteja-b8cc44052019-02-27 23:29:36 -060023
24using InternalFailure =
25 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Alexander Filippov75626582022-02-09 18:42:37 +030026using UserNameDoesNotExist =
27 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameDoesNotExist;
raviteja-b8cc44052019-02-27 23:29:36 -060028
29class TestUserMgr : public testing::Test
30{
31 public:
Nan Zhou78d85042022-08-29 17:50:22 +000032 sdbusplus::SdBusMock sdBusMock;
Patrick Williamsb3ef4e12022-07-22 19:26:55 -050033 sdbusplus::bus_t bus;
raviteja-b8cc44052019-02-27 23:29:36 -060034 MockManager mockManager;
35
36 TestUserMgr() :
Nan Zhou78d85042022-08-29 17:50:22 +000037 bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath)
Patrick Williams9638afb2021-02-22 17:16:24 -060038 {}
raviteja-b8cc44052019-02-27 23:29:36 -060039
Patrick Williams9638afb2021-02-22 17:16:24 -060040 void createLocalUser(const std::string& userName,
raviteja-b8cc44052019-02-27 23:29:36 -060041 std::vector<std::string> groupNames,
Patrick Williams9638afb2021-02-22 17:16:24 -060042 const std::string& priv, bool enabled)
raviteja-b8cc44052019-02-27 23:29:36 -060043 {
P Dheeraj Srujan Kumarb01e2fe2021-12-13 09:43:28 +053044 sdbusplus::message::object_path tempObjPath(usersObjPath);
45 tempObjPath /= userName;
46 std::string userObj(tempObjPath);
raviteja-b8cc44052019-02-27 23:29:36 -060047 mockManager.usersList.emplace(
Nan Zhou78d85042022-08-29 17:50:22 +000048 userName, std::make_unique<phosphor::user::Users>(
raviteja-b8cc44052019-02-27 23:29:36 -060049 mockManager.bus, userObj.c_str(), groupNames, priv,
Nan Zhou78d85042022-08-29 17:50:22 +000050 enabled, mockManager));
raviteja-b8cc44052019-02-27 23:29:36 -060051 }
52
53 DbusUserObj createPrivilegeMapperDbusObject(void)
54 {
55 DbusUserObj object;
56 DbusUserObjValue objValue;
Ravi Teja5fe724a2019-05-07 05:14:42 -050057
Nan Zhou78d85042022-08-29 17:50:22 +000058 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
Ravi Teja5fe724a2019-05-07 05:14:42 -050059 DbusUserPropVariant enabled(true);
60 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
61 std::string intf = "xyz.openbmc_project.Object.Enable";
62 objValue.emplace(intf, property);
Nan Zhou78d85042022-08-29 17:50:22 +000063 object.emplace(objPath, objValue);
Ravi Teja5fe724a2019-05-07 05:14:42 -050064
Nan Zhou78d85042022-08-29 17:50:22 +000065 DbusUserObjPath objectPath(
Ravi Teja5fe724a2019-05-07 05:14:42 -050066 "/xyz/openbmc_project/user/ldap/openldap/role_map/1");
67 std::string group = "ldapGroup";
68 std::string priv = "priv-admin";
raviteja-b8cc44052019-02-27 23:29:36 -060069 DbusUserObjProperties properties = {std::make_pair("GroupName", group),
70 std::make_pair("Privilege", priv)};
71 std::string interface = "xyz.openbmc_project.User.PrivilegeMapperEntry";
72
73 objValue.emplace(interface, properties);
Nan Zhou78d85042022-08-29 17:50:22 +000074 object.emplace(objectPath, objValue);
raviteja-b8cc44052019-02-27 23:29:36 -060075
76 return object;
77 }
Ravi Teja5fe724a2019-05-07 05:14:42 -050078
79 DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void)
80 {
81 DbusUserObj object;
82 DbusUserObjValue objValue;
83
Nan Zhou78d85042022-08-29 17:50:22 +000084 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
Ravi Teja5fe724a2019-05-07 05:14:42 -050085 DbusUserPropVariant enabled(true);
86 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
87 std::string intf = "xyz.openbmc_project.Object.Enable";
88 objValue.emplace(intf, property);
Nan Zhou78d85042022-08-29 17:50:22 +000089 object.emplace(objPath, objValue);
Ravi Teja5fe724a2019-05-07 05:14:42 -050090 return object;
91 }
raviteja-b8cc44052019-02-27 23:29:36 -060092};
93
94TEST_F(TestUserMgr, ldapEntryDoesNotExist)
95{
96 std::string userName = "user";
97 UserInfoMap userInfo;
98
Alexander Filippov75626582022-02-09 18:42:37 +030099 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
100 .WillRepeatedly(Throw(UserNameDoesNotExist()));
101 EXPECT_THROW(userInfo = mockManager.getUserInfo(userName),
102 UserNameDoesNotExist);
raviteja-b8cc44052019-02-27 23:29:36 -0600103}
104
105TEST_F(TestUserMgr, localUser)
106{
107 UserInfoMap userInfo;
108 std::string userName = "testUser";
109 std::string privilege = "priv-admin";
110 std::vector<std::string> groups{"testGroup"};
111 // Create local user
112 createLocalUser(userName, groups, privilege, true);
113 EXPECT_CALL(mockManager, userLockedForFailedAttempt(userName)).Times(1);
114 userInfo = mockManager.getUserInfo(userName);
115
116 EXPECT_EQ(privilege, std::get<std::string>(userInfo["UserPrivilege"]));
117 EXPECT_EQ(groups,
118 std::get<std::vector<std::string>>(userInfo["UserGroups"]));
119 EXPECT_EQ(true, std::get<bool>(userInfo["UserEnabled"]));
120 EXPECT_EQ(false, std::get<bool>(userInfo["UserLockedForFailedAttempt"]));
Joseph Reynolds3ab6cc22020-03-03 14:09:03 -0600121 EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"]));
raviteja-b8cc44052019-02-27 23:29:36 -0600122 EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"]));
123}
124
125TEST_F(TestUserMgr, ldapUserWithPrivMapper)
126{
127 UserInfoMap userInfo;
128 std::string userName = "ldapUser";
129 std::string ldapGroup = "ldapGroup";
Alexander Filippov75626582022-02-09 18:42:37 +0300130 gid_t primaryGid = 1000;
raviteja-b8cc44052019-02-27 23:29:36 -0600131
Alexander Filippov75626582022-02-09 18:42:37 +0300132 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
133 .WillRepeatedly(Return(primaryGid));
raviteja-b8cc44052019-02-27 23:29:36 -0600134 // Create privilege mapper dbus object
135 DbusUserObj object = createPrivilegeMapperDbusObject();
136 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
137 .WillRepeatedly(Return(object));
Alexander Filippov75626582022-02-09 18:42:37 +0300138 EXPECT_CALL(mockManager, isGroupMember(userName, primaryGid, ldapGroup))
139 .WillRepeatedly(Return(true));
raviteja-b8cc44052019-02-27 23:29:36 -0600140 userInfo = mockManager.getUserInfo(userName);
141 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
142 EXPECT_EQ("priv-admin", std::get<std::string>(userInfo["UserPrivilege"]));
143}
144
145TEST_F(TestUserMgr, ldapUserWithoutPrivMapper)
146{
Alexander Filippov75626582022-02-09 18:42:37 +0300147 using ::testing::_;
148
raviteja-b8cc44052019-02-27 23:29:36 -0600149 UserInfoMap userInfo;
150 std::string userName = "ldapUser";
151 std::string ldapGroup = "ldapGroup";
Alexander Filippov75626582022-02-09 18:42:37 +0300152 gid_t primaryGid = 1000;
raviteja-b8cc44052019-02-27 23:29:36 -0600153
Alexander Filippov75626582022-02-09 18:42:37 +0300154 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
155 .WillRepeatedly(Return(primaryGid));
Ravi Teja5fe724a2019-05-07 05:14:42 -0500156 // Create LDAP config object without privilege mapper
157 DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper();
raviteja-b8cc44052019-02-27 23:29:36 -0600158 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
159 .WillRepeatedly(Return(object));
Alexander Filippov75626582022-02-09 18:42:37 +0300160 EXPECT_CALL(mockManager, isGroupMember(_, _, _)).Times(0);
raviteja-b8cc44052019-02-27 23:29:36 -0600161 userInfo = mockManager.getUserInfo(userName);
162 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
Jiaqing Zhao56862062022-05-31 19:16:09 +0800163 EXPECT_EQ("priv-user", std::get<std::string>(userInfo["UserPrivilege"]));
raviteja-b8cc44052019-02-27 23:29:36 -0600164}
Nan Zhoue47c09d2022-10-25 00:06:41 +0000165
166TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString)
167{
168 EXPECT_EQ(getCSVFromVector({}), "");
169}
170
171TEST(GetCSVFromVector, ElementsAreJoinedByComma)
172{
173 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123"}), "123");
174 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123", "456"}),
175 "123,456");
176}
177
Nan Zhou332fb9d2022-10-25 00:07:03 +0000178TEST(RemoveStringFromCSV, WithoutDeleteStringReturnsFalse)
179{
180 std::string expected = "whatever,https";
181 std::string str = expected;
182 EXPECT_FALSE(removeStringFromCSV(str, "ssh"));
183 EXPECT_EQ(str, expected);
184
185 std::string empty;
186 EXPECT_FALSE(removeStringFromCSV(empty, "ssh"));
187}
188
189TEST(RemoveStringFromCSV, WithDeleteStringReturnsTrue)
190{
191 std::string expected = "whatever";
192 std::string str = "whatever,https";
193 EXPECT_TRUE(removeStringFromCSV(str, "https"));
194 EXPECT_EQ(str, expected);
195
196 str = "https";
197 EXPECT_TRUE(removeStringFromCSV(str, "https"));
198 EXPECT_EQ(str, "");
199}
200
Nan Zhoue48085d2022-10-25 00:07:04 +0000201namespace
202{
203inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user";
204
Jason M. Bills2d042d12023-03-28 15:32:45 -0700205// Fake configs; referenced configs on real BMC
Nan Zhoue48085d2022-10-25 00:07:04 +0000206inline constexpr const char* rawConfig = R"(
207#
208# /etc/pam.d/common-password - password-related modules common to all services
209#
210# This file is included from other service-specific PAM config files,
211# and should contain a list of modules that define the services to be
212# used to change user passwords. The default is pam_unix.
213
214# Explanation of pam_unix options:
215#
216# The "sha512" option enables salted SHA512 passwords. Without this option,
217# the default is Unix crypt. Prior releases used the option "md5".
218#
219# The "obscure" option replaces the old `OBSCURE_CHECKS_ENAB' option in
220# login.defs.
221#
222# See the pam_unix manpage for other options.
223
224# here are the per-package modules (the "Primary" block)
Jason M. Bills2d042d12023-03-28 15:32:45 -0700225password [success=ok default=die] pam_faillock.so authsucc
226password [success=ok default=die] pam_pwquality.so debug
Nan Zhoue48085d2022-10-25 00:07:04 +0000227password [success=ok default=die] pam_ipmicheck.so spec_grp_name=ipmi use_authtok
228password [success=ok ignore=ignore default=die] pam_pwhistory.so debug enforce_for_root remember=0 use_authtok
229password [success=ok default=die] pam_unix.so sha512 use_authtok
230password [success=1 default=die] pam_ipmisave.so spec_grp_name=ipmi spec_pass_file=/etc/ipmi_pass key_file=/etc/key_file
231# here's the fallback if no module succeeds
232password requisite pam_deny.so
233# prime the stack with a positive return value if there isn't one already;
234# this avoids us returning an error just because nothing sets a success code
235# since the modules above will each just jump around
236password required pam_permit.so
237# and here are more per-package modules (the "Additional" block)
238)";
Jason M. Bills2d042d12023-03-28 15:32:45 -0700239inline constexpr const char* rawFailLockConfig = R"(
240deny=2
241unlock_time=3
242)";
243inline constexpr const char* rawPWQualityConfig = R"(
244enforce_for_root
245minlen=8
246difok=0
247lcredit=0
248ocredit=0
249dcredit=0
250ucredit=0
251)";
Nan Zhoue48085d2022-10-25 00:07:04 +0000252} // namespace
253
254void dumpStringToFile(const std::string& str, const std::string& filePath)
255{
256 std::ofstream outputFileStream;
257
258 outputFileStream.exceptions(std::ofstream::failbit | std::ofstream::badbit |
259 std::ofstream::eofbit);
260
261 outputFileStream.open(filePath, std::ios::out);
262 outputFileStream << str << "\n" << std::flush;
263 outputFileStream.close();
264}
265
266void removeFile(const std::string& filePath)
267{
268 std::filesystem::remove(filePath);
269}
270
271class UserMgrInTest : public testing::Test, public UserMgr
272{
273 public:
274 UserMgrInTest() : UserMgr(busInTest, objectRootInTest)
275 {
276 tempPamConfigFile = "/tmp/test-data-XXXXXX";
277 mktemp(tempPamConfigFile.data());
278 EXPECT_NO_THROW(dumpStringToFile(rawConfig, tempPamConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700279 tempFaillockConfigFile = "/tmp/test-data-XXXXXX";
280 mktemp(tempFaillockConfigFile.data());
281 EXPECT_NO_THROW(
282 dumpStringToFile(rawFailLockConfig, tempFaillockConfigFile));
283 tempPWQualityConfigFile = "/tmp/test-data-XXXXXX";
284 mktemp(tempPWQualityConfigFile.data());
285 EXPECT_NO_THROW(
286 dumpStringToFile(rawPWQualityConfig, tempPWQualityConfigFile));
Nan Zhoue48085d2022-10-25 00:07:04 +0000287 // Set config files to test files
288 pamPasswdConfigFile = tempPamConfigFile;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700289 faillockConfigFile = tempFaillockConfigFile;
290 pwQualityConfigFile = tempPWQualityConfigFile;
Nan Zhou49c81362022-10-25 00:07:08 +0000291
292 ON_CALL(*this, executeUserAdd).WillByDefault(testing::Return());
293
294 ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return());
295
Jayanth Othayothac921a52023-07-21 03:48:55 -0500296 ON_CALL(*this, executeUserClearFailRecords)
297 .WillByDefault(testing::Return());
298
Nan Zhou49c81362022-10-25 00:07:08 +0000299 ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0));
Nan Zhouf25443e2022-10-25 00:07:11 +0000300
301 ON_CALL(*this, executeUserRename).WillByDefault(testing::Return());
Nan Zhoufef63032022-10-25 00:07:12 +0000302
303 ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_))
304 .WillByDefault(testing::Return());
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000305
306 ON_CALL(*this, executeUserModifyUserEnable)
307 .WillByDefault(testing::Return());
Nan Zhouda401fe2022-10-25 00:07:18 +0000308
309 ON_CALL(*this, executeGroupCreation(testing::_))
310 .WillByDefault(testing::Return());
311
312 ON_CALL(*this, executeGroupDeletion(testing::_))
313 .WillByDefault(testing::Return());
314
315 ON_CALL(*this, executeGroupCreation).WillByDefault(testing::Return());
316
317 ON_CALL(*this, executeGroupDeletion).WillByDefault(testing::Return());
Nan Zhoue48085d2022-10-25 00:07:04 +0000318 }
319
320 ~UserMgrInTest() override
321 {
322 EXPECT_NO_THROW(removeFile(tempPamConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700323 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
324 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
Nan Zhoue48085d2022-10-25 00:07:04 +0000325 }
326
Nan Zhou49c81362022-10-25 00:07:08 +0000327 MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool),
328 (override));
329
330 MOCK_METHOD(void, executeUserDelete, (const char*), (override));
331
Jayanth Othayothac921a52023-07-21 03:48:55 -0500332 MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override));
333
Nan Zhou49c81362022-10-25 00:07:08 +0000334 MOCK_METHOD(size_t, getIpmiUsersCount, (), (override));
335
Nan Zhouf25443e2022-10-25 00:07:11 +0000336 MOCK_METHOD(void, executeUserRename, (const char*, const char*),
337 (override));
338
Nan Zhoufef63032022-10-25 00:07:12 +0000339 MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool),
340 (override));
341
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000342 MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool),
343 (override));
344
Nan Zhoua2953032022-11-11 21:50:32 +0000345 MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*),
346 (override));
347
Nan Zhouda401fe2022-10-25 00:07:18 +0000348 MOCK_METHOD(void, executeGroupCreation, (const char*), (override));
349
350 MOCK_METHOD(void, executeGroupDeletion, (const char*), (override));
351
Nan Zhoufef63032022-10-25 00:07:12 +0000352 protected:
Nan Zhoue48085d2022-10-25 00:07:04 +0000353 static sdbusplus::bus_t busInTest;
354 std::string tempPamConfigFile;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700355 std::string tempFaillockConfigFile;
356 std::string tempPWQualityConfigFile;
Nan Zhoue48085d2022-10-25 00:07:04 +0000357};
358
359sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
360
361TEST_F(UserMgrInTest, GetPamModuleArgValueOnSuccess)
362{
Jason M. Bills2d042d12023-03-28 15:32:45 -0700363 std::string remember;
364 EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
365 0);
366 EXPECT_EQ(remember, "0");
367}
368
369TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
370{
371 std::string minlen;
372 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
373 0);
374 EXPECT_EQ(minlen, "8");
375 std::string deny;
376 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
377 EXPECT_EQ(deny, "2");
Nan Zhoue48085d2022-10-25 00:07:04 +0000378}
379
380TEST_F(UserMgrInTest, SetPamModuleArgValueOnSuccess)
381{
Jason M. Bills2d042d12023-03-28 15:32:45 -0700382 EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), 0);
383 std::string remember;
384 EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
385 0);
386 EXPECT_EQ(remember, "1");
387}
388
389TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
390{
391 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
392 0);
393 std::string minlen;
394 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
395 0);
396 EXPECT_EQ(minlen, "16");
397
398 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
399 std::string deny;
400 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
401 EXPECT_EQ(deny, "3");
Nan Zhoue48085d2022-10-25 00:07:04 +0000402}
403
Jason M. Bills17b88272023-05-22 14:24:02 -0700404TEST_F(UserMgrInTest, SetPamModuleArgValueTempFileOnSuccess)
405{
406 EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), 0);
407
408 std::string tmpFile = tempPamConfigFile + "_tmp";
409 EXPECT_FALSE(std::filesystem::exists(tmpFile));
410}
411
412TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
413{
414 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
415 0);
416
417 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
418 EXPECT_FALSE(std::filesystem::exists(tmpFile));
419
420 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
421
422 tmpFile = tempFaillockConfigFile + "_tmp";
423 EXPECT_FALSE(std::filesystem::exists(tmpFile));
424}
425
Nan Zhoue48085d2022-10-25 00:07:04 +0000426TEST_F(UserMgrInTest, GetPamModuleArgValueOnFailure)
427{
428 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700429 std::string remember;
430 EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
431 -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000432
433 EXPECT_NO_THROW(removeFile(tempPamConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700434 EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
435 -1);
436}
437
438TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
439{
440 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
441 std::string minlen;
442 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
443 -1);
444
445 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
446 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
447 -1);
448
449 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
450 std::string deny;
451 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
452
453 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
454 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000455}
456
457TEST_F(UserMgrInTest, SetPamModuleArgValueOnFailure)
458{
459 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700460 EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000461
462 EXPECT_NO_THROW(removeFile(tempPamConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700463 EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
464}
465
466TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
467{
468 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
469 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
470 -1);
471
472 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
473 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
474 -1);
475
476 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
477 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
478
479 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
480 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000481}
482
Jason M. Bills17b88272023-05-22 14:24:02 -0700483TEST_F(UserMgrInTest, SetPamModuleArgValueTempFileOnFailure)
484{
485 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
486 EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
487
488 std::string tmpFile = tempPamConfigFile + "_tmp";
489 EXPECT_FALSE(std::filesystem::exists(tmpFile));
490
491 EXPECT_NO_THROW(removeFile(tempPamConfigFile));
492 EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
493
494 EXPECT_FALSE(std::filesystem::exists(tmpFile));
495}
496
497TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
498{
499 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
500 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
501 -1);
502
503 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
504 EXPECT_FALSE(std::filesystem::exists(tmpFile));
505
506 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
507 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
508 -1);
509
510 EXPECT_FALSE(std::filesystem::exists(tmpFile));
511
512 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
513 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
514
515 tmpFile = tempFaillockConfigFile + "_tmp";
516 EXPECT_FALSE(std::filesystem::exists(tmpFile));
517
518 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
519 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
520
521 EXPECT_FALSE(std::filesystem::exists(tmpFile));
522}
523
Nan Zhou8a11d992022-10-25 00:07:06 +0000524TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
525{
526 EXPECT_THROW(
527 isUserExist(""),
528 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
529}
530
531TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
532{
533 EXPECT_THROW(throwForUserDoesNotExist("whatever"),
534 sdbusplus::xyz::openbmc_project::User::Common::Error::
535 UserNameDoesNotExist);
536}
537
538TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
539{
540 EXPECT_THROW(
541 throwForUserExists("root"),
542 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
543}
544
Nan Zhou40e44972022-10-25 00:07:07 +0000545TEST_F(
546 UserMgrInTest,
547 ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)
548{
549 std::string strWith17Chars(17, 'A');
550 EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}),
551 sdbusplus::xyz::openbmc_project::User::Common::Error::
552 UserNameGroupFail);
553}
554
555TEST_F(
556 UserMgrInTest,
557 ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
558{
559 std::string strWith31Chars(31, 'A');
560 EXPECT_THROW(
561 throwForUserNameConstraints(strWith31Chars, {}),
562 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
563}
564
565TEST_F(UserMgrInTest,
566 ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
567{
568 std::string startWithNumber = "0ABC";
569 EXPECT_THROW(
570 throwForUserNameConstraints(startWithNumber, {"ipmi"}),
571 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
572}
573
Nan Zhou49c81362022-10-25 00:07:08 +0000574TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure)
575{
576 EXPECT_THROW(
577 UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true),
578 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
579}
580
581TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
582{
583 EXPECT_THROW(
584 UserMgr::executeUserDelete("user0"),
585 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
586}
587
588TEST_F(UserMgrInTest,
589 ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)
590{
591 EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers));
592 EXPECT_THROW(
593 throwForMaxGrpUserCount({"ipmi"}),
594 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
595}
596
597TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails)
598{
599 EXPECT_CALL(*this, executeUserAdd)
600 .WillOnce(testing::Throw(
601 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
602 EXPECT_THROW(
603 createUser("whatever", {"redfish"}, "", true),
604 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
605}
606
607TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)
608{
609 std::string username = "user";
610 EXPECT_NO_THROW(
611 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
612 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
613 .WillOnce(testing::Throw(
614 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
615 .WillOnce(testing::DoDefault());
616
617 EXPECT_THROW(
618 deleteUser(username),
619 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
620 EXPECT_NO_THROW(UserMgr::deleteUser(username));
621}
622
Jayanth Othayothac921a52023-07-21 03:48:55 -0500623TEST_F(UserMgrInTest,
624 DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)
625{
626 const char* username = "user";
627 EXPECT_NO_THROW(
628 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
629 EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username)))
630 .WillOnce(testing::Throw(
631 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
632 .WillOnce(testing::DoDefault());
633
634 EXPECT_THROW(
635 deleteUser(username),
636 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
637 EXPECT_NO_THROW(UserMgr::deleteUser(username));
638}
639
Nan Zhou589aeb42022-10-25 00:07:09 +0000640TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
641{
642 EXPECT_THROW(
643 throwForInvalidPrivilege("whatever"),
644 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
645}
646
647TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)
648{
649 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin"));
650 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator"));
651 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user"));
Nan Zhou589aeb42022-10-25 00:07:09 +0000652}
653
Nan Zhouecf88762022-10-25 00:07:10 +0000654TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
655{
656 EXPECT_THROW(
657 throwForInvalidGroups({"whatever"}),
658 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
659}
660
661TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
662{
663 EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
664 EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
665 EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
666 EXPECT_NO_THROW(throwForInvalidGroups({"web"}));
Ninad Palsule601d3db2023-03-09 10:27:37 -0600667 EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
Nan Zhouecf88762022-10-25 00:07:10 +0000668}
669
Nan Zhouf25443e2022-10-25 00:07:11 +0000670TEST_F(UserMgrInTest, RenameUserOnSuccess)
671{
672 std::string username = "user001";
673 EXPECT_NO_THROW(
674 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
675 std::string newUsername = "user002";
676
677 EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername));
678
679 // old username doesn't exist
680 EXPECT_THROW(getUserInfo(username),
681 sdbusplus::xyz::openbmc_project::User::Common::Error::
682 UserNameDoesNotExist);
683
684 UserInfoMap userInfo = getUserInfo(newUsername);
685 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
686 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
687 testing::UnorderedElementsAre("redfish", "ssh"));
688 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
689
690 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
691}
692
693TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails)
694{
695 std::string username = "user001";
696 EXPECT_NO_THROW(
697 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
698 std::string newUsername = "user002";
699
700 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
701 testing::StrEq(newUsername)))
702 .WillOnce(testing::Throw(
703 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
704 EXPECT_THROW(
705 UserMgr::renameUser(username, newUsername),
706 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
707
708 // The original user is unchanged
709 UserInfoMap userInfo = getUserInfo(username);
710 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
711 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
712 testing::UnorderedElementsAre("redfish", "ssh"));
713 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
714
715 EXPECT_NO_THROW(UserMgr::deleteUser(username));
716}
717
718TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
719{
720 EXPECT_THROW(
721 UserMgr::executeUserRename("user0", "user1"),
722 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
Nan Zhoufef63032022-10-25 00:07:12 +0000723 EXPECT_THROW(
724 UserMgr::executeUserModify("user0", "ssh", true),
725 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
726}
727
728TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess)
729{
730 std::string username = "user001";
731 EXPECT_NO_THROW(
732 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
733 EXPECT_NO_THROW(
734 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"));
735 UserInfoMap userInfo = getUserInfo(username);
736 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin");
737 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
738 testing::UnorderedElementsAre("ipmi", "ssh"));
739 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
740 EXPECT_NO_THROW(UserMgr::deleteUser(username));
741}
742
743TEST_F(UserMgrInTest,
744 UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)
745{
746 std::string username = "user001";
747 EXPECT_NO_THROW(
748 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
749 EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_,
750 testing::_))
751 .WillOnce(testing::Throw(
752 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
753 EXPECT_THROW(
754 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"),
755 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
756 EXPECT_NO_THROW(UserMgr::deleteUser(username));
Nan Zhouf25443e2022-10-25 00:07:11 +0000757}
758
Nan Zhou18031012022-11-10 22:24:58 +0000759TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
760{
761 initializeAccountPolicy();
762 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
763 UserMgr::minPasswordLength(8);
764 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
765}
766
767TEST_F(UserMgrInTest,
768 MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)
769{
770 initializeAccountPolicy();
771 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
772 EXPECT_THROW(
773 UserMgr::minPasswordLength(minPasswdLength - 1),
774 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
775 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
776}
777
778TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
779{
780 initializeAccountPolicy();
781 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
782 UserMgr::minPasswordLength(16);
783 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
784}
785
786TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
787{
Jason M. Bills2d042d12023-03-28 15:32:45 -0700788 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
Nan Zhou18031012022-11-10 22:24:58 +0000789 initializeAccountPolicy();
790 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
791 EXPECT_THROW(
792 UserMgr::minPasswordLength(16),
793 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
794 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
795}
796
Nan Zhoua6ce1fa2022-10-25 00:07:14 +0000797TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame)
798{
799 initializeAccountPolicy();
800 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
801 UserMgr::rememberOldPasswordTimes(8);
802 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
803 UserMgr::rememberOldPasswordTimes(8);
804 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
805}
806
807TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
808{
809 initializeAccountPolicy();
810 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
811 UserMgr::rememberOldPasswordTimes(16);
812 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
813}
814
815TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
816{
817 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
818 initializeAccountPolicy();
819 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
820 EXPECT_THROW(
821 UserMgr::rememberOldPasswordTimes(16),
822 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
823 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
824}
825
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000826TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
827{
828 initializeAccountPolicy();
829 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
830 UserMgr::maxLoginAttemptBeforeLockout(2);
831 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
832}
833
834TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
835{
836 initializeAccountPolicy();
837 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
838 UserMgr::maxLoginAttemptBeforeLockout(16);
839 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
840}
841
842TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
843{
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000844 initializeAccountPolicy();
Jason M. Bills2d042d12023-03-28 15:32:45 -0700845 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000846 EXPECT_THROW(
847 UserMgr::maxLoginAttemptBeforeLockout(16),
848 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
Jason M. Bills2d042d12023-03-28 15:32:45 -0700849 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000850}
851
Nan Zhou784aecd2022-10-25 00:07:16 +0000852TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
853{
854 initializeAccountPolicy();
855 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
856 UserMgr::accountUnlockTimeout(3);
857 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
858}
859
860TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
861{
862 initializeAccountPolicy();
863 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
864 UserMgr::accountUnlockTimeout(16);
865 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
866}
867
868TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
869{
870 initializeAccountPolicy();
Jason M. Bills2d042d12023-03-28 15:32:45 -0700871 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
Nan Zhou784aecd2022-10-25 00:07:16 +0000872 EXPECT_THROW(
873 UserMgr::accountUnlockTimeout(16),
874 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
875 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
876}
877
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000878TEST_F(UserMgrInTest, UserEnableOnSuccess)
879{
880 std::string username = "user001";
881 EXPECT_NO_THROW(
882 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
883 UserInfoMap userInfo = getUserInfo(username);
884 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
885
886 EXPECT_NO_THROW(userEnable(username, false));
887
888 userInfo = getUserInfo(username);
889 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false);
890
891 EXPECT_NO_THROW(UserMgr::deleteUser(username));
892}
893
Ninad Palsule601d3db2023-03-09 10:27:37 -0600894TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole)
895{
896 std::string username = "user001";
897 EXPECT_NO_THROW(
898 UserMgr::createUser(username, {"hostconsole"}, "priv-user", true));
899 EXPECT_NO_THROW(UserMgr::deleteUser(username));
900 EXPECT_NO_THROW(
901 UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true));
902 EXPECT_NO_THROW(UserMgr::deleteUser(username));
903 EXPECT_NO_THROW(
904 UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true));
905 EXPECT_NO_THROW(UserMgr::deleteUser(username));
906}
907
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000908TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail)
909{
910 std::string username = "user001";
911 EXPECT_NO_THROW(
912 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
913 UserInfoMap userInfo = getUserInfo(username);
914 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
915
916 EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username),
917 testing::Eq(false)))
918 .WillOnce(testing::Throw(
919 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
920 EXPECT_THROW(
921 userEnable(username, false),
922 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
923
924 userInfo = getUserInfo(username);
925 // Stay unchanged
926 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
927
928 EXPECT_NO_THROW(UserMgr::deleteUser(username));
929}
930
Nan Zhoua2953032022-11-11 21:50:32 +0000931TEST_F(
932 UserMgrInTest,
933 UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
934{
935 EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
936}
937
938TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
939{
940 std::string username = "user001";
941 initializeAccountPolicy();
942 // Example output from BMC
Jason M. Bills2d042d12023-03-28 15:32:45 -0700943 // root:~# faillock --user root
944 // root:
945 // When Type Source Valid
946 std::vector<std::string> output = {"whatever",
947 "When Type Source Valid"};
Nan Zhoua2953032022-11-11 21:50:32 +0000948 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
949 .WillOnce(testing::Return(output));
950
951 EXPECT_FALSE(userLockedForFailedAttempt(username));
952}
953
954TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail)
955{
956 std::string username = "user001";
957 initializeAccountPolicy();
958 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
959 .WillOnce(testing::Throw(
960 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
961
962 EXPECT_THROW(
963 userLockedForFailedAttempt(username),
964 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
965}
966
967TEST_F(UserMgrInTest,
Nan Zhoua2953032022-11-11 21:50:32 +0000968 UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
969{
970 std::string username = "user001";
971 initializeAccountPolicy();
972
973 // Choose a date in the past.
974 std::vector<std::string> output = {"whatever",
Jason M. Bills2d042d12023-03-28 15:32:45 -0700975 "10/24/2002 00:00:00 type source V"};
Nan Zhoua2953032022-11-11 21:50:32 +0000976 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
977 .WillOnce(testing::Return(output));
978
979 EXPECT_THROW(
980 userLockedForFailedAttempt(username),
981 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
982}
983
984TEST_F(UserMgrInTest,
985 UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)
986{
987 std::string username = "user001";
988 initializeAccountPolicy();
989
990 // Choose a date in the past.
991 std::vector<std::string> output = {"whatever",
Jason M. Bills2d042d12023-03-28 15:32:45 -0700992 "2002-10-24 00:00:00 type source V"};
Nan Zhoua2953032022-11-11 21:50:32 +0000993 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
994 .WillOnce(testing::Return(output));
995
996 EXPECT_EQ(userLockedForFailedAttempt(username), false);
997}
998
Nan Zhouda401fe2022-10-25 00:07:18 +0000999TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess)
1000{
1001 // Base Redfish Roles
1002 EXPECT_NO_THROW(
1003 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator"));
1004 EXPECT_NO_THROW(
1005 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator"));
1006 EXPECT_NO_THROW(
1007 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly"));
1008 // Base Redfish Privileges
1009 EXPECT_NO_THROW(
1010 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login"));
1011 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1012 "openbmc_rfp_ConfigureManager"));
1013 EXPECT_NO_THROW(
1014 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers"));
1015 EXPECT_NO_THROW(
1016 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf"));
1017 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1018 "openbmc_rfp_ConfigureComponents"));
1019 // OEM Redfish Roles
1020 EXPECT_NO_THROW(
1021 checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService"));
1022 // OEM Redfish Privileges
1023 EXPECT_NO_THROW(
1024 checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService"));
1025}
1026
1027TEST_F(UserMgrInTest,
1028 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)
1029{
1030 std::string groupName(maxSystemGroupNameLength + 1, 'A');
1031 EXPECT_THROW(
1032 checkAndThrowForDisallowedGroupCreation(groupName),
1033 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1034}
1035
1036TEST_F(
1037 UserMgrInTest,
1038 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1039{
Nan Zhouda401fe2022-10-25 00:07:18 +00001040 EXPECT_THROW(
1041 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"),
1042 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1043 EXPECT_THROW(
1044 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"),
1045 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1046}
1047
1048TEST_F(
1049 UserMgrInTest,
1050 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1051{
Nan Zhouda401fe2022-10-25 00:07:18 +00001052 EXPECT_THROW(
1053 checkAndThrowForDisallowedGroupCreation("google_rfp_"),
1054 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1055 EXPECT_THROW(
1056 checkAndThrowForDisallowedGroupCreation("com_rfp_"),
1057 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1058}
1059
1060TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1061{
Ninad Palsule601d3db2023-03-09 10:27:37 -06001062 constexpr size_t predefGroupCount = 5;
1063
1064 EXPECT_THAT(allGroups().size(), predefGroupCount);
1065 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
Nan Zhouda401fe2022-10-25 00:07:18 +00001066 {
1067 std::string groupName = "openbmc_rfr_role";
1068 groupName += std::to_string(i);
1069 EXPECT_NO_THROW(createGroup(groupName));
1070 }
1071 EXPECT_THROW(
1072 createGroup("openbmc_rfr_AnotherRole"),
1073 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
Ninad Palsule601d3db2023-03-09 10:27:37 -06001074 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
Nan Zhouda401fe2022-10-25 00:07:18 +00001075 {
1076 std::string groupName = "openbmc_rfr_role";
1077 groupName += std::to_string(i);
1078 EXPECT_NO_THROW(deleteGroup(groupName));
1079 }
1080}
1081
1082TEST_F(UserMgrInTest, CheckAndThrowForGroupExist)
1083{
1084 std::string groupName = "openbmc_rfr_role";
1085 EXPECT_NO_THROW(createGroup(groupName));
1086 EXPECT_THROW(
1087 createGroup(groupName),
1088 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1089 EXPECT_NO_THROW(deleteGroup(groupName));
1090}
1091
1092TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1093{
1094 EXPECT_THAT(allGroups(),
Ninad Palsule601d3db2023-03-09 10:27:37 -06001095 testing::UnorderedElementsAre("web", "redfish", "ipmi", "ssh",
1096 "hostconsole"));
1097}
1098
1099TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1100{
1101 EXPECT_THROW(
1102 createGroup("ipmi"),
1103 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1104 EXPECT_THROW(
1105 createGroup("web"),
1106 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1107 EXPECT_THROW(
1108 createGroup("redfish"),
1109 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1110 EXPECT_THROW(
1111 createGroup("ssh"),
1112 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1113 EXPECT_THROW(
1114 createGroup("hostconsole"),
1115 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
Nan Zhouda401fe2022-10-25 00:07:18 +00001116}
1117
1118TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1119{
1120 EXPECT_THROW(
1121 deleteGroup("ipmi"),
1122 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1123 EXPECT_THROW(
1124 deleteGroup("web"),
1125 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1126 EXPECT_THROW(
1127 deleteGroup("redfish"),
1128 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1129 EXPECT_THROW(
1130 deleteGroup("ssh"),
1131 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Ninad Palsule601d3db2023-03-09 10:27:37 -06001132 EXPECT_THROW(
1133 deleteGroup("hostconsole"),
1134 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Nan Zhouda401fe2022-10-25 00:07:18 +00001135}
1136
1137TEST_F(UserMgrInTest,
1138 CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)
1139{
1140 EXPECT_CALL(*this, executeGroupCreation)
1141 .WillOnce(testing::Throw(
1142 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1143 EXPECT_THROW(
1144 createGroup("openbmc_rfr_role1"),
1145 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1146}
1147
1148TEST_F(UserMgrInTest,
1149 DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)
1150{
1151 std::string groupName = "openbmc_rfr_role1";
1152 EXPECT_NO_THROW(UserMgr::createGroup(groupName));
1153 EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName)))
1154 .WillOnce(testing::Throw(
1155 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1156 .WillOnce(testing::DoDefault());
1157
1158 EXPECT_THROW(
1159 deleteGroup(groupName),
1160 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1161 EXPECT_NO_THROW(UserMgr::deleteGroup(groupName));
1162}
1163
1164TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1165{
1166 EXPECT_THROW(deleteGroup("whatever"),
1167 sdbusplus::xyz::openbmc_project::User::Common::Error::
1168 GroupNameDoesNotExist);
1169}
1170
1171TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1172{
1173 EXPECT_THAT(UserMgr::readAllGroupsOnSystem(),
Ninad Palsule601d3db2023-03-09 10:27:37 -06001174 testing::UnorderedElementsAre("web", "redfish", "ipmi", "ssh",
1175 "hostconsole"));
Nan Zhouda401fe2022-10-25 00:07:18 +00001176}
1177
raviteja-b8cc44052019-02-27 23:29:36 -06001178} // namespace user
1179} // namespace phosphor