xref: /openbmc/phosphor-user-manager/test/user_mgr_test.cpp (revision 0af827c59340ad333c50834c95fbd38b66f547b6)
1 #include "mock_user_mgr.hpp"
2 #include "user_mgr.hpp"
3 
4 #include <unistd.h>
5 
6 #include <sdbusplus/test/sdbus_mock.hpp>
7 #include <xyz/openbmc_project/Common/error.hpp>
8 #include <xyz/openbmc_project/User/Common/error.hpp>
9 
10 #include <exception>
11 #include <filesystem>
12 #include <fstream>
13 #include <vector>
14 
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 
18 namespace phosphor
19 {
20 namespace user
21 {
22 
23 using ::testing::Return;
24 using ::testing::Throw;
25 
26 using InternalFailure =
27     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
28 using UserNameDoesNotExist =
29     sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameDoesNotExist;
30 
31 class TestUserMgr : public testing::Test
32 {
33   public:
34     sdbusplus::SdBusMock sdBusMock;
35     sdbusplus::bus_t bus;
36     MockManager mockManager;
37 
TestUserMgr()38     TestUserMgr() :
39         bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath)
40     {}
41 
createLocalUser(const std::string & userName,std::vector<std::string> groupNames,const std::string & priv,bool enabled)42     void createLocalUser(const std::string& userName,
43                          std::vector<std::string> groupNames,
44                          const std::string& priv, bool enabled)
45     {
46         sdbusplus::message::object_path tempObjPath(usersObjPath);
47         tempObjPath /= userName;
48         std::string userObj(tempObjPath);
49         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         }
59         mockManager.usersList.emplace(
60             userName, std::make_unique<phosphor::user::Users>(
61                           mockManager.bus, userObj.c_str(), groupNames, priv,
62                           enabled, mockManager));
63     }
64 
createPrivilegeMapperDbusObject(void)65     DbusUserObj createPrivilegeMapperDbusObject(void)
66     {
67         DbusUserObj object;
68         DbusUserObjValue objValue;
69 
70         DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
71         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);
75         object.emplace(objPath, objValue);
76 
77         DbusUserObjPath objectPath(
78             "/xyz/openbmc_project/user/ldap/openldap/role_map/1");
79         std::string group = "ldapGroup";
80         std::string priv = "priv-admin";
81         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);
86         object.emplace(objectPath, objValue);
87 
88         return object;
89     }
90 
createLdapConfigObjectWithoutPrivilegeMapper(void)91     DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void)
92     {
93         DbusUserObj object;
94         DbusUserObjValue objValue;
95 
96         DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
97         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);
101         object.emplace(objPath, objValue);
102         return object;
103     }
104 };
105 
TEST_F(TestUserMgr,ldapEntryDoesNotExist)106 TEST_F(TestUserMgr, ldapEntryDoesNotExist)
107 {
108     std::string userName = "user";
109     UserInfoMap userInfo;
110 
111     EXPECT_CALL(mockManager, getPrimaryGroup(userName))
112         .WillRepeatedly(Throw(UserNameDoesNotExist()));
113     EXPECT_THROW(userInfo = mockManager.getUserInfo(userName),
114                  UserNameDoesNotExist);
115 }
116 
TEST_F(TestUserMgr,localUser)117 TEST_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"]));
133     EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"]));
134     EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"]));
135 }
136 
TEST_F(TestUserMgr,ldapUserWithPrivMapper)137 TEST_F(TestUserMgr, ldapUserWithPrivMapper)
138 {
139     UserInfoMap userInfo;
140     std::string userName = "ldapUser";
141     std::string ldapGroup = "ldapGroup";
142     gid_t primaryGid = 1000;
143 
144     EXPECT_CALL(mockManager, getPrimaryGroup(userName))
145         .WillRepeatedly(Return(primaryGid));
146     // Create privilege mapper dbus object
147     DbusUserObj object = createPrivilegeMapperDbusObject();
148     EXPECT_CALL(mockManager, getPrivilegeMapperObject())
149         .WillRepeatedly(Return(object));
150     EXPECT_CALL(mockManager, isGroupMember(userName, primaryGid, ldapGroup))
151         .WillRepeatedly(Return(true));
152     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 
TEST_F(TestUserMgr,ldapUserWithoutPrivMapper)157 TEST_F(TestUserMgr, ldapUserWithoutPrivMapper)
158 {
159     using ::testing::_;
160 
161     UserInfoMap userInfo;
162     std::string userName = "ldapUser";
163     std::string ldapGroup = "ldapGroup";
164     gid_t primaryGid = 1000;
165 
166     EXPECT_CALL(mockManager, getPrimaryGroup(userName))
167         .WillRepeatedly(Return(primaryGid));
168     // Create LDAP config object without privilege mapper
169     DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper();
170     EXPECT_CALL(mockManager, getPrivilegeMapperObject())
171         .WillRepeatedly(Return(object));
172     EXPECT_CALL(mockManager, isGroupMember(_, _, _)).Times(0);
173     userInfo = mockManager.getUserInfo(userName);
174     EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
175     EXPECT_EQ("priv-user", std::get<std::string>(userInfo["UserPrivilege"]));
176 }
177 
TEST(GetCSVFromVector,EmptyVectorReturnsEmptyString)178 TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString)
179 {
180     EXPECT_EQ(getCSVFromVector({}), "");
181 }
182 
TEST(GetCSVFromVector,ElementsAreJoinedByComma)183 TEST(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 
TEST(RemoveStringFromCSV,WithoutDeleteStringReturnsFalse)190 TEST(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 
TEST(RemoveStringFromCSV,WithDeleteStringReturnsTrue)201 TEST(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 
213 namespace
214 {
215 inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user";
216 
217 // Fake configs; referenced configs on real BMC
218 inline constexpr const char* rawFailLockConfig = R"(
219 deny=2
220 unlock_time=3
221 )";
222 inline constexpr const char* rawPWHistoryConfig = R"(
223 enforce_for_root
224 remember=0
225 )";
226 inline constexpr const char* rawPWQualityConfig = R"(
227 enforce_for_root
228 minlen=8
229 difok=0
230 lcredit=0
231 ocredit=0
232 dcredit=0
233 ucredit=0
234 )";
235 } // namespace
236 
dumpStringToFile(const std::string & str,const std::string & filePath)237 void dumpStringToFile(const std::string& str, const std::string& filePath)
238 {
239     std::ofstream outputFileStream;
240 
241     outputFileStream.exceptions(
242         std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
243 
244     outputFileStream.open(filePath, std::ios::out);
245     outputFileStream << str << "\n" << std::flush;
246     outputFileStream.close();
247 }
248 
removeFile(const std::string & filePath)249 void removeFile(const std::string& filePath)
250 {
251     std::filesystem::remove(filePath);
252 }
253 
254 class UserMgrInTest : public testing::Test, public UserMgr
255 {
256   public:
UserMgrInTest()257     UserMgrInTest() : UserMgr(busInTest, objectRootInTest)
258     {
259         {
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 
295         // Set config files to test files
296         faillockConfigFile = tempFaillockConfigFile;
297         pwHistoryConfigFile = tempPWHistoryConfigFile;
298         pwQualityConfigFile = tempPWQualityConfigFile;
299 
300         ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
301                                       testing::Eq(true)))
302             .WillByDefault([this]() {
303                 ON_CALL(*this, isUserEnabled)
304                     .WillByDefault(testing::Return(true));
305                 testing::Return();
306             });
307 
308         ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
309                                       testing::Eq(false)))
310             .WillByDefault([this]() {
311                 ON_CALL(*this, isUserEnabled)
312                     .WillByDefault(testing::Return(false));
313                 testing::Return();
314             });
315 
316         ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return());
317 
318         ON_CALL(*this, executeUserClearFailRecords)
319             .WillByDefault(testing::Return());
320 
321         ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0));
322 
323         ON_CALL(*this, executeUserRename).WillByDefault(testing::Return());
324 
325         ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_))
326             .WillByDefault(testing::Return());
327 
328         ON_CALL(*this,
329                 executeUserModifyUserEnable(testing::_, testing::Eq(true)))
330             .WillByDefault([this]() {
331                 ON_CALL(*this, isUserEnabled)
332                     .WillByDefault(testing::Return(true));
333                 testing::Return();
334             });
335 
336         ON_CALL(*this,
337                 executeUserModifyUserEnable(testing::_, testing::Eq(false)))
338             .WillByDefault([this]() {
339                 ON_CALL(*this, isUserEnabled)
340                     .WillByDefault(testing::Return(false));
341                 testing::Return();
342             });
343 
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());
353     }
354 
~UserMgrInTest()355     ~UserMgrInTest() override
356     {
357         EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
358         EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
359         EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
360     }
361 
362     MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool),
363                 (override));
364 
365     MOCK_METHOD(void, executeUserDelete, (const char*), (override));
366 
367     MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override));
368 
369     MOCK_METHOD(size_t, getIpmiUsersCount, (), (override));
370 
371     MOCK_METHOD(void, executeUserRename, (const char*, const char*),
372                 (override));
373 
374     MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool),
375                 (override));
376 
377     MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool),
378                 (override));
379 
380     MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*),
381                 (override));
382 
383     MOCK_METHOD(void, executeGroupCreation, (const char*), (override));
384 
385     MOCK_METHOD(void, executeGroupDeletion, (const char*), (override));
386 
387     MOCK_METHOD(bool, isUserEnabled, (const std::string& userName), (override));
388 
389   protected:
390     static constexpr auto tempFilePath = "/tmp/test-data-XXXXXX";
391 
392     static sdbusplus::bus_t busInTest;
393     std::string tempFaillockConfigFile;
394     std::string tempPWHistoryConfigFile;
395     std::string tempPWQualityConfigFile;
396 };
397 
398 sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
399 
TEST_F(UserMgrInTest,GetPamModuleConfValueOnSuccess)400 TEST_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");
409     std::string remember;
410     EXPECT_EQ(
411         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
412         0);
413     EXPECT_EQ(remember, "0");
414 }
415 
TEST_F(UserMgrInTest,SetPamModuleConfValueOnSuccess)416 TEST_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");
429 
430     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");
437 }
438 
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnSuccess)439 TEST_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));
451 
452     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
453               0);
454 
455     tmpFile = tempPWHistoryConfigFile + "_tmp";
456     EXPECT_FALSE(std::filesystem::exists(tmpFile));
457 }
458 
TEST_F(UserMgrInTest,GetPamModuleConfValueOnFailure)459 TEST_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);
476 
477     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
478     std::string remember;
479     EXPECT_EQ(
480         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
481         -1);
482 
483     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
484     EXPECT_EQ(
485         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
486         -1);
487 }
488 
TEST_F(UserMgrInTest,SetPamModuleConfValueOnFailure)489 TEST_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);
504 
505     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
506     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
507               -1);
508 
509     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
510     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
511               -1);
512 }
513 
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnFailure)514 TEST_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));
539 
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));
552 }
553 
TEST_F(UserMgrInTest,IsUserExistEmptyInputThrowsError)554 TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
555 {
556     EXPECT_THROW(
557         isUserExist(""),
558         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
559 }
560 
TEST_F(UserMgrInTest,ThrowForUserDoesNotExistThrowsError)561 TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
562 {
563     EXPECT_THROW(throwForUserDoesNotExist("whatever"),
564                  sdbusplus::xyz::openbmc_project::User::Common::Error::
565                      UserNameDoesNotExist);
566 }
567 
TEST_F(UserMgrInTest,ThrowForUserExistsThrowsError)568 TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
569 {
570     EXPECT_THROW(
571         throwForUserExists("root"),
572         sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
573 }
574 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)575 TEST_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 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)585 TEST_F(
586     UserMgrInTest,
587     ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
588 {
589     std::string strWith31Chars(101, 'A');
590     EXPECT_THROW(
591         throwForUserNameConstraints(strWith31Chars, {}),
592         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
593 }
594 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)595 TEST_F(UserMgrInTest,
596        ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
597 {
598     std::string startWithNumber = "0ABC";
599     std::string startWithDisallowedCharacter = "[test";
600     EXPECT_THROW(
601         throwForUserNameConstraints(startWithNumber, {"ipmi"}),
602         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
603     EXPECT_THROW(
604         throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}),
605         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
606 }
607 
TEST_F(UserMgrInTest,UserAddNotRootFailedWithInternalFailure)608 TEST_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 
TEST_F(UserMgrInTest,UserDeleteNotRootFailedWithInternalFailure)615 TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
616 {
617     EXPECT_THROW(
618         UserMgr::executeUserDelete("user0"),
619         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
620 }
621 
TEST_F(UserMgrInTest,ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)622 TEST_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 
TEST_F(UserMgrInTest,CreateUserThrowsInternalFailureWhenExecuteUserAddFails)631 TEST_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 
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)641 TEST_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 
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)657 TEST_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 
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)674 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
675 {
676     EXPECT_THROW(
677         throwForInvalidPrivilege("whatever"),
678         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
679 }
680 
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)681 TEST_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"));
686 }
687 
TEST_F(UserMgrInTest,ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)688 TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
689 {
690     EXPECT_THROW(
691         throwForInvalidGroups({"whatever"}),
692         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
693     EXPECT_THROW(
694         throwForInvalidGroups({"web"}),
695         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
696 }
697 
TEST_F(UserMgrInTest,ThrowForInvalidGroupsNoThrowWhenGroupIsValid)698 TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
699 {
700     EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
701     EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
702     EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
703     EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
704 }
705 
TEST_F(UserMgrInTest,RenameUserOnSuccess)706 TEST_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 
TEST_F(UserMgrInTest,RenameUserThrowsInternalFailureIfExecuteUserModifyFails)729 TEST_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 
TEST_F(UserMgrInTest,DefaultUserModifyFailedWithInternalFailure)754 TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
755 {
756     EXPECT_THROW(
757         UserMgr::executeUserRename("user0", "user1"),
758         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
759     EXPECT_THROW(
760         UserMgr::executeUserModify("user0", "ssh", true),
761         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
762 }
763 
TEST_F(UserMgrInTest,UpdateGroupsAndPrivOnSuccess)764 TEST_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 
TEST_F(UserMgrInTest,UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)779 TEST_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));
793 }
794 
TEST_F(UserMgrInTest,MinPasswordLengthReturnsIfValueIsTheSame)795 TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
796 {
797     initializeAccountPolicy();
798     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
799     UserMgr::minPasswordLength(8);
800     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
801 }
802 
TEST_F(UserMgrInTest,MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)803 TEST_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 
TEST_F(UserMgrInTest,MinPasswordLengthOnSuccess)814 TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
815 {
816     initializeAccountPolicy();
817     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
818     UserMgr::minPasswordLength(16);
819     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
820 }
821 
TEST_F(UserMgrInTest,MinPasswordLengthOnFailure)822 TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
823 {
824     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
825     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 
TEST_F(UserMgrInTest,MinPasswordLengthGreaterThanMaxPasswordLength)833 TEST_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 
TEST_F(UserMgrInTest,RememberOldPasswordTimesReturnsIfValueIsTheSame)844 TEST_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 
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnSuccess)854 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
855 {
856     initializeAccountPolicy();
857     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
858     UserMgr::rememberOldPasswordTimes(16);
859     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
860 }
861 
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnFailure)862 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
863 {
864     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
865     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 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)873 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
874 {
875     initializeAccountPolicy();
876     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
877     UserMgr::maxLoginAttemptBeforeLockout(2);
878     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
879 }
880 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnSuccess)881 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
882 {
883     initializeAccountPolicy();
884     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
885     UserMgr::maxLoginAttemptBeforeLockout(16);
886     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
887 }
888 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnFailure)889 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
890 {
891     initializeAccountPolicy();
892     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
893     EXPECT_THROW(
894         UserMgr::maxLoginAttemptBeforeLockout(16),
895         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
896     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
897 }
898 
TEST_F(UserMgrInTest,AccountUnlockTimeoutReturnsIfValueIsTheSame)899 TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
900 {
901     initializeAccountPolicy();
902     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
903     UserMgr::accountUnlockTimeout(3);
904     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
905 }
906 
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnSuccess)907 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
908 {
909     initializeAccountPolicy();
910     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
911     UserMgr::accountUnlockTimeout(16);
912     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
913 }
914 
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnFailure)915 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
916 {
917     initializeAccountPolicy();
918     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
919     EXPECT_THROW(
920         UserMgr::accountUnlockTimeout(16),
921         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
922     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
923 }
924 
TEST_F(UserMgrInTest,UserEnableOnSuccess)925 TEST_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 
TEST_F(UserMgrInTest,CreateDeleteUserSuccessForHostConsole)941 TEST_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 
TEST_F(UserMgrInTest,UserEnableThrowsInternalFailureIfExecuteUserModifyFail)955 TEST_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 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)978 TEST_F(
979     UserMgrInTest,
980     UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
981 {
982     EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
983 }
984 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptZeroFailuresReturnsFalse)985 TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
986 {
987     std::string username = "user001";
988     initializeAccountPolicy();
989     // Example output from BMC
990     // root:~# faillock --user root
991     // root:
992     // When   Type   Source   Valid
993     std::vector<std::string> output = {"whatever",
994                                        "When   Type   Source   Valid"};
995     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
996         .WillOnce(testing::Return(output));
997 
998     EXPECT_FALSE(userLockedForFailedAttempt(username));
999 }
1000 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptFailIfGetFailedAttemptFail)1001 TEST_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 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)1014 TEST_F(UserMgrInTest,
1015        UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
1016 {
1017     std::string username = "user001";
1018     initializeAccountPolicy();
1019 
1020     // Choose a date in the past.
1021     std::vector<std::string> output = {"whatever",
1022                                        "10/24/2002 00:00:00 type source V"};
1023     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 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)1031 TEST_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",
1039                                        "2002-10-24 00:00:00 type source V"};
1040     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1041         .WillOnce(testing::Return(output));
1042 
1043     EXPECT_EQ(userLockedForFailedAttempt(username), false);
1044 }
1045 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationOnSuccess)1046 TEST_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 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)1074 TEST_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 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)1083 TEST_F(
1084     UserMgrInTest,
1085     CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1086 {
1087     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 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)1095 TEST_F(
1096     UserMgrInTest,
1097     CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1098 {
1099     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 
TEST_F(UserMgrInTest,CheckAndThrowForMaxGroupCountOnSuccess)1107 TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1108 {
1109     constexpr size_t predefGroupCount = 4;
1110 
1111     EXPECT_THAT(allGroups().size(), predefGroupCount);
1112     for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1113     {
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);
1121     for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1122     {
1123         std::string groupName = "openbmc_rfr_role";
1124         groupName += std::to_string(i);
1125         EXPECT_NO_THROW(deleteGroup(groupName));
1126     }
1127 }
1128 
TEST_F(UserMgrInTest,CheckAndThrowForGroupExist)1129 TEST_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 
TEST_F(UserMgrInTest,ByDefaultAllGroupsArePredefinedGroups)1139 TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1140 {
1141     EXPECT_THAT(allGroups(), testing::UnorderedElementsAre(
1142                                  "redfish", "ipmi", "ssh", "hostconsole"));
1143 }
1144 
TEST_F(UserMgrInTest,AddGroupThrowsIfPreDefinedGroupAdd)1145 TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1146 {
1147     EXPECT_THROW(
1148         createGroup("ipmi"),
1149         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1150     EXPECT_THROW(
1151         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);
1159 }
1160 
TEST_F(UserMgrInTest,DeleteGroupThrowsIfGroupIsNotAllowedToChange)1161 TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1162 {
1163     EXPECT_THROW(
1164         deleteGroup("ipmi"),
1165         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1166     EXPECT_THROW(
1167         deleteGroup("redfish"),
1168         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1169     EXPECT_THROW(
1170         deleteGroup("ssh"),
1171         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1172     EXPECT_THROW(
1173         deleteGroup("hostconsole"),
1174         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1175 }
1176 
TEST_F(UserMgrInTest,CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)1177 TEST_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 
TEST_F(UserMgrInTest,DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)1188 TEST_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 
TEST_F(UserMgrInTest,CheckAndThrowForGroupNotExist)1204 TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1205 {
1206     EXPECT_THROW(deleteGroup("whatever"),
1207                  sdbusplus::xyz::openbmc_project::User::Common::Error::
1208                      GroupNameDoesNotExist);
1209 }
1210 
TEST(ReadAllGroupsOnSystemTest,OnlyReturnsPredefinedGroups)1211 TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1212 {
1213     EXPECT_THAT(
1214         UserMgr::readAllGroupsOnSystem(),
1215         testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole"));
1216 }
1217 
1218 } // namespace user
1219 } // namespace phosphor
1220