blob: bb84e6d451ce9dfd4a51e824a49de978e2ffde21 [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);
Denis Zlobine8edab52023-09-06 12:26:45 +000047 if (enabled)
48 {
49 ON_CALL(mockManager, isUserEnabled)
50 .WillByDefault(testing::Return(true));
51 }
52 else
53 {
54 ON_CALL(mockManager, isUserEnabled)
55 .WillByDefault(testing::Return(false));
56 }
raviteja-b8cc44052019-02-27 23:29:36 -060057 mockManager.usersList.emplace(
Abhilash Raju0e427be2025-03-03 12:11:39 +000058 userName,
59 std::make_unique<MockUser>(mockManager.bus, userObj.c_str(),
60 groupNames, priv, enabled, mockManager));
raviteja-b8cc44052019-02-27 23:29:36 -060061 }
62
63 DbusUserObj createPrivilegeMapperDbusObject(void)
64 {
65 DbusUserObj object;
66 DbusUserObjValue objValue;
Ravi Teja5fe724a2019-05-07 05:14:42 -050067
Nan Zhou78d85042022-08-29 17:50:22 +000068 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
Ravi Teja5fe724a2019-05-07 05:14:42 -050069 DbusUserPropVariant enabled(true);
70 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
71 std::string intf = "xyz.openbmc_project.Object.Enable";
72 objValue.emplace(intf, property);
Nan Zhou78d85042022-08-29 17:50:22 +000073 object.emplace(objPath, objValue);
Ravi Teja5fe724a2019-05-07 05:14:42 -050074
Nan Zhou78d85042022-08-29 17:50:22 +000075 DbusUserObjPath objectPath(
Ravi Teja5fe724a2019-05-07 05:14:42 -050076 "/xyz/openbmc_project/user/ldap/openldap/role_map/1");
77 std::string group = "ldapGroup";
78 std::string priv = "priv-admin";
raviteja-b8cc44052019-02-27 23:29:36 -060079 DbusUserObjProperties properties = {std::make_pair("GroupName", group),
80 std::make_pair("Privilege", priv)};
81 std::string interface = "xyz.openbmc_project.User.PrivilegeMapperEntry";
82
83 objValue.emplace(interface, properties);
Nan Zhou78d85042022-08-29 17:50:22 +000084 object.emplace(objectPath, objValue);
raviteja-b8cc44052019-02-27 23:29:36 -060085
86 return object;
87 }
Ravi Teja5fe724a2019-05-07 05:14:42 -050088
89 DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void)
90 {
91 DbusUserObj object;
92 DbusUserObjValue objValue;
93
Nan Zhou78d85042022-08-29 17:50:22 +000094 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
Ravi Teja5fe724a2019-05-07 05:14:42 -050095 DbusUserPropVariant enabled(true);
96 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
97 std::string intf = "xyz.openbmc_project.Object.Enable";
98 objValue.emplace(intf, property);
Nan Zhou78d85042022-08-29 17:50:22 +000099 object.emplace(objPath, objValue);
Ravi Teja5fe724a2019-05-07 05:14:42 -0500100 return object;
101 }
raviteja-b8cc44052019-02-27 23:29:36 -0600102};
103
104TEST_F(TestUserMgr, ldapEntryDoesNotExist)
105{
106 std::string userName = "user";
107 UserInfoMap userInfo;
108
Alexander Filippov75626582022-02-09 18:42:37 +0300109 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
110 .WillRepeatedly(Throw(UserNameDoesNotExist()));
111 EXPECT_THROW(userInfo = mockManager.getUserInfo(userName),
112 UserNameDoesNotExist);
raviteja-b8cc44052019-02-27 23:29:36 -0600113}
114
115TEST_F(TestUserMgr, localUser)
116{
117 UserInfoMap userInfo;
118 std::string userName = "testUser";
119 std::string privilege = "priv-admin";
120 std::vector<std::string> groups{"testGroup"};
121 // Create local user
122 createLocalUser(userName, groups, privilege, true);
123 EXPECT_CALL(mockManager, userLockedForFailedAttempt(userName)).Times(1);
124 userInfo = mockManager.getUserInfo(userName);
125
126 EXPECT_EQ(privilege, std::get<std::string>(userInfo["UserPrivilege"]));
127 EXPECT_EQ(groups,
128 std::get<std::vector<std::string>>(userInfo["UserGroups"]));
129 EXPECT_EQ(true, std::get<bool>(userInfo["UserEnabled"]));
130 EXPECT_EQ(false, std::get<bool>(userInfo["UserLockedForFailedAttempt"]));
Joseph Reynolds3ab6cc22020-03-03 14:09:03 -0600131 EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"]));
raviteja-b8cc44052019-02-27 23:29:36 -0600132 EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"]));
133}
Abhilash Raju0e427be2025-03-03 12:11:39 +0000134TEST_F(TestUserMgr, mfaEnabled)
135{
136 auto ret =
137 mockManager.enabled(MultiFactorAuthType::GoogleAuthenticator, false);
138 EXPECT_EQ(ret, MultiFactorAuthType::GoogleAuthenticator);
139 EXPECT_EQ(ret, mockManager.enabled());
140
141 ret = mockManager.enabled(MultiFactorAuthType::None, false);
142 EXPECT_EQ(ret, MultiFactorAuthType::None);
143 EXPECT_EQ(ret, mockManager.enabled());
144}
145TEST_F(TestUserMgr, mfaDefaultUser)
146{
147 std::string userName = "testUser";
148 std::string privilege = "priv-admin";
149 std::vector<std::string> groups{"testGroup"};
150 // Create local user
151 createLocalUser(userName, groups, privilege, true);
152 auto user = mockManager.getUserObject(userName);
153 EXPECT_EQ(user->secretKeyIsValid(), false);
154}
155TEST_F(TestUserMgr, mfaCreateSecretKeyEnableMFA)
156{
157 std::string userName = "testUser";
158 std::string privilege = "priv-admin";
159 std::vector<std::string> groups{"testGroup"};
160 // Create local user
161 createLocalUser(userName, groups, privilege, true);
162 MockUser* user =
163 static_cast<MockUser*>(mockManager.getUserObject(userName));
164 EXPECT_EQ(user->secretKeyIsValid(), false);
165 auto ret =
166 mockManager.enabled(MultiFactorAuthType::GoogleAuthenticator, true);
167 EXPECT_EQ(ret, MultiFactorAuthType::GoogleAuthenticator);
168 ON_CALL(*user, createSecretKey).WillByDefault(testing::Return("SKJDY&@H"));
169 user->createSecretKey();
170 EXPECT_EQ(user->secretKeyIsValid(), false);
171}
172TEST_F(TestUserMgr, bypassMFA)
173{
174 std::string userName = "testUser";
175 std::string privilege = "priv-admin";
176 std::vector<std::string> groups{"testGroup"};
177 // Create local user
178 createLocalUser(userName, groups, privilege, true);
179 MockUser* user =
180 static_cast<MockUser*>(mockManager.getUserObject(userName));
181 mockManager.enabled(MultiFactorAuthType::GoogleAuthenticator, true);
182 user->bypassedProtocol(MultiFactorAuthType::GoogleAuthenticator, false);
183 EXPECT_EQ(user->secretKeyGenerationRequired(), false);
184 user->bypassedProtocol(MultiFactorAuthType::None, false);
185 EXPECT_EQ(user->secretKeyGenerationRequired(), true);
186}
raviteja-b8cc44052019-02-27 23:29:36 -0600187
188TEST_F(TestUserMgr, ldapUserWithPrivMapper)
189{
190 UserInfoMap userInfo;
191 std::string userName = "ldapUser";
192 std::string ldapGroup = "ldapGroup";
Alexander Filippov75626582022-02-09 18:42:37 +0300193 gid_t primaryGid = 1000;
raviteja-b8cc44052019-02-27 23:29:36 -0600194
Alexander Filippov75626582022-02-09 18:42:37 +0300195 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
196 .WillRepeatedly(Return(primaryGid));
raviteja-b8cc44052019-02-27 23:29:36 -0600197 // Create privilege mapper dbus object
198 DbusUserObj object = createPrivilegeMapperDbusObject();
199 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
200 .WillRepeatedly(Return(object));
Alexander Filippov75626582022-02-09 18:42:37 +0300201 EXPECT_CALL(mockManager, isGroupMember(userName, primaryGid, ldapGroup))
202 .WillRepeatedly(Return(true));
raviteja-b8cc44052019-02-27 23:29:36 -0600203 userInfo = mockManager.getUserInfo(userName);
204 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
205 EXPECT_EQ("priv-admin", std::get<std::string>(userInfo["UserPrivilege"]));
206}
207
208TEST_F(TestUserMgr, ldapUserWithoutPrivMapper)
209{
Alexander Filippov75626582022-02-09 18:42:37 +0300210 using ::testing::_;
211
raviteja-b8cc44052019-02-27 23:29:36 -0600212 UserInfoMap userInfo;
213 std::string userName = "ldapUser";
214 std::string ldapGroup = "ldapGroup";
Alexander Filippov75626582022-02-09 18:42:37 +0300215 gid_t primaryGid = 1000;
raviteja-b8cc44052019-02-27 23:29:36 -0600216
Alexander Filippov75626582022-02-09 18:42:37 +0300217 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
218 .WillRepeatedly(Return(primaryGid));
Ravi Teja5fe724a2019-05-07 05:14:42 -0500219 // Create LDAP config object without privilege mapper
220 DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper();
raviteja-b8cc44052019-02-27 23:29:36 -0600221 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
222 .WillRepeatedly(Return(object));
Alexander Filippov75626582022-02-09 18:42:37 +0300223 EXPECT_CALL(mockManager, isGroupMember(_, _, _)).Times(0);
raviteja-b8cc44052019-02-27 23:29:36 -0600224 userInfo = mockManager.getUserInfo(userName);
225 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
Jiaqing Zhao56862062022-05-31 19:16:09 +0800226 EXPECT_EQ("priv-user", std::get<std::string>(userInfo["UserPrivilege"]));
raviteja-b8cc44052019-02-27 23:29:36 -0600227}
Nan Zhoue47c09d2022-10-25 00:06:41 +0000228
229TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString)
230{
231 EXPECT_EQ(getCSVFromVector({}), "");
232}
233
234TEST(GetCSVFromVector, ElementsAreJoinedByComma)
235{
236 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123"}), "123");
237 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123", "456"}),
238 "123,456");
239}
240
Nan Zhou332fb9d2022-10-25 00:07:03 +0000241TEST(RemoveStringFromCSV, WithoutDeleteStringReturnsFalse)
242{
243 std::string expected = "whatever,https";
244 std::string str = expected;
245 EXPECT_FALSE(removeStringFromCSV(str, "ssh"));
246 EXPECT_EQ(str, expected);
247
248 std::string empty;
249 EXPECT_FALSE(removeStringFromCSV(empty, "ssh"));
250}
251
252TEST(RemoveStringFromCSV, WithDeleteStringReturnsTrue)
253{
254 std::string expected = "whatever";
255 std::string str = "whatever,https";
256 EXPECT_TRUE(removeStringFromCSV(str, "https"));
257 EXPECT_EQ(str, expected);
258
259 str = "https";
260 EXPECT_TRUE(removeStringFromCSV(str, "https"));
261 EXPECT_EQ(str, "");
262}
263
Nan Zhoue48085d2022-10-25 00:07:04 +0000264namespace
265{
266inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user";
267
Jason M. Bills2d042d12023-03-28 15:32:45 -0700268// Fake configs; referenced configs on real BMC
Jason M. Bills2d042d12023-03-28 15:32:45 -0700269inline constexpr const char* rawFailLockConfig = R"(
270deny=2
271unlock_time=3
272)";
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700273inline constexpr const char* rawPWHistoryConfig = R"(
274enforce_for_root
275remember=0
276)";
Jason M. Bills2d042d12023-03-28 15:32:45 -0700277inline constexpr const char* rawPWQualityConfig = R"(
278enforce_for_root
279minlen=8
280difok=0
281lcredit=0
282ocredit=0
283dcredit=0
284ucredit=0
285)";
Nan Zhoue48085d2022-10-25 00:07:04 +0000286} // namespace
287
288void dumpStringToFile(const std::string& str, const std::string& filePath)
289{
290 std::ofstream outputFileStream;
291
Patrick Williams16c2b682024-08-16 15:20:56 -0400292 outputFileStream.exceptions(
293 std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
Nan Zhoue48085d2022-10-25 00:07:04 +0000294
295 outputFileStream.open(filePath, std::ios::out);
296 outputFileStream << str << "\n" << std::flush;
297 outputFileStream.close();
298}
299
300void removeFile(const std::string& filePath)
301{
302 std::filesystem::remove(filePath);
303}
304
305class UserMgrInTest : public testing::Test, public UserMgr
306{
307 public:
308 UserMgrInTest() : UserMgr(busInTest, objectRootInTest)
309 {
Jason M. Bills2d042d12023-03-28 15:32:45 -0700310 tempFaillockConfigFile = "/tmp/test-data-XXXXXX";
311 mktemp(tempFaillockConfigFile.data());
312 EXPECT_NO_THROW(
313 dumpStringToFile(rawFailLockConfig, tempFaillockConfigFile));
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700314 tempPWHistoryConfigFile = "/tmp/test-data-XXXXXX";
315 mktemp(tempPWHistoryConfigFile.data());
316 EXPECT_NO_THROW(
317 dumpStringToFile(rawPWHistoryConfig, tempPWHistoryConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700318 tempPWQualityConfigFile = "/tmp/test-data-XXXXXX";
319 mktemp(tempPWQualityConfigFile.data());
320 EXPECT_NO_THROW(
321 dumpStringToFile(rawPWQualityConfig, tempPWQualityConfigFile));
Nan Zhoue48085d2022-10-25 00:07:04 +0000322 // Set config files to test files
Jason M. Bills2d042d12023-03-28 15:32:45 -0700323 faillockConfigFile = tempFaillockConfigFile;
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700324 pwHistoryConfigFile = tempPWHistoryConfigFile;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700325 pwQualityConfigFile = tempPWQualityConfigFile;
Nan Zhou49c81362022-10-25 00:07:08 +0000326
Denis Zlobine8edab52023-09-06 12:26:45 +0000327 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
328 testing::Eq(true)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500329 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400330 ON_CALL(*this, isUserEnabled)
331 .WillByDefault(testing::Return(true));
332 testing::Return();
333 });
Denis Zlobine8edab52023-09-06 12:26:45 +0000334
335 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
336 testing::Eq(false)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500337 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400338 ON_CALL(*this, isUserEnabled)
339 .WillByDefault(testing::Return(false));
340 testing::Return();
341 });
Nan Zhou49c81362022-10-25 00:07:08 +0000342
343 ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return());
344
Jayanth Othayothac921a52023-07-21 03:48:55 -0500345 ON_CALL(*this, executeUserClearFailRecords)
346 .WillByDefault(testing::Return());
347
Nan Zhou49c81362022-10-25 00:07:08 +0000348 ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0));
Nan Zhouf25443e2022-10-25 00:07:11 +0000349
350 ON_CALL(*this, executeUserRename).WillByDefault(testing::Return());
Nan Zhoufef63032022-10-25 00:07:12 +0000351
352 ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_))
353 .WillByDefault(testing::Return());
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000354
Denis Zlobine8edab52023-09-06 12:26:45 +0000355 ON_CALL(*this,
356 executeUserModifyUserEnable(testing::_, testing::Eq(true)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500357 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400358 ON_CALL(*this, isUserEnabled)
359 .WillByDefault(testing::Return(true));
360 testing::Return();
361 });
Denis Zlobine8edab52023-09-06 12:26:45 +0000362
363 ON_CALL(*this,
364 executeUserModifyUserEnable(testing::_, testing::Eq(false)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500365 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400366 ON_CALL(*this, isUserEnabled)
367 .WillByDefault(testing::Return(false));
368 testing::Return();
369 });
Nan Zhouda401fe2022-10-25 00:07:18 +0000370
371 ON_CALL(*this, executeGroupCreation(testing::_))
372 .WillByDefault(testing::Return());
373
374 ON_CALL(*this, executeGroupDeletion(testing::_))
375 .WillByDefault(testing::Return());
376
377 ON_CALL(*this, executeGroupCreation).WillByDefault(testing::Return());
378
379 ON_CALL(*this, executeGroupDeletion).WillByDefault(testing::Return());
Nan Zhoue48085d2022-10-25 00:07:04 +0000380 }
381
382 ~UserMgrInTest() override
383 {
Jason M. Bills2d042d12023-03-28 15:32:45 -0700384 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700385 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700386 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
Nan Zhoue48085d2022-10-25 00:07:04 +0000387 }
388
Nan Zhou49c81362022-10-25 00:07:08 +0000389 MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool),
390 (override));
391
392 MOCK_METHOD(void, executeUserDelete, (const char*), (override));
393
Jayanth Othayothac921a52023-07-21 03:48:55 -0500394 MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override));
395
Nan Zhou49c81362022-10-25 00:07:08 +0000396 MOCK_METHOD(size_t, getIpmiUsersCount, (), (override));
397
Nan Zhouf25443e2022-10-25 00:07:11 +0000398 MOCK_METHOD(void, executeUserRename, (const char*, const char*),
399 (override));
400
Nan Zhoufef63032022-10-25 00:07:12 +0000401 MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool),
402 (override));
403
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000404 MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool),
405 (override));
406
Nan Zhoua2953032022-11-11 21:50:32 +0000407 MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*),
408 (override));
409
Nan Zhouda401fe2022-10-25 00:07:18 +0000410 MOCK_METHOD(void, executeGroupCreation, (const char*), (override));
411
412 MOCK_METHOD(void, executeGroupDeletion, (const char*), (override));
413
Denis Zlobine8edab52023-09-06 12:26:45 +0000414 MOCK_METHOD(bool, isUserEnabled, (const std::string& userName), (override));
415
Nan Zhoufef63032022-10-25 00:07:12 +0000416 protected:
Nan Zhoue48085d2022-10-25 00:07:04 +0000417 static sdbusplus::bus_t busInTest;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700418 std::string tempFaillockConfigFile;
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700419 std::string tempPWHistoryConfigFile;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700420 std::string tempPWQualityConfigFile;
Nan Zhoue48085d2022-10-25 00:07:04 +0000421};
422
423sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
424
Jason M. Bills2d042d12023-03-28 15:32:45 -0700425TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
426{
427 std::string minlen;
428 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
429 0);
430 EXPECT_EQ(minlen, "8");
431 std::string deny;
432 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
433 EXPECT_EQ(deny, "2");
Jason M. Bills2d042d12023-03-28 15:32:45 -0700434 std::string remember;
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700435 EXPECT_EQ(
436 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
437 0);
438 EXPECT_EQ(remember, "0");
Jason M. Bills2d042d12023-03-28 15:32:45 -0700439}
440
441TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
442{
443 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
444 0);
445 std::string minlen;
446 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
447 0);
448 EXPECT_EQ(minlen, "16");
449
450 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
451 std::string deny;
452 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
453 EXPECT_EQ(deny, "3");
Nan Zhoue48085d2022-10-25 00:07:04 +0000454
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700455 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
456 0);
457 std::string remember;
458 EXPECT_EQ(
459 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
460 0);
461 EXPECT_EQ(remember, "1");
Jason M. Bills17b88272023-05-22 14:24:02 -0700462}
463
464TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
465{
466 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
467 0);
468
469 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
470 EXPECT_FALSE(std::filesystem::exists(tmpFile));
471
472 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
473
474 tmpFile = tempFaillockConfigFile + "_tmp";
475 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills17b88272023-05-22 14:24:02 -0700476
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700477 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
478 0);
Nan Zhoue48085d2022-10-25 00:07:04 +0000479
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700480 tmpFile = tempPWHistoryConfigFile + "_tmp";
481 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700482}
483
484TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
485{
486 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
487 std::string minlen;
488 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
489 -1);
490
491 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
492 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
493 -1);
494
495 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
496 std::string deny;
497 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
498
499 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
500 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000501
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700502 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
503 std::string remember;
504 EXPECT_EQ(
505 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
506 -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000507
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700508 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
509 EXPECT_EQ(
510 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
511 -1);
Jason M. Bills2d042d12023-03-28 15:32:45 -0700512}
513
514TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
515{
516 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
517 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
518 -1);
519
520 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
521 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
522 -1);
523
524 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
525 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
526
527 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
528 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000529
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700530 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
531 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
532 -1);
Jason M. Bills17b88272023-05-22 14:24:02 -0700533
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700534 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
535 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
536 -1);
Jason M. Bills17b88272023-05-22 14:24:02 -0700537}
538
539TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
540{
541 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
542 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
543 -1);
544
545 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
546 EXPECT_FALSE(std::filesystem::exists(tmpFile));
547
548 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
549 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
550 -1);
551
552 EXPECT_FALSE(std::filesystem::exists(tmpFile));
553
554 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
555 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
556
557 tmpFile = tempFaillockConfigFile + "_tmp";
558 EXPECT_FALSE(std::filesystem::exists(tmpFile));
559
560 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
561 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
562
563 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700564
565 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
566 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
567 -1);
568
569 tmpFile = tempPWHistoryConfigFile + "_tmp";
570 EXPECT_FALSE(std::filesystem::exists(tmpFile));
571
572 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
573 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
574 -1);
575
576 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills17b88272023-05-22 14:24:02 -0700577}
578
Nan Zhou8a11d992022-10-25 00:07:06 +0000579TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
580{
581 EXPECT_THROW(
582 isUserExist(""),
583 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
584}
585
586TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
587{
588 EXPECT_THROW(throwForUserDoesNotExist("whatever"),
589 sdbusplus::xyz::openbmc_project::User::Common::Error::
590 UserNameDoesNotExist);
591}
592
593TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
594{
595 EXPECT_THROW(
596 throwForUserExists("root"),
597 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
598}
599
Nan Zhou40e44972022-10-25 00:07:07 +0000600TEST_F(
601 UserMgrInTest,
602 ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)
603{
604 std::string strWith17Chars(17, 'A');
605 EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}),
606 sdbusplus::xyz::openbmc_project::User::Common::Error::
607 UserNameGroupFail);
608}
609
610TEST_F(
611 UserMgrInTest,
612 ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
613{
Malik Akbar Hashemi Rafsanjani27d56762025-03-12 03:19:52 -0700614 std::string strWith31Chars(101, 'A');
Nan Zhou40e44972022-10-25 00:07:07 +0000615 EXPECT_THROW(
616 throwForUserNameConstraints(strWith31Chars, {}),
617 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
618}
619
620TEST_F(UserMgrInTest,
621 ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
622{
623 std::string startWithNumber = "0ABC";
nichanghao.nchd9adc732024-01-17 20:24:17 +0800624 std::string startWithDisallowedCharacter = "[test";
Nan Zhou40e44972022-10-25 00:07:07 +0000625 EXPECT_THROW(
626 throwForUserNameConstraints(startWithNumber, {"ipmi"}),
627 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
nichanghao.nchd9adc732024-01-17 20:24:17 +0800628 EXPECT_THROW(
629 throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}),
630 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Nan Zhou40e44972022-10-25 00:07:07 +0000631}
632
Nan Zhou49c81362022-10-25 00:07:08 +0000633TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure)
634{
635 EXPECT_THROW(
636 UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true),
637 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
638}
639
640TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
641{
642 EXPECT_THROW(
643 UserMgr::executeUserDelete("user0"),
644 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
645}
646
647TEST_F(UserMgrInTest,
648 ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)
649{
650 EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers));
651 EXPECT_THROW(
652 throwForMaxGrpUserCount({"ipmi"}),
653 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
654}
655
656TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails)
657{
658 EXPECT_CALL(*this, executeUserAdd)
659 .WillOnce(testing::Throw(
660 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
661 EXPECT_THROW(
662 createUser("whatever", {"redfish"}, "", true),
663 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
664}
665
666TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)
667{
668 std::string username = "user";
669 EXPECT_NO_THROW(
670 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
671 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
672 .WillOnce(testing::Throw(
673 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
674 .WillOnce(testing::DoDefault());
675
676 EXPECT_THROW(
677 deleteUser(username),
678 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
679 EXPECT_NO_THROW(UserMgr::deleteUser(username));
680}
681
Jayanth Othayothac921a52023-07-21 03:48:55 -0500682TEST_F(UserMgrInTest,
683 DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)
684{
685 const char* username = "user";
686 EXPECT_NO_THROW(
687 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
688 EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username)))
689 .WillOnce(testing::Throw(
690 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
691 .WillOnce(testing::DoDefault());
692
693 EXPECT_THROW(
694 deleteUser(username),
695 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
696 EXPECT_NO_THROW(UserMgr::deleteUser(username));
697}
698
Nan Zhou589aeb42022-10-25 00:07:09 +0000699TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
700{
701 EXPECT_THROW(
702 throwForInvalidPrivilege("whatever"),
703 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
704}
705
706TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)
707{
708 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin"));
709 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator"));
710 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user"));
Nan Zhou589aeb42022-10-25 00:07:09 +0000711}
712
Nan Zhouecf88762022-10-25 00:07:10 +0000713TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
714{
715 EXPECT_THROW(
716 throwForInvalidGroups({"whatever"}),
717 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Ravi Teja4e2c06e2024-04-20 23:18:34 -0500718 EXPECT_THROW(
719 throwForInvalidGroups({"web"}),
720 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Nan Zhouecf88762022-10-25 00:07:10 +0000721}
722
723TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
724{
725 EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
726 EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
727 EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
Ninad Palsule601d3db2023-03-09 10:27:37 -0600728 EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
Nan Zhouecf88762022-10-25 00:07:10 +0000729}
730
Nan Zhouf25443e2022-10-25 00:07:11 +0000731TEST_F(UserMgrInTest, RenameUserOnSuccess)
732{
733 std::string username = "user001";
734 EXPECT_NO_THROW(
735 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
736 std::string newUsername = "user002";
737
738 EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername));
739
740 // old username doesn't exist
741 EXPECT_THROW(getUserInfo(username),
742 sdbusplus::xyz::openbmc_project::User::Common::Error::
743 UserNameDoesNotExist);
744
745 UserInfoMap userInfo = getUserInfo(newUsername);
746 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
747 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
748 testing::UnorderedElementsAre("redfish", "ssh"));
749 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
750
751 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
752}
753
754TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails)
755{
756 std::string username = "user001";
757 EXPECT_NO_THROW(
758 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
759 std::string newUsername = "user002";
760
761 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
762 testing::StrEq(newUsername)))
763 .WillOnce(testing::Throw(
764 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
765 EXPECT_THROW(
766 UserMgr::renameUser(username, newUsername),
767 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
768
769 // The original user is unchanged
770 UserInfoMap userInfo = getUserInfo(username);
771 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
772 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
773 testing::UnorderedElementsAre("redfish", "ssh"));
774 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
775
776 EXPECT_NO_THROW(UserMgr::deleteUser(username));
777}
778
779TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
780{
781 EXPECT_THROW(
782 UserMgr::executeUserRename("user0", "user1"),
783 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
Nan Zhoufef63032022-10-25 00:07:12 +0000784 EXPECT_THROW(
785 UserMgr::executeUserModify("user0", "ssh", true),
786 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
787}
788
789TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess)
790{
791 std::string username = "user001";
792 EXPECT_NO_THROW(
793 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
794 EXPECT_NO_THROW(
795 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"));
796 UserInfoMap userInfo = getUserInfo(username);
797 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin");
798 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
799 testing::UnorderedElementsAre("ipmi", "ssh"));
800 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
801 EXPECT_NO_THROW(UserMgr::deleteUser(username));
802}
803
804TEST_F(UserMgrInTest,
805 UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)
806{
807 std::string username = "user001";
808 EXPECT_NO_THROW(
809 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
810 EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_,
811 testing::_))
812 .WillOnce(testing::Throw(
813 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
814 EXPECT_THROW(
815 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"),
816 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
817 EXPECT_NO_THROW(UserMgr::deleteUser(username));
Nan Zhouf25443e2022-10-25 00:07:11 +0000818}
819
Nan Zhou18031012022-11-10 22:24:58 +0000820TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
821{
822 initializeAccountPolicy();
823 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
824 UserMgr::minPasswordLength(8);
825 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
826}
827
828TEST_F(UserMgrInTest,
829 MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)
830{
831 initializeAccountPolicy();
832 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
833 EXPECT_THROW(
834 UserMgr::minPasswordLength(minPasswdLength - 1),
835 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
836 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
837}
838
839TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
840{
841 initializeAccountPolicy();
842 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
843 UserMgr::minPasswordLength(16);
844 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
845}
846
847TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
848{
Jason M. Bills2d042d12023-03-28 15:32:45 -0700849 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
Nan Zhou18031012022-11-10 22:24:58 +0000850 initializeAccountPolicy();
851 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
852 EXPECT_THROW(
853 UserMgr::minPasswordLength(16),
854 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
855 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
856}
857
Nan Zhoua6ce1fa2022-10-25 00:07:14 +0000858TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame)
859{
860 initializeAccountPolicy();
861 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
862 UserMgr::rememberOldPasswordTimes(8);
863 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
864 UserMgr::rememberOldPasswordTimes(8);
865 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
866}
867
868TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
869{
870 initializeAccountPolicy();
871 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
872 UserMgr::rememberOldPasswordTimes(16);
873 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
874}
875
876TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
877{
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700878 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
Nan Zhoua6ce1fa2022-10-25 00:07:14 +0000879 initializeAccountPolicy();
880 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
881 EXPECT_THROW(
882 UserMgr::rememberOldPasswordTimes(16),
883 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
884 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
885}
886
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000887TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
888{
889 initializeAccountPolicy();
890 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
891 UserMgr::maxLoginAttemptBeforeLockout(2);
892 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
893}
894
895TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
896{
897 initializeAccountPolicy();
898 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
899 UserMgr::maxLoginAttemptBeforeLockout(16);
900 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
901}
902
903TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
904{
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000905 initializeAccountPolicy();
Jason M. Bills2d042d12023-03-28 15:32:45 -0700906 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000907 EXPECT_THROW(
908 UserMgr::maxLoginAttemptBeforeLockout(16),
909 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
Jason M. Bills2d042d12023-03-28 15:32:45 -0700910 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000911}
912
Nan Zhou784aecd2022-10-25 00:07:16 +0000913TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
914{
915 initializeAccountPolicy();
916 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
917 UserMgr::accountUnlockTimeout(3);
918 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
919}
920
921TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
922{
923 initializeAccountPolicy();
924 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
925 UserMgr::accountUnlockTimeout(16);
926 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
927}
928
929TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
930{
931 initializeAccountPolicy();
Jason M. Bills2d042d12023-03-28 15:32:45 -0700932 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
Nan Zhou784aecd2022-10-25 00:07:16 +0000933 EXPECT_THROW(
934 UserMgr::accountUnlockTimeout(16),
935 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
936 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
937}
938
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000939TEST_F(UserMgrInTest, UserEnableOnSuccess)
940{
941 std::string username = "user001";
942 EXPECT_NO_THROW(
943 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
944 UserInfoMap userInfo = getUserInfo(username);
945 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
946
947 EXPECT_NO_THROW(userEnable(username, false));
948
949 userInfo = getUserInfo(username);
950 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false);
951
952 EXPECT_NO_THROW(UserMgr::deleteUser(username));
953}
954
Ninad Palsule601d3db2023-03-09 10:27:37 -0600955TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole)
956{
957 std::string username = "user001";
958 EXPECT_NO_THROW(
959 UserMgr::createUser(username, {"hostconsole"}, "priv-user", true));
960 EXPECT_NO_THROW(UserMgr::deleteUser(username));
961 EXPECT_NO_THROW(
962 UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true));
963 EXPECT_NO_THROW(UserMgr::deleteUser(username));
964 EXPECT_NO_THROW(
965 UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true));
966 EXPECT_NO_THROW(UserMgr::deleteUser(username));
967}
968
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000969TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail)
970{
971 std::string username = "user001";
972 EXPECT_NO_THROW(
973 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
974 UserInfoMap userInfo = getUserInfo(username);
975 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
976
977 EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username),
978 testing::Eq(false)))
979 .WillOnce(testing::Throw(
980 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
981 EXPECT_THROW(
982 userEnable(username, false),
983 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
984
985 userInfo = getUserInfo(username);
986 // Stay unchanged
987 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
988
989 EXPECT_NO_THROW(UserMgr::deleteUser(username));
990}
991
Nan Zhoua2953032022-11-11 21:50:32 +0000992TEST_F(
993 UserMgrInTest,
994 UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
995{
996 EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
997}
998
999TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
1000{
1001 std::string username = "user001";
1002 initializeAccountPolicy();
1003 // Example output from BMC
Jason M. Bills2d042d12023-03-28 15:32:45 -07001004 // root:~# faillock --user root
1005 // root:
1006 // When Type Source Valid
1007 std::vector<std::string> output = {"whatever",
1008 "When Type Source Valid"};
Nan Zhoua2953032022-11-11 21:50:32 +00001009 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1010 .WillOnce(testing::Return(output));
1011
1012 EXPECT_FALSE(userLockedForFailedAttempt(username));
1013}
1014
1015TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail)
1016{
1017 std::string username = "user001";
1018 initializeAccountPolicy();
1019 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1020 .WillOnce(testing::Throw(
1021 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1022
1023 EXPECT_THROW(
1024 userLockedForFailedAttempt(username),
1025 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1026}
1027
1028TEST_F(UserMgrInTest,
Nan Zhoua2953032022-11-11 21:50:32 +00001029 UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
1030{
1031 std::string username = "user001";
1032 initializeAccountPolicy();
1033
1034 // Choose a date in the past.
1035 std::vector<std::string> output = {"whatever",
Jason M. Bills2d042d12023-03-28 15:32:45 -07001036 "10/24/2002 00:00:00 type source V"};
Nan Zhoua2953032022-11-11 21:50:32 +00001037 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1038 .WillOnce(testing::Return(output));
1039
1040 EXPECT_THROW(
1041 userLockedForFailedAttempt(username),
1042 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1043}
1044
1045TEST_F(UserMgrInTest,
1046 UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)
1047{
1048 std::string username = "user001";
1049 initializeAccountPolicy();
1050
1051 // Choose a date in the past.
1052 std::vector<std::string> output = {"whatever",
Jason M. Bills2d042d12023-03-28 15:32:45 -07001053 "2002-10-24 00:00:00 type source V"};
Nan Zhoua2953032022-11-11 21:50:32 +00001054 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1055 .WillOnce(testing::Return(output));
1056
1057 EXPECT_EQ(userLockedForFailedAttempt(username), false);
1058}
1059
Nan Zhouda401fe2022-10-25 00:07:18 +00001060TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess)
1061{
1062 // Base Redfish Roles
1063 EXPECT_NO_THROW(
1064 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator"));
1065 EXPECT_NO_THROW(
1066 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator"));
1067 EXPECT_NO_THROW(
1068 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly"));
1069 // Base Redfish Privileges
1070 EXPECT_NO_THROW(
1071 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login"));
1072 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1073 "openbmc_rfp_ConfigureManager"));
1074 EXPECT_NO_THROW(
1075 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers"));
1076 EXPECT_NO_THROW(
1077 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf"));
1078 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1079 "openbmc_rfp_ConfigureComponents"));
1080 // OEM Redfish Roles
1081 EXPECT_NO_THROW(
1082 checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService"));
1083 // OEM Redfish Privileges
1084 EXPECT_NO_THROW(
1085 checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService"));
1086}
1087
1088TEST_F(UserMgrInTest,
1089 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)
1090{
1091 std::string groupName(maxSystemGroupNameLength + 1, 'A');
1092 EXPECT_THROW(
1093 checkAndThrowForDisallowedGroupCreation(groupName),
1094 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1095}
1096
1097TEST_F(
1098 UserMgrInTest,
1099 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1100{
Nan Zhouda401fe2022-10-25 00:07:18 +00001101 EXPECT_THROW(
1102 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"),
1103 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1104 EXPECT_THROW(
1105 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"),
1106 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1107}
1108
1109TEST_F(
1110 UserMgrInTest,
1111 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1112{
Nan Zhouda401fe2022-10-25 00:07:18 +00001113 EXPECT_THROW(
1114 checkAndThrowForDisallowedGroupCreation("google_rfp_"),
1115 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1116 EXPECT_THROW(
1117 checkAndThrowForDisallowedGroupCreation("com_rfp_"),
1118 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1119}
1120
1121TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1122{
Ravi Teja4e2c06e2024-04-20 23:18:34 -05001123 constexpr size_t predefGroupCount = 4;
Ninad Palsule601d3db2023-03-09 10:27:37 -06001124
1125 EXPECT_THAT(allGroups().size(), predefGroupCount);
1126 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
Nan Zhouda401fe2022-10-25 00:07:18 +00001127 {
1128 std::string groupName = "openbmc_rfr_role";
1129 groupName += std::to_string(i);
1130 EXPECT_NO_THROW(createGroup(groupName));
1131 }
1132 EXPECT_THROW(
1133 createGroup("openbmc_rfr_AnotherRole"),
1134 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
Ninad Palsule601d3db2023-03-09 10:27:37 -06001135 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
Nan Zhouda401fe2022-10-25 00:07:18 +00001136 {
1137 std::string groupName = "openbmc_rfr_role";
1138 groupName += std::to_string(i);
1139 EXPECT_NO_THROW(deleteGroup(groupName));
1140 }
1141}
1142
1143TEST_F(UserMgrInTest, CheckAndThrowForGroupExist)
1144{
1145 std::string groupName = "openbmc_rfr_role";
1146 EXPECT_NO_THROW(createGroup(groupName));
1147 EXPECT_THROW(
1148 createGroup(groupName),
1149 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1150 EXPECT_NO_THROW(deleteGroup(groupName));
1151}
1152
1153TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1154{
Ravi Teja4e2c06e2024-04-20 23:18:34 -05001155 EXPECT_THAT(allGroups(), testing::UnorderedElementsAre(
1156 "redfish", "ipmi", "ssh", "hostconsole"));
Ninad Palsule601d3db2023-03-09 10:27:37 -06001157}
1158
1159TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1160{
1161 EXPECT_THROW(
1162 createGroup("ipmi"),
1163 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1164 EXPECT_THROW(
Ninad Palsule601d3db2023-03-09 10:27:37 -06001165 createGroup("redfish"),
1166 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1167 EXPECT_THROW(
1168 createGroup("ssh"),
1169 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1170 EXPECT_THROW(
1171 createGroup("hostconsole"),
1172 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
Nan Zhouda401fe2022-10-25 00:07:18 +00001173}
1174
1175TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1176{
1177 EXPECT_THROW(
1178 deleteGroup("ipmi"),
1179 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1180 EXPECT_THROW(
Nan Zhouda401fe2022-10-25 00:07:18 +00001181 deleteGroup("redfish"),
1182 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1183 EXPECT_THROW(
1184 deleteGroup("ssh"),
1185 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Ninad Palsule601d3db2023-03-09 10:27:37 -06001186 EXPECT_THROW(
1187 deleteGroup("hostconsole"),
1188 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Nan Zhouda401fe2022-10-25 00:07:18 +00001189}
1190
1191TEST_F(UserMgrInTest,
1192 CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)
1193{
1194 EXPECT_CALL(*this, executeGroupCreation)
1195 .WillOnce(testing::Throw(
1196 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1197 EXPECT_THROW(
1198 createGroup("openbmc_rfr_role1"),
1199 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1200}
1201
1202TEST_F(UserMgrInTest,
1203 DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)
1204{
1205 std::string groupName = "openbmc_rfr_role1";
1206 EXPECT_NO_THROW(UserMgr::createGroup(groupName));
1207 EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName)))
1208 .WillOnce(testing::Throw(
1209 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1210 .WillOnce(testing::DoDefault());
1211
1212 EXPECT_THROW(
1213 deleteGroup(groupName),
1214 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1215 EXPECT_NO_THROW(UserMgr::deleteGroup(groupName));
1216}
1217
1218TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1219{
1220 EXPECT_THROW(deleteGroup("whatever"),
1221 sdbusplus::xyz::openbmc_project::User::Common::Error::
1222 GroupNameDoesNotExist);
1223}
1224
1225TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1226{
Ravi Teja4e2c06e2024-04-20 23:18:34 -05001227 EXPECT_THAT(
1228 UserMgr::readAllGroupsOnSystem(),
1229 testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole"));
Nan Zhouda401fe2022-10-25 00:07:18 +00001230}
1231
raviteja-b8cc44052019-02-27 23:29:36 -06001232} // namespace user
1233} // namespace phosphor