blob: 9e55fc85fc59fd91d1fcc92a0d4b65fa347d991a [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
Patrick Williams0af827c2025-07-02 16:53:03 -04004#include <unistd.h>
5
Ravi Teja417c0892020-08-22 08:04:01 -05006#include <sdbusplus/test/sdbus_mock.hpp>
Patrick Williams9638afb2021-02-22 17:16:24 -06007#include <xyz/openbmc_project/Common/error.hpp>
8#include <xyz/openbmc_project/User/Common/error.hpp>
9
10#include <exception>
Nan Zhoue48085d2022-10-25 00:07:04 +000011#include <filesystem>
12#include <fstream>
Nan Zhouda401fe2022-10-25 00:07:18 +000013#include <vector>
Patrick Williams9638afb2021-02-22 17:16:24 -060014
Nan Zhouda401fe2022-10-25 00:07:18 +000015#include <gmock/gmock.h>
Patrick Williams9638afb2021-02-22 17:16:24 -060016#include <gtest/gtest.h>
raviteja-b8cc44052019-02-27 23:29:36 -060017
18namespace phosphor
19{
20namespace user
21{
22
23using ::testing::Return;
Alexander Filippov75626582022-02-09 18:42:37 +030024using ::testing::Throw;
raviteja-b8cc44052019-02-27 23:29:36 -060025
26using InternalFailure =
27 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Alexander Filippov75626582022-02-09 18:42:37 +030028using UserNameDoesNotExist =
29 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameDoesNotExist;
raviteja-b8cc44052019-02-27 23:29:36 -060030
31class TestUserMgr : public testing::Test
32{
33 public:
Nan Zhou78d85042022-08-29 17:50:22 +000034 sdbusplus::SdBusMock sdBusMock;
Patrick Williamsb3ef4e12022-07-22 19:26:55 -050035 sdbusplus::bus_t bus;
raviteja-b8cc44052019-02-27 23:29:36 -060036 MockManager mockManager;
37
38 TestUserMgr() :
Nan Zhou78d85042022-08-29 17:50:22 +000039 bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath)
Patrick Williams9638afb2021-02-22 17:16:24 -060040 {}
raviteja-b8cc44052019-02-27 23:29:36 -060041
Patrick Williams9638afb2021-02-22 17:16:24 -060042 void createLocalUser(const std::string& userName,
raviteja-b8cc44052019-02-27 23:29:36 -060043 std::vector<std::string> groupNames,
Patrick Williams9638afb2021-02-22 17:16:24 -060044 const std::string& priv, bool enabled)
raviteja-b8cc44052019-02-27 23:29:36 -060045 {
P Dheeraj Srujan Kumarb01e2fe2021-12-13 09:43:28 +053046 sdbusplus::message::object_path tempObjPath(usersObjPath);
47 tempObjPath /= userName;
48 std::string userObj(tempObjPath);
Denis Zlobine8edab52023-09-06 12:26:45 +000049 if (enabled)
50 {
51 ON_CALL(mockManager, isUserEnabled)
52 .WillByDefault(testing::Return(true));
53 }
54 else
55 {
56 ON_CALL(mockManager, isUserEnabled)
57 .WillByDefault(testing::Return(false));
58 }
raviteja-b8cc44052019-02-27 23:29:36 -060059 mockManager.usersList.emplace(
Ravi Teja4a263202025-04-04 09:19:56 -050060 userName, std::make_unique<phosphor::user::Users>(
61 mockManager.bus, userObj.c_str(), groupNames, priv,
62 enabled, mockManager));
raviteja-b8cc44052019-02-27 23:29:36 -060063 }
64
65 DbusUserObj createPrivilegeMapperDbusObject(void)
66 {
67 DbusUserObj object;
68 DbusUserObjValue objValue;
Ravi Teja5fe724a2019-05-07 05:14:42 -050069
Nan Zhou78d85042022-08-29 17:50:22 +000070 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
Ravi Teja5fe724a2019-05-07 05:14:42 -050071 DbusUserPropVariant enabled(true);
72 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
73 std::string intf = "xyz.openbmc_project.Object.Enable";
74 objValue.emplace(intf, property);
Nan Zhou78d85042022-08-29 17:50:22 +000075 object.emplace(objPath, objValue);
Ravi Teja5fe724a2019-05-07 05:14:42 -050076
Nan Zhou78d85042022-08-29 17:50:22 +000077 DbusUserObjPath objectPath(
Ravi Teja5fe724a2019-05-07 05:14:42 -050078 "/xyz/openbmc_project/user/ldap/openldap/role_map/1");
79 std::string group = "ldapGroup";
80 std::string priv = "priv-admin";
raviteja-b8cc44052019-02-27 23:29:36 -060081 DbusUserObjProperties properties = {std::make_pair("GroupName", group),
82 std::make_pair("Privilege", priv)};
83 std::string interface = "xyz.openbmc_project.User.PrivilegeMapperEntry";
84
85 objValue.emplace(interface, properties);
Nan Zhou78d85042022-08-29 17:50:22 +000086 object.emplace(objectPath, objValue);
raviteja-b8cc44052019-02-27 23:29:36 -060087
88 return object;
89 }
Ravi Teja5fe724a2019-05-07 05:14:42 -050090
91 DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void)
92 {
93 DbusUserObj object;
94 DbusUserObjValue objValue;
95
Nan Zhou78d85042022-08-29 17:50:22 +000096 DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
Ravi Teja5fe724a2019-05-07 05:14:42 -050097 DbusUserPropVariant enabled(true);
98 DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
99 std::string intf = "xyz.openbmc_project.Object.Enable";
100 objValue.emplace(intf, property);
Nan Zhou78d85042022-08-29 17:50:22 +0000101 object.emplace(objPath, objValue);
Ravi Teja5fe724a2019-05-07 05:14:42 -0500102 return object;
103 }
raviteja-b8cc44052019-02-27 23:29:36 -0600104};
105
106TEST_F(TestUserMgr, ldapEntryDoesNotExist)
107{
108 std::string userName = "user";
109 UserInfoMap userInfo;
110
Alexander Filippov75626582022-02-09 18:42:37 +0300111 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
112 .WillRepeatedly(Throw(UserNameDoesNotExist()));
113 EXPECT_THROW(userInfo = mockManager.getUserInfo(userName),
114 UserNameDoesNotExist);
raviteja-b8cc44052019-02-27 23:29:36 -0600115}
116
117TEST_F(TestUserMgr, localUser)
118{
119 UserInfoMap userInfo;
120 std::string userName = "testUser";
121 std::string privilege = "priv-admin";
122 std::vector<std::string> groups{"testGroup"};
123 // Create local user
124 createLocalUser(userName, groups, privilege, true);
125 EXPECT_CALL(mockManager, userLockedForFailedAttempt(userName)).Times(1);
126 userInfo = mockManager.getUserInfo(userName);
127
128 EXPECT_EQ(privilege, std::get<std::string>(userInfo["UserPrivilege"]));
129 EXPECT_EQ(groups,
130 std::get<std::vector<std::string>>(userInfo["UserGroups"]));
131 EXPECT_EQ(true, std::get<bool>(userInfo["UserEnabled"]));
132 EXPECT_EQ(false, std::get<bool>(userInfo["UserLockedForFailedAttempt"]));
Joseph Reynolds3ab6cc22020-03-03 14:09:03 -0600133 EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"]));
raviteja-b8cc44052019-02-27 23:29:36 -0600134 EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"]));
135}
136
137TEST_F(TestUserMgr, ldapUserWithPrivMapper)
138{
139 UserInfoMap userInfo;
140 std::string userName = "ldapUser";
141 std::string ldapGroup = "ldapGroup";
Alexander Filippov75626582022-02-09 18:42:37 +0300142 gid_t primaryGid = 1000;
raviteja-b8cc44052019-02-27 23:29:36 -0600143
Alexander Filippov75626582022-02-09 18:42:37 +0300144 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
145 .WillRepeatedly(Return(primaryGid));
raviteja-b8cc44052019-02-27 23:29:36 -0600146 // Create privilege mapper dbus object
147 DbusUserObj object = createPrivilegeMapperDbusObject();
148 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
149 .WillRepeatedly(Return(object));
Alexander Filippov75626582022-02-09 18:42:37 +0300150 EXPECT_CALL(mockManager, isGroupMember(userName, primaryGid, ldapGroup))
151 .WillRepeatedly(Return(true));
raviteja-b8cc44052019-02-27 23:29:36 -0600152 userInfo = mockManager.getUserInfo(userName);
153 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
154 EXPECT_EQ("priv-admin", std::get<std::string>(userInfo["UserPrivilege"]));
155}
156
157TEST_F(TestUserMgr, ldapUserWithoutPrivMapper)
158{
Alexander Filippov75626582022-02-09 18:42:37 +0300159 using ::testing::_;
160
raviteja-b8cc44052019-02-27 23:29:36 -0600161 UserInfoMap userInfo;
162 std::string userName = "ldapUser";
163 std::string ldapGroup = "ldapGroup";
Alexander Filippov75626582022-02-09 18:42:37 +0300164 gid_t primaryGid = 1000;
raviteja-b8cc44052019-02-27 23:29:36 -0600165
Alexander Filippov75626582022-02-09 18:42:37 +0300166 EXPECT_CALL(mockManager, getPrimaryGroup(userName))
167 .WillRepeatedly(Return(primaryGid));
Ravi Teja5fe724a2019-05-07 05:14:42 -0500168 // Create LDAP config object without privilege mapper
169 DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper();
raviteja-b8cc44052019-02-27 23:29:36 -0600170 EXPECT_CALL(mockManager, getPrivilegeMapperObject())
171 .WillRepeatedly(Return(object));
Alexander Filippov75626582022-02-09 18:42:37 +0300172 EXPECT_CALL(mockManager, isGroupMember(_, _, _)).Times(0);
raviteja-b8cc44052019-02-27 23:29:36 -0600173 userInfo = mockManager.getUserInfo(userName);
174 EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
Jiaqing Zhao56862062022-05-31 19:16:09 +0800175 EXPECT_EQ("priv-user", std::get<std::string>(userInfo["UserPrivilege"]));
raviteja-b8cc44052019-02-27 23:29:36 -0600176}
Nan Zhoue47c09d2022-10-25 00:06:41 +0000177
178TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString)
179{
180 EXPECT_EQ(getCSVFromVector({}), "");
181}
182
183TEST(GetCSVFromVector, ElementsAreJoinedByComma)
184{
185 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123"}), "123");
186 EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123", "456"}),
187 "123,456");
188}
189
Nan Zhou332fb9d2022-10-25 00:07:03 +0000190TEST(RemoveStringFromCSV, WithoutDeleteStringReturnsFalse)
191{
192 std::string expected = "whatever,https";
193 std::string str = expected;
194 EXPECT_FALSE(removeStringFromCSV(str, "ssh"));
195 EXPECT_EQ(str, expected);
196
197 std::string empty;
198 EXPECT_FALSE(removeStringFromCSV(empty, "ssh"));
199}
200
201TEST(RemoveStringFromCSV, WithDeleteStringReturnsTrue)
202{
203 std::string expected = "whatever";
204 std::string str = "whatever,https";
205 EXPECT_TRUE(removeStringFromCSV(str, "https"));
206 EXPECT_EQ(str, expected);
207
208 str = "https";
209 EXPECT_TRUE(removeStringFromCSV(str, "https"));
210 EXPECT_EQ(str, "");
211}
212
Nan Zhoue48085d2022-10-25 00:07:04 +0000213namespace
214{
215inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user";
216
Jason M. Bills2d042d12023-03-28 15:32:45 -0700217// Fake configs; referenced configs on real BMC
Jason M. Bills2d042d12023-03-28 15:32:45 -0700218inline constexpr const char* rawFailLockConfig = R"(
219deny=2
220unlock_time=3
221)";
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700222inline constexpr const char* rawPWHistoryConfig = R"(
223enforce_for_root
224remember=0
225)";
Jason M. Bills2d042d12023-03-28 15:32:45 -0700226inline constexpr const char* rawPWQualityConfig = R"(
227enforce_for_root
228minlen=8
229difok=0
230lcredit=0
231ocredit=0
232dcredit=0
233ucredit=0
234)";
Nan Zhoue48085d2022-10-25 00:07:04 +0000235} // namespace
236
237void dumpStringToFile(const std::string& str, const std::string& filePath)
238{
239 std::ofstream outputFileStream;
240
Patrick Williams16c2b682024-08-16 15:20:56 -0400241 outputFileStream.exceptions(
242 std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
Nan Zhoue48085d2022-10-25 00:07:04 +0000243
244 outputFileStream.open(filePath, std::ios::out);
245 outputFileStream << str << "\n" << std::flush;
246 outputFileStream.close();
247}
248
249void removeFile(const std::string& filePath)
250{
251 std::filesystem::remove(filePath);
252}
253
254class UserMgrInTest : public testing::Test, public UserMgr
255{
256 public:
257 UserMgrInTest() : UserMgr(busInTest, objectRootInTest)
258 {
Patrick Williams0af827c2025-07-02 16:53:03 -0400259 {
260 tempFaillockConfigFile = tempFilePath;
261 int fd = mkstemp(tempFaillockConfigFile.data());
262 EXPECT_NE(-1, fd);
263 EXPECT_NO_THROW(
264 dumpStringToFile(rawFailLockConfig, tempFaillockConfigFile));
265 if (fd != -1)
266 {
267 close(fd);
268 }
269 }
270
271 {
272 tempPWHistoryConfigFile = tempFilePath;
273 int fd = mkstemp(tempPWHistoryConfigFile.data());
274 EXPECT_NE(-1, fd);
275 EXPECT_NO_THROW(
276 dumpStringToFile(rawPWHistoryConfig, tempPWHistoryConfigFile));
277 if (fd != -1)
278 {
279 close(fd);
280 }
281 }
282
283 {
284 tempPWQualityConfigFile = tempFilePath;
285 int fd = mkstemp(tempPWQualityConfigFile.data());
286 EXPECT_NE(-1, fd);
287 EXPECT_NO_THROW(
288 dumpStringToFile(rawPWQualityConfig, tempPWQualityConfigFile));
289 if (fd != -1)
290 {
291 close(fd);
292 }
293 }
294
Nan Zhoue48085d2022-10-25 00:07:04 +0000295 // Set config files to test files
Jason M. Bills2d042d12023-03-28 15:32:45 -0700296 faillockConfigFile = tempFaillockConfigFile;
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700297 pwHistoryConfigFile = tempPWHistoryConfigFile;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700298 pwQualityConfigFile = tempPWQualityConfigFile;
Nan Zhou49c81362022-10-25 00:07:08 +0000299
Denis Zlobine8edab52023-09-06 12:26:45 +0000300 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
301 testing::Eq(true)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500302 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400303 ON_CALL(*this, isUserEnabled)
304 .WillByDefault(testing::Return(true));
305 testing::Return();
306 });
Denis Zlobine8edab52023-09-06 12:26:45 +0000307
308 ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
309 testing::Eq(false)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500310 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400311 ON_CALL(*this, isUserEnabled)
312 .WillByDefault(testing::Return(false));
313 testing::Return();
314 });
Nan Zhou49c81362022-10-25 00:07:08 +0000315
316 ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return());
317
Jayanth Othayothac921a52023-07-21 03:48:55 -0500318 ON_CALL(*this, executeUserClearFailRecords)
319 .WillByDefault(testing::Return());
320
Nan Zhou49c81362022-10-25 00:07:08 +0000321 ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0));
Nan Zhouf25443e2022-10-25 00:07:11 +0000322
323 ON_CALL(*this, executeUserRename).WillByDefault(testing::Return());
Nan Zhoufef63032022-10-25 00:07:12 +0000324
325 ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_))
326 .WillByDefault(testing::Return());
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000327
Denis Zlobine8edab52023-09-06 12:26:45 +0000328 ON_CALL(*this,
329 executeUserModifyUserEnable(testing::_, testing::Eq(true)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500330 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400331 ON_CALL(*this, isUserEnabled)
332 .WillByDefault(testing::Return(true));
333 testing::Return();
334 });
Denis Zlobine8edab52023-09-06 12:26:45 +0000335
336 ON_CALL(*this,
337 executeUserModifyUserEnable(testing::_, testing::Eq(false)))
Patrick Williamscb20ea82023-10-20 11:19:13 -0500338 .WillByDefault([this]() {
Patrick Williams16c2b682024-08-16 15:20:56 -0400339 ON_CALL(*this, isUserEnabled)
340 .WillByDefault(testing::Return(false));
341 testing::Return();
342 });
Nan Zhouda401fe2022-10-25 00:07:18 +0000343
344 ON_CALL(*this, executeGroupCreation(testing::_))
345 .WillByDefault(testing::Return());
346
347 ON_CALL(*this, executeGroupDeletion(testing::_))
348 .WillByDefault(testing::Return());
349
350 ON_CALL(*this, executeGroupCreation).WillByDefault(testing::Return());
351
352 ON_CALL(*this, executeGroupDeletion).WillByDefault(testing::Return());
Nan Zhoue48085d2022-10-25 00:07:04 +0000353 }
354
355 ~UserMgrInTest() override
356 {
Jason M. Bills2d042d12023-03-28 15:32:45 -0700357 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700358 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700359 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
Nan Zhoue48085d2022-10-25 00:07:04 +0000360 }
361
Nan Zhou49c81362022-10-25 00:07:08 +0000362 MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool),
363 (override));
364
365 MOCK_METHOD(void, executeUserDelete, (const char*), (override));
366
Jayanth Othayothac921a52023-07-21 03:48:55 -0500367 MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override));
368
Nan Zhou49c81362022-10-25 00:07:08 +0000369 MOCK_METHOD(size_t, getIpmiUsersCount, (), (override));
370
Nan Zhouf25443e2022-10-25 00:07:11 +0000371 MOCK_METHOD(void, executeUserRename, (const char*, const char*),
372 (override));
373
Nan Zhoufef63032022-10-25 00:07:12 +0000374 MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool),
375 (override));
376
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000377 MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool),
378 (override));
379
Nan Zhoua2953032022-11-11 21:50:32 +0000380 MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*),
381 (override));
382
Nan Zhouda401fe2022-10-25 00:07:18 +0000383 MOCK_METHOD(void, executeGroupCreation, (const char*), (override));
384
385 MOCK_METHOD(void, executeGroupDeletion, (const char*), (override));
386
Denis Zlobine8edab52023-09-06 12:26:45 +0000387 MOCK_METHOD(bool, isUserEnabled, (const std::string& userName), (override));
388
Nan Zhoufef63032022-10-25 00:07:12 +0000389 protected:
Patrick Williams0af827c2025-07-02 16:53:03 -0400390 static constexpr auto tempFilePath = "/tmp/test-data-XXXXXX";
391
Nan Zhoue48085d2022-10-25 00:07:04 +0000392 static sdbusplus::bus_t busInTest;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700393 std::string tempFaillockConfigFile;
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700394 std::string tempPWHistoryConfigFile;
Jason M. Bills2d042d12023-03-28 15:32:45 -0700395 std::string tempPWQualityConfigFile;
Nan Zhoue48085d2022-10-25 00:07:04 +0000396};
397
398sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
399
Jason M. Bills2d042d12023-03-28 15:32:45 -0700400TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
401{
402 std::string minlen;
403 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
404 0);
405 EXPECT_EQ(minlen, "8");
406 std::string deny;
407 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
408 EXPECT_EQ(deny, "2");
Jason M. Bills2d042d12023-03-28 15:32:45 -0700409 std::string remember;
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700410 EXPECT_EQ(
411 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
412 0);
413 EXPECT_EQ(remember, "0");
Jason M. Bills2d042d12023-03-28 15:32:45 -0700414}
415
416TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
417{
418 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
419 0);
420 std::string minlen;
421 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
422 0);
423 EXPECT_EQ(minlen, "16");
424
425 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
426 std::string deny;
427 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
428 EXPECT_EQ(deny, "3");
Nan Zhoue48085d2022-10-25 00:07:04 +0000429
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700430 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
431 0);
432 std::string remember;
433 EXPECT_EQ(
434 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
435 0);
436 EXPECT_EQ(remember, "1");
Jason M. Bills17b88272023-05-22 14:24:02 -0700437}
438
439TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
440{
441 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
442 0);
443
444 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
445 EXPECT_FALSE(std::filesystem::exists(tmpFile));
446
447 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
448
449 tmpFile = tempFaillockConfigFile + "_tmp";
450 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills17b88272023-05-22 14:24:02 -0700451
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700452 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
453 0);
Nan Zhoue48085d2022-10-25 00:07:04 +0000454
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700455 tmpFile = tempPWHistoryConfigFile + "_tmp";
456 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills2d042d12023-03-28 15:32:45 -0700457}
458
459TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
460{
461 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
462 std::string minlen;
463 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
464 -1);
465
466 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
467 EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
468 -1);
469
470 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
471 std::string deny;
472 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
473
474 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
475 EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000476
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700477 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
478 std::string remember;
479 EXPECT_EQ(
480 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
481 -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000482
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700483 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
484 EXPECT_EQ(
485 getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
486 -1);
Jason M. Bills2d042d12023-03-28 15:32:45 -0700487}
488
489TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
490{
491 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
492 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
493 -1);
494
495 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
496 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
497 -1);
498
499 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
500 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
501
502 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
503 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
Nan Zhoue48085d2022-10-25 00:07:04 +0000504
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700505 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
506 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
507 -1);
Jason M. Bills17b88272023-05-22 14:24:02 -0700508
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700509 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
510 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
511 -1);
Jason M. Bills17b88272023-05-22 14:24:02 -0700512}
513
514TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
515{
516 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
517 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
518 -1);
519
520 std::string tmpFile = tempPWQualityConfigFile + "_tmp";
521 EXPECT_FALSE(std::filesystem::exists(tmpFile));
522
523 EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
524 EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
525 -1);
526
527 EXPECT_FALSE(std::filesystem::exists(tmpFile));
528
529 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
530 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
531
532 tmpFile = tempFaillockConfigFile + "_tmp";
533 EXPECT_FALSE(std::filesystem::exists(tmpFile));
534
535 EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
536 EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
537
538 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700539
540 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
541 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
542 -1);
543
544 tmpFile = tempPWHistoryConfigFile + "_tmp";
545 EXPECT_FALSE(std::filesystem::exists(tmpFile));
546
547 EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
548 EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
549 -1);
550
551 EXPECT_FALSE(std::filesystem::exists(tmpFile));
Jason M. Bills17b88272023-05-22 14:24:02 -0700552}
553
Nan Zhou8a11d992022-10-25 00:07:06 +0000554TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
555{
556 EXPECT_THROW(
557 isUserExist(""),
558 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
559}
560
561TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
562{
563 EXPECT_THROW(throwForUserDoesNotExist("whatever"),
564 sdbusplus::xyz::openbmc_project::User::Common::Error::
565 UserNameDoesNotExist);
566}
567
568TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
569{
570 EXPECT_THROW(
571 throwForUserExists("root"),
572 sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
573}
574
Nan Zhou40e44972022-10-25 00:07:07 +0000575TEST_F(
576 UserMgrInTest,
577 ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)
578{
579 std::string strWith17Chars(17, 'A');
580 EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}),
581 sdbusplus::xyz::openbmc_project::User::Common::Error::
582 UserNameGroupFail);
583}
584
585TEST_F(
586 UserMgrInTest,
587 ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
588{
Malik Akbar Hashemi Rafsanjani27d56762025-03-12 03:19:52 -0700589 std::string strWith31Chars(101, 'A');
Nan Zhou40e44972022-10-25 00:07:07 +0000590 EXPECT_THROW(
591 throwForUserNameConstraints(strWith31Chars, {}),
592 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
593}
594
595TEST_F(UserMgrInTest,
596 ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
597{
598 std::string startWithNumber = "0ABC";
nichanghao.nchd9adc732024-01-17 20:24:17 +0800599 std::string startWithDisallowedCharacter = "[test";
Nan Zhou40e44972022-10-25 00:07:07 +0000600 EXPECT_THROW(
601 throwForUserNameConstraints(startWithNumber, {"ipmi"}),
602 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
nichanghao.nchd9adc732024-01-17 20:24:17 +0800603 EXPECT_THROW(
604 throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}),
605 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Nan Zhou40e44972022-10-25 00:07:07 +0000606}
607
Nan Zhou49c81362022-10-25 00:07:08 +0000608TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure)
609{
610 EXPECT_THROW(
611 UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true),
612 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
613}
614
615TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
616{
617 EXPECT_THROW(
618 UserMgr::executeUserDelete("user0"),
619 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
620}
621
622TEST_F(UserMgrInTest,
623 ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)
624{
625 EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers));
626 EXPECT_THROW(
627 throwForMaxGrpUserCount({"ipmi"}),
628 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
629}
630
631TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails)
632{
633 EXPECT_CALL(*this, executeUserAdd)
634 .WillOnce(testing::Throw(
635 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
636 EXPECT_THROW(
637 createUser("whatever", {"redfish"}, "", true),
638 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
639}
640
641TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)
642{
643 std::string username = "user";
644 EXPECT_NO_THROW(
645 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
646 EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
647 .WillOnce(testing::Throw(
648 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
649 .WillOnce(testing::DoDefault());
650
651 EXPECT_THROW(
652 deleteUser(username),
653 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
654 EXPECT_NO_THROW(UserMgr::deleteUser(username));
655}
656
Jayanth Othayothac921a52023-07-21 03:48:55 -0500657TEST_F(UserMgrInTest,
658 DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)
659{
660 const char* username = "user";
661 EXPECT_NO_THROW(
662 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
663 EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username)))
664 .WillOnce(testing::Throw(
665 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
666 .WillOnce(testing::DoDefault());
667
668 EXPECT_THROW(
669 deleteUser(username),
670 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
671 EXPECT_NO_THROW(UserMgr::deleteUser(username));
672}
673
Nan Zhou589aeb42022-10-25 00:07:09 +0000674TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
675{
676 EXPECT_THROW(
677 throwForInvalidPrivilege("whatever"),
678 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
679}
680
681TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)
682{
683 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin"));
684 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator"));
685 EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user"));
Nan Zhou589aeb42022-10-25 00:07:09 +0000686}
687
Nan Zhouecf88762022-10-25 00:07:10 +0000688TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
689{
690 EXPECT_THROW(
691 throwForInvalidGroups({"whatever"}),
692 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Ravi Teja4e2c06e2024-04-20 23:18:34 -0500693 EXPECT_THROW(
694 throwForInvalidGroups({"web"}),
695 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Nan Zhouecf88762022-10-25 00:07:10 +0000696}
697
698TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
699{
700 EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
701 EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
702 EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
Ninad Palsule601d3db2023-03-09 10:27:37 -0600703 EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
Nan Zhouecf88762022-10-25 00:07:10 +0000704}
705
Nan Zhouf25443e2022-10-25 00:07:11 +0000706TEST_F(UserMgrInTest, RenameUserOnSuccess)
707{
708 std::string username = "user001";
709 EXPECT_NO_THROW(
710 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
711 std::string newUsername = "user002";
712
713 EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername));
714
715 // old username doesn't exist
716 EXPECT_THROW(getUserInfo(username),
717 sdbusplus::xyz::openbmc_project::User::Common::Error::
718 UserNameDoesNotExist);
719
720 UserInfoMap userInfo = getUserInfo(newUsername);
721 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
722 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
723 testing::UnorderedElementsAre("redfish", "ssh"));
724 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
725
726 EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
727}
728
729TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails)
730{
731 std::string username = "user001";
732 EXPECT_NO_THROW(
733 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
734 std::string newUsername = "user002";
735
736 EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
737 testing::StrEq(newUsername)))
738 .WillOnce(testing::Throw(
739 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
740 EXPECT_THROW(
741 UserMgr::renameUser(username, newUsername),
742 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
743
744 // The original user is unchanged
745 UserInfoMap userInfo = getUserInfo(username);
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(username));
752}
753
754TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
755{
756 EXPECT_THROW(
757 UserMgr::executeUserRename("user0", "user1"),
758 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
Nan Zhoufef63032022-10-25 00:07:12 +0000759 EXPECT_THROW(
760 UserMgr::executeUserModify("user0", "ssh", true),
761 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
762}
763
764TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess)
765{
766 std::string username = "user001";
767 EXPECT_NO_THROW(
768 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
769 EXPECT_NO_THROW(
770 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"));
771 UserInfoMap userInfo = getUserInfo(username);
772 EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin");
773 EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
774 testing::UnorderedElementsAre("ipmi", "ssh"));
775 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
776 EXPECT_NO_THROW(UserMgr::deleteUser(username));
777}
778
779TEST_F(UserMgrInTest,
780 UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)
781{
782 std::string username = "user001";
783 EXPECT_NO_THROW(
784 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
785 EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_,
786 testing::_))
787 .WillOnce(testing::Throw(
788 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
789 EXPECT_THROW(
790 updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"),
791 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
792 EXPECT_NO_THROW(UserMgr::deleteUser(username));
Nan Zhouf25443e2022-10-25 00:07:11 +0000793}
794
Nan Zhou18031012022-11-10 22:24:58 +0000795TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
796{
797 initializeAccountPolicy();
798 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
799 UserMgr::minPasswordLength(8);
800 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
801}
802
803TEST_F(UserMgrInTest,
804 MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)
805{
806 initializeAccountPolicy();
807 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
808 EXPECT_THROW(
809 UserMgr::minPasswordLength(minPasswdLength - 1),
810 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
811 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
812}
813
814TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
815{
816 initializeAccountPolicy();
817 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
818 UserMgr::minPasswordLength(16);
819 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
820}
821
822TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
823{
Jason M. Bills2d042d12023-03-28 15:32:45 -0700824 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
Nan Zhou18031012022-11-10 22:24:58 +0000825 initializeAccountPolicy();
826 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
827 EXPECT_THROW(
828 UserMgr::minPasswordLength(16),
829 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
830 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
831}
832
Chandramohan Harkude9ca86922025-05-18 13:09:25 +0530833TEST_F(UserMgrInTest, MinPasswordLengthGreaterThanMaxPasswordLength)
834{
835 initializeAccountPolicy();
836
837 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
838 EXPECT_THROW(
839 UserMgr::minPasswordLength(maxPasswdLength + 1),
840 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
841 EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
842}
843
Nan Zhoua6ce1fa2022-10-25 00:07:14 +0000844TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame)
845{
846 initializeAccountPolicy();
847 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
848 UserMgr::rememberOldPasswordTimes(8);
849 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
850 UserMgr::rememberOldPasswordTimes(8);
851 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
852}
853
854TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
855{
856 initializeAccountPolicy();
857 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
858 UserMgr::rememberOldPasswordTimes(16);
859 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
860}
861
862TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
863{
Jason M. Bills3b280ec2023-08-15 16:15:48 -0700864 EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
Nan Zhoua6ce1fa2022-10-25 00:07:14 +0000865 initializeAccountPolicy();
866 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
867 EXPECT_THROW(
868 UserMgr::rememberOldPasswordTimes(16),
869 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
870 EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
871}
872
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000873TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
874{
875 initializeAccountPolicy();
876 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
877 UserMgr::maxLoginAttemptBeforeLockout(2);
878 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
879}
880
881TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
882{
883 initializeAccountPolicy();
884 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
885 UserMgr::maxLoginAttemptBeforeLockout(16);
886 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
887}
888
889TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
890{
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000891 initializeAccountPolicy();
Jason M. Bills2d042d12023-03-28 15:32:45 -0700892 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000893 EXPECT_THROW(
894 UserMgr::maxLoginAttemptBeforeLockout(16),
895 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
Jason M. Bills2d042d12023-03-28 15:32:45 -0700896 EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
Nan Zhoucfabe6b2022-10-25 00:07:15 +0000897}
898
Nan Zhou784aecd2022-10-25 00:07:16 +0000899TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
900{
901 initializeAccountPolicy();
902 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
903 UserMgr::accountUnlockTimeout(3);
904 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
905}
906
907TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
908{
909 initializeAccountPolicy();
910 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
911 UserMgr::accountUnlockTimeout(16);
912 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
913}
914
915TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
916{
917 initializeAccountPolicy();
Jason M. Bills2d042d12023-03-28 15:32:45 -0700918 EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
Nan Zhou784aecd2022-10-25 00:07:16 +0000919 EXPECT_THROW(
920 UserMgr::accountUnlockTimeout(16),
921 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
922 EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
923}
924
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000925TEST_F(UserMgrInTest, UserEnableOnSuccess)
926{
927 std::string username = "user001";
928 EXPECT_NO_THROW(
929 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
930 UserInfoMap userInfo = getUserInfo(username);
931 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
932
933 EXPECT_NO_THROW(userEnable(username, false));
934
935 userInfo = getUserInfo(username);
936 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false);
937
938 EXPECT_NO_THROW(UserMgr::deleteUser(username));
939}
940
Ninad Palsule601d3db2023-03-09 10:27:37 -0600941TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole)
942{
943 std::string username = "user001";
944 EXPECT_NO_THROW(
945 UserMgr::createUser(username, {"hostconsole"}, "priv-user", true));
946 EXPECT_NO_THROW(UserMgr::deleteUser(username));
947 EXPECT_NO_THROW(
948 UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true));
949 EXPECT_NO_THROW(UserMgr::deleteUser(username));
950 EXPECT_NO_THROW(
951 UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true));
952 EXPECT_NO_THROW(UserMgr::deleteUser(username));
953}
954
Nan Zhou6b6f2d82022-10-25 00:07:17 +0000955TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail)
956{
957 std::string username = "user001";
958 EXPECT_NO_THROW(
959 UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
960 UserInfoMap userInfo = getUserInfo(username);
961 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
962
963 EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username),
964 testing::Eq(false)))
965 .WillOnce(testing::Throw(
966 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
967 EXPECT_THROW(
968 userEnable(username, false),
969 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
970
971 userInfo = getUserInfo(username);
972 // Stay unchanged
973 EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
974
975 EXPECT_NO_THROW(UserMgr::deleteUser(username));
976}
977
Nan Zhoua2953032022-11-11 21:50:32 +0000978TEST_F(
979 UserMgrInTest,
980 UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
981{
982 EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
983}
984
985TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
986{
987 std::string username = "user001";
988 initializeAccountPolicy();
989 // Example output from BMC
Jason M. Bills2d042d12023-03-28 15:32:45 -0700990 // root:~# faillock --user root
991 // root:
992 // When Type Source Valid
993 std::vector<std::string> output = {"whatever",
994 "When Type Source Valid"};
Nan Zhoua2953032022-11-11 21:50:32 +0000995 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
996 .WillOnce(testing::Return(output));
997
998 EXPECT_FALSE(userLockedForFailedAttempt(username));
999}
1000
1001TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail)
1002{
1003 std::string username = "user001";
1004 initializeAccountPolicy();
1005 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1006 .WillOnce(testing::Throw(
1007 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1008
1009 EXPECT_THROW(
1010 userLockedForFailedAttempt(username),
1011 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1012}
1013
1014TEST_F(UserMgrInTest,
Nan Zhoua2953032022-11-11 21:50:32 +00001015 UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
1016{
1017 std::string username = "user001";
1018 initializeAccountPolicy();
1019
1020 // Choose a date in the past.
1021 std::vector<std::string> output = {"whatever",
Jason M. Bills2d042d12023-03-28 15:32:45 -07001022 "10/24/2002 00:00:00 type source V"};
Nan Zhoua2953032022-11-11 21:50:32 +00001023 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1024 .WillOnce(testing::Return(output));
1025
1026 EXPECT_THROW(
1027 userLockedForFailedAttempt(username),
1028 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1029}
1030
1031TEST_F(UserMgrInTest,
1032 UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)
1033{
1034 std::string username = "user001";
1035 initializeAccountPolicy();
1036
1037 // Choose a date in the past.
1038 std::vector<std::string> output = {"whatever",
Jason M. Bills2d042d12023-03-28 15:32:45 -07001039 "2002-10-24 00:00:00 type source V"};
Nan Zhoua2953032022-11-11 21:50:32 +00001040 EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1041 .WillOnce(testing::Return(output));
1042
1043 EXPECT_EQ(userLockedForFailedAttempt(username), false);
1044}
1045
Nan Zhouda401fe2022-10-25 00:07:18 +00001046TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess)
1047{
1048 // Base Redfish Roles
1049 EXPECT_NO_THROW(
1050 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator"));
1051 EXPECT_NO_THROW(
1052 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator"));
1053 EXPECT_NO_THROW(
1054 checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly"));
1055 // Base Redfish Privileges
1056 EXPECT_NO_THROW(
1057 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login"));
1058 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1059 "openbmc_rfp_ConfigureManager"));
1060 EXPECT_NO_THROW(
1061 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers"));
1062 EXPECT_NO_THROW(
1063 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf"));
1064 EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1065 "openbmc_rfp_ConfigureComponents"));
1066 // OEM Redfish Roles
1067 EXPECT_NO_THROW(
1068 checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService"));
1069 // OEM Redfish Privileges
1070 EXPECT_NO_THROW(
1071 checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService"));
1072}
1073
1074TEST_F(UserMgrInTest,
1075 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)
1076{
1077 std::string groupName(maxSystemGroupNameLength + 1, 'A');
1078 EXPECT_THROW(
1079 checkAndThrowForDisallowedGroupCreation(groupName),
1080 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1081}
1082
1083TEST_F(
1084 UserMgrInTest,
1085 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1086{
Nan Zhouda401fe2022-10-25 00:07:18 +00001087 EXPECT_THROW(
1088 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"),
1089 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1090 EXPECT_THROW(
1091 checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"),
1092 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1093}
1094
1095TEST_F(
1096 UserMgrInTest,
1097 CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1098{
Nan Zhouda401fe2022-10-25 00:07:18 +00001099 EXPECT_THROW(
1100 checkAndThrowForDisallowedGroupCreation("google_rfp_"),
1101 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1102 EXPECT_THROW(
1103 checkAndThrowForDisallowedGroupCreation("com_rfp_"),
1104 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1105}
1106
1107TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1108{
Ravi Teja4e2c06e2024-04-20 23:18:34 -05001109 constexpr size_t predefGroupCount = 4;
Ninad Palsule601d3db2023-03-09 10:27:37 -06001110
1111 EXPECT_THAT(allGroups().size(), predefGroupCount);
1112 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
Nan Zhouda401fe2022-10-25 00:07:18 +00001113 {
1114 std::string groupName = "openbmc_rfr_role";
1115 groupName += std::to_string(i);
1116 EXPECT_NO_THROW(createGroup(groupName));
1117 }
1118 EXPECT_THROW(
1119 createGroup("openbmc_rfr_AnotherRole"),
1120 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
Ninad Palsule601d3db2023-03-09 10:27:37 -06001121 for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
Nan Zhouda401fe2022-10-25 00:07:18 +00001122 {
1123 std::string groupName = "openbmc_rfr_role";
1124 groupName += std::to_string(i);
1125 EXPECT_NO_THROW(deleteGroup(groupName));
1126 }
1127}
1128
1129TEST_F(UserMgrInTest, CheckAndThrowForGroupExist)
1130{
1131 std::string groupName = "openbmc_rfr_role";
1132 EXPECT_NO_THROW(createGroup(groupName));
1133 EXPECT_THROW(
1134 createGroup(groupName),
1135 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1136 EXPECT_NO_THROW(deleteGroup(groupName));
1137}
1138
1139TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1140{
Ravi Teja4e2c06e2024-04-20 23:18:34 -05001141 EXPECT_THAT(allGroups(), testing::UnorderedElementsAre(
1142 "redfish", "ipmi", "ssh", "hostconsole"));
Ninad Palsule601d3db2023-03-09 10:27:37 -06001143}
1144
1145TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1146{
1147 EXPECT_THROW(
1148 createGroup("ipmi"),
1149 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1150 EXPECT_THROW(
Ninad Palsule601d3db2023-03-09 10:27:37 -06001151 createGroup("redfish"),
1152 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1153 EXPECT_THROW(
1154 createGroup("ssh"),
1155 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1156 EXPECT_THROW(
1157 createGroup("hostconsole"),
1158 sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
Nan Zhouda401fe2022-10-25 00:07:18 +00001159}
1160
1161TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1162{
1163 EXPECT_THROW(
1164 deleteGroup("ipmi"),
1165 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1166 EXPECT_THROW(
Nan Zhouda401fe2022-10-25 00:07:18 +00001167 deleteGroup("redfish"),
1168 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1169 EXPECT_THROW(
1170 deleteGroup("ssh"),
1171 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Ninad Palsule601d3db2023-03-09 10:27:37 -06001172 EXPECT_THROW(
1173 deleteGroup("hostconsole"),
1174 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
Nan Zhouda401fe2022-10-25 00:07:18 +00001175}
1176
1177TEST_F(UserMgrInTest,
1178 CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)
1179{
1180 EXPECT_CALL(*this, executeGroupCreation)
1181 .WillOnce(testing::Throw(
1182 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1183 EXPECT_THROW(
1184 createGroup("openbmc_rfr_role1"),
1185 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1186}
1187
1188TEST_F(UserMgrInTest,
1189 DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)
1190{
1191 std::string groupName = "openbmc_rfr_role1";
1192 EXPECT_NO_THROW(UserMgr::createGroup(groupName));
1193 EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName)))
1194 .WillOnce(testing::Throw(
1195 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1196 .WillOnce(testing::DoDefault());
1197
1198 EXPECT_THROW(
1199 deleteGroup(groupName),
1200 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1201 EXPECT_NO_THROW(UserMgr::deleteGroup(groupName));
1202}
1203
1204TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1205{
1206 EXPECT_THROW(deleteGroup("whatever"),
1207 sdbusplus::xyz::openbmc_project::User::Common::Error::
1208 GroupNameDoesNotExist);
1209}
1210
1211TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1212{
Ravi Teja4e2c06e2024-04-20 23:18:34 -05001213 EXPECT_THAT(
1214 UserMgr::readAllGroupsOnSystem(),
1215 testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole"));
Nan Zhouda401fe2022-10-25 00:07:18 +00001216}
1217
raviteja-b8cc44052019-02-27 23:29:36 -06001218} // namespace user
1219} // namespace phosphor