1 #include "mock_user_mgr.hpp"
2 #include "user_mgr.hpp"
3 
4 #include <sdbusplus/test/sdbus_mock.hpp>
5 #include <xyz/openbmc_project/Common/error.hpp>
6 #include <xyz/openbmc_project/User/Common/error.hpp>
7 
8 #include <exception>
9 #include <filesystem>
10 #include <fstream>
11 #include <vector>
12 
13 #include <gmock/gmock.h>
14 #include <gtest/gtest.h>
15 
16 namespace phosphor
17 {
18 namespace user
19 {
20 
21 using ::testing::Return;
22 using ::testing::Throw;
23 
24 using InternalFailure =
25     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
26 using UserNameDoesNotExist =
27     sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameDoesNotExist;
28 
29 class TestUserMgr : public testing::Test
30 {
31   public:
32     sdbusplus::SdBusMock sdBusMock;
33     sdbusplus::bus_t bus;
34     MockManager mockManager;
35 
TestUserMgr()36     TestUserMgr() :
37         bus(sdbusplus::get_mocked_new(&sdBusMock)), mockManager(bus, objpath)
38     {}
39 
createLocalUser(const std::string & userName,std::vector<std::string> groupNames,const std::string & priv,bool enabled)40     void createLocalUser(const std::string& userName,
41                          std::vector<std::string> groupNames,
42                          const std::string& priv, bool enabled)
43     {
44         sdbusplus::message::object_path tempObjPath(usersObjPath);
45         tempObjPath /= userName;
46         std::string userObj(tempObjPath);
47         if (enabled)
48         {
49             ON_CALL(mockManager, isUserEnabled)
50                 .WillByDefault(testing::Return(true));
51         }
52         else
53         {
54             ON_CALL(mockManager, isUserEnabled)
55                 .WillByDefault(testing::Return(false));
56         }
57         mockManager.usersList.emplace(
58             userName, std::make_unique<phosphor::user::Users>(
59                           mockManager.bus, userObj.c_str(), groupNames, priv,
60                           enabled, mockManager));
61     }
62 
createPrivilegeMapperDbusObject(void)63     DbusUserObj createPrivilegeMapperDbusObject(void)
64     {
65         DbusUserObj object;
66         DbusUserObjValue objValue;
67 
68         DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
69         DbusUserPropVariant enabled(true);
70         DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
71         std::string intf = "xyz.openbmc_project.Object.Enable";
72         objValue.emplace(intf, property);
73         object.emplace(objPath, objValue);
74 
75         DbusUserObjPath objectPath(
76             "/xyz/openbmc_project/user/ldap/openldap/role_map/1");
77         std::string group = "ldapGroup";
78         std::string priv = "priv-admin";
79         DbusUserObjProperties properties = {std::make_pair("GroupName", group),
80                                             std::make_pair("Privilege", priv)};
81         std::string interface = "xyz.openbmc_project.User.PrivilegeMapperEntry";
82 
83         objValue.emplace(interface, properties);
84         object.emplace(objectPath, objValue);
85 
86         return object;
87     }
88 
createLdapConfigObjectWithoutPrivilegeMapper(void)89     DbusUserObj createLdapConfigObjectWithoutPrivilegeMapper(void)
90     {
91         DbusUserObj object;
92         DbusUserObjValue objValue;
93 
94         DbusUserObjPath objPath("/xyz/openbmc_project/user/ldap/openldap");
95         DbusUserPropVariant enabled(true);
96         DbusUserObjProperties property = {std::make_pair("Enabled", enabled)};
97         std::string intf = "xyz.openbmc_project.Object.Enable";
98         objValue.emplace(intf, property);
99         object.emplace(objPath, objValue);
100         return object;
101     }
102 };
103 
TEST_F(TestUserMgr,ldapEntryDoesNotExist)104 TEST_F(TestUserMgr, ldapEntryDoesNotExist)
105 {
106     std::string userName = "user";
107     UserInfoMap userInfo;
108 
109     EXPECT_CALL(mockManager, getPrimaryGroup(userName))
110         .WillRepeatedly(Throw(UserNameDoesNotExist()));
111     EXPECT_THROW(userInfo = mockManager.getUserInfo(userName),
112                  UserNameDoesNotExist);
113 }
114 
TEST_F(TestUserMgr,localUser)115 TEST_F(TestUserMgr, localUser)
116 {
117     UserInfoMap userInfo;
118     std::string userName = "testUser";
119     std::string privilege = "priv-admin";
120     std::vector<std::string> groups{"testGroup"};
121     // Create local user
122     createLocalUser(userName, groups, privilege, true);
123     EXPECT_CALL(mockManager, userLockedForFailedAttempt(userName)).Times(1);
124     userInfo = mockManager.getUserInfo(userName);
125 
126     EXPECT_EQ(privilege, std::get<std::string>(userInfo["UserPrivilege"]));
127     EXPECT_EQ(groups,
128               std::get<std::vector<std::string>>(userInfo["UserGroups"]));
129     EXPECT_EQ(true, std::get<bool>(userInfo["UserEnabled"]));
130     EXPECT_EQ(false, std::get<bool>(userInfo["UserLockedForFailedAttempt"]));
131     EXPECT_EQ(false, std::get<bool>(userInfo["UserPasswordExpired"]));
132     EXPECT_EQ(false, std::get<bool>(userInfo["RemoteUser"]));
133 }
134 
TEST_F(TestUserMgr,ldapUserWithPrivMapper)135 TEST_F(TestUserMgr, ldapUserWithPrivMapper)
136 {
137     UserInfoMap userInfo;
138     std::string userName = "ldapUser";
139     std::string ldapGroup = "ldapGroup";
140     gid_t primaryGid = 1000;
141 
142     EXPECT_CALL(mockManager, getPrimaryGroup(userName))
143         .WillRepeatedly(Return(primaryGid));
144     // Create privilege mapper dbus object
145     DbusUserObj object = createPrivilegeMapperDbusObject();
146     EXPECT_CALL(mockManager, getPrivilegeMapperObject())
147         .WillRepeatedly(Return(object));
148     EXPECT_CALL(mockManager, isGroupMember(userName, primaryGid, ldapGroup))
149         .WillRepeatedly(Return(true));
150     userInfo = mockManager.getUserInfo(userName);
151     EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
152     EXPECT_EQ("priv-admin", std::get<std::string>(userInfo["UserPrivilege"]));
153 }
154 
TEST_F(TestUserMgr,ldapUserWithoutPrivMapper)155 TEST_F(TestUserMgr, ldapUserWithoutPrivMapper)
156 {
157     using ::testing::_;
158 
159     UserInfoMap userInfo;
160     std::string userName = "ldapUser";
161     std::string ldapGroup = "ldapGroup";
162     gid_t primaryGid = 1000;
163 
164     EXPECT_CALL(mockManager, getPrimaryGroup(userName))
165         .WillRepeatedly(Return(primaryGid));
166     // Create LDAP config object without privilege mapper
167     DbusUserObj object = createLdapConfigObjectWithoutPrivilegeMapper();
168     EXPECT_CALL(mockManager, getPrivilegeMapperObject())
169         .WillRepeatedly(Return(object));
170     EXPECT_CALL(mockManager, isGroupMember(_, _, _)).Times(0);
171     userInfo = mockManager.getUserInfo(userName);
172     EXPECT_EQ(true, std::get<bool>(userInfo["RemoteUser"]));
173     EXPECT_EQ("priv-user", std::get<std::string>(userInfo["UserPrivilege"]));
174 }
175 
TEST(GetCSVFromVector,EmptyVectorReturnsEmptyString)176 TEST(GetCSVFromVector, EmptyVectorReturnsEmptyString)
177 {
178     EXPECT_EQ(getCSVFromVector({}), "");
179 }
180 
TEST(GetCSVFromVector,ElementsAreJoinedByComma)181 TEST(GetCSVFromVector, ElementsAreJoinedByComma)
182 {
183     EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123"}), "123");
184     EXPECT_EQ(getCSVFromVector(std::vector<std::string>{"123", "456"}),
185               "123,456");
186 }
187 
TEST(RemoveStringFromCSV,WithoutDeleteStringReturnsFalse)188 TEST(RemoveStringFromCSV, WithoutDeleteStringReturnsFalse)
189 {
190     std::string expected = "whatever,https";
191     std::string str = expected;
192     EXPECT_FALSE(removeStringFromCSV(str, "ssh"));
193     EXPECT_EQ(str, expected);
194 
195     std::string empty;
196     EXPECT_FALSE(removeStringFromCSV(empty, "ssh"));
197 }
198 
TEST(RemoveStringFromCSV,WithDeleteStringReturnsTrue)199 TEST(RemoveStringFromCSV, WithDeleteStringReturnsTrue)
200 {
201     std::string expected = "whatever";
202     std::string str = "whatever,https";
203     EXPECT_TRUE(removeStringFromCSV(str, "https"));
204     EXPECT_EQ(str, expected);
205 
206     str = "https";
207     EXPECT_TRUE(removeStringFromCSV(str, "https"));
208     EXPECT_EQ(str, "");
209 }
210 
211 namespace
212 {
213 inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user";
214 
215 // Fake configs; referenced configs on real BMC
216 inline constexpr const char* rawFailLockConfig = R"(
217 deny=2
218 unlock_time=3
219 )";
220 inline constexpr const char* rawPWHistoryConfig = R"(
221 enforce_for_root
222 remember=0
223 )";
224 inline constexpr const char* rawPWQualityConfig = R"(
225 enforce_for_root
226 minlen=8
227 difok=0
228 lcredit=0
229 ocredit=0
230 dcredit=0
231 ucredit=0
232 )";
233 } // namespace
234 
dumpStringToFile(const std::string & str,const std::string & filePath)235 void dumpStringToFile(const std::string& str, const std::string& filePath)
236 {
237     std::ofstream outputFileStream;
238 
239     outputFileStream.exceptions(
240         std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
241 
242     outputFileStream.open(filePath, std::ios::out);
243     outputFileStream << str << "\n" << std::flush;
244     outputFileStream.close();
245 }
246 
removeFile(const std::string & filePath)247 void removeFile(const std::string& filePath)
248 {
249     std::filesystem::remove(filePath);
250 }
251 
252 class UserMgrInTest : public testing::Test, public UserMgr
253 {
254   public:
UserMgrInTest()255     UserMgrInTest() : UserMgr(busInTest, objectRootInTest)
256     {
257         tempFaillockConfigFile = "/tmp/test-data-XXXXXX";
258         mktemp(tempFaillockConfigFile.data());
259         EXPECT_NO_THROW(
260             dumpStringToFile(rawFailLockConfig, tempFaillockConfigFile));
261         tempPWHistoryConfigFile = "/tmp/test-data-XXXXXX";
262         mktemp(tempPWHistoryConfigFile.data());
263         EXPECT_NO_THROW(
264             dumpStringToFile(rawPWHistoryConfig, tempPWHistoryConfigFile));
265         tempPWQualityConfigFile = "/tmp/test-data-XXXXXX";
266         mktemp(tempPWQualityConfigFile.data());
267         EXPECT_NO_THROW(
268             dumpStringToFile(rawPWQualityConfig, tempPWQualityConfigFile));
269         // Set config files to test files
270         faillockConfigFile = tempFaillockConfigFile;
271         pwHistoryConfigFile = tempPWHistoryConfigFile;
272         pwQualityConfigFile = tempPWQualityConfigFile;
273 
274         ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
275                                       testing::Eq(true)))
276             .WillByDefault([this]() {
277                 ON_CALL(*this, isUserEnabled)
278                     .WillByDefault(testing::Return(true));
279                 testing::Return();
280             });
281 
282         ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
283                                       testing::Eq(false)))
284             .WillByDefault([this]() {
285                 ON_CALL(*this, isUserEnabled)
286                     .WillByDefault(testing::Return(false));
287                 testing::Return();
288             });
289 
290         ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return());
291 
292         ON_CALL(*this, executeUserClearFailRecords)
293             .WillByDefault(testing::Return());
294 
295         ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0));
296 
297         ON_CALL(*this, executeUserRename).WillByDefault(testing::Return());
298 
299         ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_))
300             .WillByDefault(testing::Return());
301 
302         ON_CALL(*this,
303                 executeUserModifyUserEnable(testing::_, testing::Eq(true)))
304             .WillByDefault([this]() {
305                 ON_CALL(*this, isUserEnabled)
306                     .WillByDefault(testing::Return(true));
307                 testing::Return();
308             });
309 
310         ON_CALL(*this,
311                 executeUserModifyUserEnable(testing::_, testing::Eq(false)))
312             .WillByDefault([this]() {
313                 ON_CALL(*this, isUserEnabled)
314                     .WillByDefault(testing::Return(false));
315                 testing::Return();
316             });
317 
318         ON_CALL(*this, executeGroupCreation(testing::_))
319             .WillByDefault(testing::Return());
320 
321         ON_CALL(*this, executeGroupDeletion(testing::_))
322             .WillByDefault(testing::Return());
323 
324         ON_CALL(*this, executeGroupCreation).WillByDefault(testing::Return());
325 
326         ON_CALL(*this, executeGroupDeletion).WillByDefault(testing::Return());
327     }
328 
~UserMgrInTest()329     ~UserMgrInTest() override
330     {
331         EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
332         EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
333         EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
334     }
335 
336     MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool),
337                 (override));
338 
339     MOCK_METHOD(void, executeUserDelete, (const char*), (override));
340 
341     MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override));
342 
343     MOCK_METHOD(size_t, getIpmiUsersCount, (), (override));
344 
345     MOCK_METHOD(void, executeUserRename, (const char*, const char*),
346                 (override));
347 
348     MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool),
349                 (override));
350 
351     MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool),
352                 (override));
353 
354     MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*),
355                 (override));
356 
357     MOCK_METHOD(void, executeGroupCreation, (const char*), (override));
358 
359     MOCK_METHOD(void, executeGroupDeletion, (const char*), (override));
360 
361     MOCK_METHOD(bool, isUserEnabled, (const std::string& userName), (override));
362 
363   protected:
364     static sdbusplus::bus_t busInTest;
365     std::string tempFaillockConfigFile;
366     std::string tempPWHistoryConfigFile;
367     std::string tempPWQualityConfigFile;
368 };
369 
370 sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
371 
TEST_F(UserMgrInTest,GetPamModuleConfValueOnSuccess)372 TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
373 {
374     std::string minlen;
375     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
376               0);
377     EXPECT_EQ(minlen, "8");
378     std::string deny;
379     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
380     EXPECT_EQ(deny, "2");
381     std::string remember;
382     EXPECT_EQ(
383         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
384         0);
385     EXPECT_EQ(remember, "0");
386 }
387 
TEST_F(UserMgrInTest,SetPamModuleConfValueOnSuccess)388 TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
389 {
390     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
391               0);
392     std::string minlen;
393     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
394               0);
395     EXPECT_EQ(minlen, "16");
396 
397     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
398     std::string deny;
399     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
400     EXPECT_EQ(deny, "3");
401 
402     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
403               0);
404     std::string remember;
405     EXPECT_EQ(
406         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
407         0);
408     EXPECT_EQ(remember, "1");
409 }
410 
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnSuccess)411 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
412 {
413     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
414               0);
415 
416     std::string tmpFile = tempPWQualityConfigFile + "_tmp";
417     EXPECT_FALSE(std::filesystem::exists(tmpFile));
418 
419     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
420 
421     tmpFile = tempFaillockConfigFile + "_tmp";
422     EXPECT_FALSE(std::filesystem::exists(tmpFile));
423 
424     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
425               0);
426 
427     tmpFile = tempPWHistoryConfigFile + "_tmp";
428     EXPECT_FALSE(std::filesystem::exists(tmpFile));
429 }
430 
TEST_F(UserMgrInTest,GetPamModuleConfValueOnFailure)431 TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
432 {
433     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
434     std::string minlen;
435     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
436               -1);
437 
438     EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
439     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
440               -1);
441 
442     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
443     std::string deny;
444     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
445 
446     EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
447     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
448 
449     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
450     std::string remember;
451     EXPECT_EQ(
452         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
453         -1);
454 
455     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
456     EXPECT_EQ(
457         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
458         -1);
459 }
460 
TEST_F(UserMgrInTest,SetPamModuleConfValueOnFailure)461 TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
462 {
463     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
464     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
465               -1);
466 
467     EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
468     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
469               -1);
470 
471     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
472     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
473 
474     EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
475     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
476 
477     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
478     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
479               -1);
480 
481     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
482     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
483               -1);
484 }
485 
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnFailure)486 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
487 {
488     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
489     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
490               -1);
491 
492     std::string tmpFile = tempPWQualityConfigFile + "_tmp";
493     EXPECT_FALSE(std::filesystem::exists(tmpFile));
494 
495     EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
496     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
497               -1);
498 
499     EXPECT_FALSE(std::filesystem::exists(tmpFile));
500 
501     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
502     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
503 
504     tmpFile = tempFaillockConfigFile + "_tmp";
505     EXPECT_FALSE(std::filesystem::exists(tmpFile));
506 
507     EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
508     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
509 
510     EXPECT_FALSE(std::filesystem::exists(tmpFile));
511 
512     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
513     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
514               -1);
515 
516     tmpFile = tempPWHistoryConfigFile + "_tmp";
517     EXPECT_FALSE(std::filesystem::exists(tmpFile));
518 
519     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
520     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
521               -1);
522 
523     EXPECT_FALSE(std::filesystem::exists(tmpFile));
524 }
525 
TEST_F(UserMgrInTest,IsUserExistEmptyInputThrowsError)526 TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
527 {
528     EXPECT_THROW(
529         isUserExist(""),
530         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
531 }
532 
TEST_F(UserMgrInTest,ThrowForUserDoesNotExistThrowsError)533 TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
534 {
535     EXPECT_THROW(throwForUserDoesNotExist("whatever"),
536                  sdbusplus::xyz::openbmc_project::User::Common::Error::
537                      UserNameDoesNotExist);
538 }
539 
TEST_F(UserMgrInTest,ThrowForUserExistsThrowsError)540 TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
541 {
542     EXPECT_THROW(
543         throwForUserExists("root"),
544         sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
545 }
546 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)547 TEST_F(
548     UserMgrInTest,
549     ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)
550 {
551     std::string strWith17Chars(17, 'A');
552     EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}),
553                  sdbusplus::xyz::openbmc_project::User::Common::Error::
554                      UserNameGroupFail);
555 }
556 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)557 TEST_F(
558     UserMgrInTest,
559     ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
560 {
561     std::string strWith31Chars(31, 'A');
562     EXPECT_THROW(
563         throwForUserNameConstraints(strWith31Chars, {}),
564         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
565 }
566 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)567 TEST_F(UserMgrInTest,
568        ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
569 {
570     std::string startWithNumber = "0ABC";
571     std::string startWithDisallowedCharacter = "[test";
572     EXPECT_THROW(
573         throwForUserNameConstraints(startWithNumber, {"ipmi"}),
574         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
575     EXPECT_THROW(
576         throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}),
577         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
578 }
579 
TEST_F(UserMgrInTest,UserAddNotRootFailedWithInternalFailure)580 TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure)
581 {
582     EXPECT_THROW(
583         UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true),
584         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
585 }
586 
TEST_F(UserMgrInTest,UserDeleteNotRootFailedWithInternalFailure)587 TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
588 {
589     EXPECT_THROW(
590         UserMgr::executeUserDelete("user0"),
591         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
592 }
593 
TEST_F(UserMgrInTest,ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)594 TEST_F(UserMgrInTest,
595        ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)
596 {
597     EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers));
598     EXPECT_THROW(
599         throwForMaxGrpUserCount({"ipmi"}),
600         sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
601 }
602 
TEST_F(UserMgrInTest,CreateUserThrowsInternalFailureWhenExecuteUserAddFails)603 TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails)
604 {
605     EXPECT_CALL(*this, executeUserAdd)
606         .WillOnce(testing::Throw(
607             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
608     EXPECT_THROW(
609         createUser("whatever", {"redfish"}, "", true),
610         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
611 }
612 
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)613 TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)
614 {
615     std::string username = "user";
616     EXPECT_NO_THROW(
617         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
618     EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
619         .WillOnce(testing::Throw(
620             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
621         .WillOnce(testing::DoDefault());
622 
623     EXPECT_THROW(
624         deleteUser(username),
625         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
626     EXPECT_NO_THROW(UserMgr::deleteUser(username));
627 }
628 
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)629 TEST_F(UserMgrInTest,
630        DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)
631 {
632     const char* username = "user";
633     EXPECT_NO_THROW(
634         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
635     EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username)))
636         .WillOnce(testing::Throw(
637             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
638         .WillOnce(testing::DoDefault());
639 
640     EXPECT_THROW(
641         deleteUser(username),
642         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
643     EXPECT_NO_THROW(UserMgr::deleteUser(username));
644 }
645 
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)646 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
647 {
648     EXPECT_THROW(
649         throwForInvalidPrivilege("whatever"),
650         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
651 }
652 
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)653 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)
654 {
655     EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin"));
656     EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator"));
657     EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user"));
658 }
659 
TEST_F(UserMgrInTest,ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)660 TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
661 {
662     EXPECT_THROW(
663         throwForInvalidGroups({"whatever"}),
664         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
665     EXPECT_THROW(
666         throwForInvalidGroups({"web"}),
667         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
668 }
669 
TEST_F(UserMgrInTest,ThrowForInvalidGroupsNoThrowWhenGroupIsValid)670 TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
671 {
672     EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
673     EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
674     EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
675     EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
676 }
677 
TEST_F(UserMgrInTest,RenameUserOnSuccess)678 TEST_F(UserMgrInTest, RenameUserOnSuccess)
679 {
680     std::string username = "user001";
681     EXPECT_NO_THROW(
682         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
683     std::string newUsername = "user002";
684 
685     EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername));
686 
687     // old username doesn't exist
688     EXPECT_THROW(getUserInfo(username),
689                  sdbusplus::xyz::openbmc_project::User::Common::Error::
690                      UserNameDoesNotExist);
691 
692     UserInfoMap userInfo = getUserInfo(newUsername);
693     EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
694     EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
695                 testing::UnorderedElementsAre("redfish", "ssh"));
696     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
697 
698     EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
699 }
700 
TEST_F(UserMgrInTest,RenameUserThrowsInternalFailureIfExecuteUserModifyFails)701 TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails)
702 {
703     std::string username = "user001";
704     EXPECT_NO_THROW(
705         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
706     std::string newUsername = "user002";
707 
708     EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
709                                          testing::StrEq(newUsername)))
710         .WillOnce(testing::Throw(
711             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
712     EXPECT_THROW(
713         UserMgr::renameUser(username, newUsername),
714         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
715 
716     // The original user is unchanged
717     UserInfoMap userInfo = getUserInfo(username);
718     EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
719     EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
720                 testing::UnorderedElementsAre("redfish", "ssh"));
721     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
722 
723     EXPECT_NO_THROW(UserMgr::deleteUser(username));
724 }
725 
TEST_F(UserMgrInTest,DefaultUserModifyFailedWithInternalFailure)726 TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
727 {
728     EXPECT_THROW(
729         UserMgr::executeUserRename("user0", "user1"),
730         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
731     EXPECT_THROW(
732         UserMgr::executeUserModify("user0", "ssh", true),
733         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
734 }
735 
TEST_F(UserMgrInTest,UpdateGroupsAndPrivOnSuccess)736 TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess)
737 {
738     std::string username = "user001";
739     EXPECT_NO_THROW(
740         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
741     EXPECT_NO_THROW(
742         updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"));
743     UserInfoMap userInfo = getUserInfo(username);
744     EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin");
745     EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
746                 testing::UnorderedElementsAre("ipmi", "ssh"));
747     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
748     EXPECT_NO_THROW(UserMgr::deleteUser(username));
749 }
750 
TEST_F(UserMgrInTest,UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)751 TEST_F(UserMgrInTest,
752        UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)
753 {
754     std::string username = "user001";
755     EXPECT_NO_THROW(
756         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
757     EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_,
758                                          testing::_))
759         .WillOnce(testing::Throw(
760             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
761     EXPECT_THROW(
762         updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"),
763         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
764     EXPECT_NO_THROW(UserMgr::deleteUser(username));
765 }
766 
TEST_F(UserMgrInTest,MinPasswordLengthReturnsIfValueIsTheSame)767 TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
768 {
769     initializeAccountPolicy();
770     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
771     UserMgr::minPasswordLength(8);
772     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
773 }
774 
TEST_F(UserMgrInTest,MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)775 TEST_F(UserMgrInTest,
776        MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)
777 {
778     initializeAccountPolicy();
779     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
780     EXPECT_THROW(
781         UserMgr::minPasswordLength(minPasswdLength - 1),
782         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
783     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
784 }
785 
TEST_F(UserMgrInTest,MinPasswordLengthOnSuccess)786 TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
787 {
788     initializeAccountPolicy();
789     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
790     UserMgr::minPasswordLength(16);
791     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
792 }
793 
TEST_F(UserMgrInTest,MinPasswordLengthOnFailure)794 TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
795 {
796     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
797     initializeAccountPolicy();
798     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
799     EXPECT_THROW(
800         UserMgr::minPasswordLength(16),
801         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
802     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
803 }
804 
TEST_F(UserMgrInTest,RememberOldPasswordTimesReturnsIfValueIsTheSame)805 TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame)
806 {
807     initializeAccountPolicy();
808     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
809     UserMgr::rememberOldPasswordTimes(8);
810     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
811     UserMgr::rememberOldPasswordTimes(8);
812     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
813 }
814 
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnSuccess)815 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
816 {
817     initializeAccountPolicy();
818     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
819     UserMgr::rememberOldPasswordTimes(16);
820     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
821 }
822 
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnFailure)823 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
824 {
825     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
826     initializeAccountPolicy();
827     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
828     EXPECT_THROW(
829         UserMgr::rememberOldPasswordTimes(16),
830         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
831     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
832 }
833 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)834 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
835 {
836     initializeAccountPolicy();
837     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
838     UserMgr::maxLoginAttemptBeforeLockout(2);
839     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
840 }
841 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnSuccess)842 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
843 {
844     initializeAccountPolicy();
845     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
846     UserMgr::maxLoginAttemptBeforeLockout(16);
847     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
848 }
849 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnFailure)850 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
851 {
852     initializeAccountPolicy();
853     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
854     EXPECT_THROW(
855         UserMgr::maxLoginAttemptBeforeLockout(16),
856         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
857     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
858 }
859 
TEST_F(UserMgrInTest,AccountUnlockTimeoutReturnsIfValueIsTheSame)860 TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
861 {
862     initializeAccountPolicy();
863     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
864     UserMgr::accountUnlockTimeout(3);
865     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
866 }
867 
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnSuccess)868 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
869 {
870     initializeAccountPolicy();
871     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
872     UserMgr::accountUnlockTimeout(16);
873     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
874 }
875 
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnFailure)876 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
877 {
878     initializeAccountPolicy();
879     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
880     EXPECT_THROW(
881         UserMgr::accountUnlockTimeout(16),
882         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
883     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
884 }
885 
TEST_F(UserMgrInTest,UserEnableOnSuccess)886 TEST_F(UserMgrInTest, UserEnableOnSuccess)
887 {
888     std::string username = "user001";
889     EXPECT_NO_THROW(
890         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
891     UserInfoMap userInfo = getUserInfo(username);
892     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
893 
894     EXPECT_NO_THROW(userEnable(username, false));
895 
896     userInfo = getUserInfo(username);
897     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false);
898 
899     EXPECT_NO_THROW(UserMgr::deleteUser(username));
900 }
901 
TEST_F(UserMgrInTest,CreateDeleteUserSuccessForHostConsole)902 TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole)
903 {
904     std::string username = "user001";
905     EXPECT_NO_THROW(
906         UserMgr::createUser(username, {"hostconsole"}, "priv-user", true));
907     EXPECT_NO_THROW(UserMgr::deleteUser(username));
908     EXPECT_NO_THROW(
909         UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true));
910     EXPECT_NO_THROW(UserMgr::deleteUser(username));
911     EXPECT_NO_THROW(
912         UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true));
913     EXPECT_NO_THROW(UserMgr::deleteUser(username));
914 }
915 
TEST_F(UserMgrInTest,UserEnableThrowsInternalFailureIfExecuteUserModifyFail)916 TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail)
917 {
918     std::string username = "user001";
919     EXPECT_NO_THROW(
920         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
921     UserInfoMap userInfo = getUserInfo(username);
922     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
923 
924     EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username),
925                                                    testing::Eq(false)))
926         .WillOnce(testing::Throw(
927             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
928     EXPECT_THROW(
929         userEnable(username, false),
930         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
931 
932     userInfo = getUserInfo(username);
933     // Stay unchanged
934     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
935 
936     EXPECT_NO_THROW(UserMgr::deleteUser(username));
937 }
938 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)939 TEST_F(
940     UserMgrInTest,
941     UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
942 {
943     EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
944 }
945 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptZeroFailuresReturnsFalse)946 TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
947 {
948     std::string username = "user001";
949     initializeAccountPolicy();
950     // Example output from BMC
951     // root:~# faillock --user root
952     // root:
953     // When   Type   Source   Valid
954     std::vector<std::string> output = {"whatever",
955                                        "When   Type   Source   Valid"};
956     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
957         .WillOnce(testing::Return(output));
958 
959     EXPECT_FALSE(userLockedForFailedAttempt(username));
960 }
961 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptFailIfGetFailedAttemptFail)962 TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail)
963 {
964     std::string username = "user001";
965     initializeAccountPolicy();
966     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
967         .WillOnce(testing::Throw(
968             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
969 
970     EXPECT_THROW(
971         userLockedForFailedAttempt(username),
972         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
973 }
974 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)975 TEST_F(UserMgrInTest,
976        UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
977 {
978     std::string username = "user001";
979     initializeAccountPolicy();
980 
981     // Choose a date in the past.
982     std::vector<std::string> output = {"whatever",
983                                        "10/24/2002 00:00:00 type source V"};
984     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
985         .WillOnce(testing::Return(output));
986 
987     EXPECT_THROW(
988         userLockedForFailedAttempt(username),
989         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
990 }
991 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)992 TEST_F(UserMgrInTest,
993        UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)
994 {
995     std::string username = "user001";
996     initializeAccountPolicy();
997 
998     // Choose a date in the past.
999     std::vector<std::string> output = {"whatever",
1000                                        "2002-10-24 00:00:00 type source V"};
1001     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
1002         .WillOnce(testing::Return(output));
1003 
1004     EXPECT_EQ(userLockedForFailedAttempt(username), false);
1005 }
1006 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationOnSuccess)1007 TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess)
1008 {
1009     // Base Redfish Roles
1010     EXPECT_NO_THROW(
1011         checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator"));
1012     EXPECT_NO_THROW(
1013         checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator"));
1014     EXPECT_NO_THROW(
1015         checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly"));
1016     // Base Redfish Privileges
1017     EXPECT_NO_THROW(
1018         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login"));
1019     EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1020         "openbmc_rfp_ConfigureManager"));
1021     EXPECT_NO_THROW(
1022         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers"));
1023     EXPECT_NO_THROW(
1024         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf"));
1025     EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1026         "openbmc_rfp_ConfigureComponents"));
1027     // OEM Redfish Roles
1028     EXPECT_NO_THROW(
1029         checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService"));
1030     // OEM Redfish Privileges
1031     EXPECT_NO_THROW(
1032         checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService"));
1033 }
1034 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)1035 TEST_F(UserMgrInTest,
1036        CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)
1037 {
1038     std::string groupName(maxSystemGroupNameLength + 1, 'A');
1039     EXPECT_THROW(
1040         checkAndThrowForDisallowedGroupCreation(groupName),
1041         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1042 }
1043 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)1044 TEST_F(
1045     UserMgrInTest,
1046     CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1047 {
1048     EXPECT_THROW(
1049         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"),
1050         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1051     EXPECT_THROW(
1052         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"),
1053         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1054 }
1055 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)1056 TEST_F(
1057     UserMgrInTest,
1058     CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1059 {
1060     EXPECT_THROW(
1061         checkAndThrowForDisallowedGroupCreation("google_rfp_"),
1062         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1063     EXPECT_THROW(
1064         checkAndThrowForDisallowedGroupCreation("com_rfp_"),
1065         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1066 }
1067 
TEST_F(UserMgrInTest,CheckAndThrowForMaxGroupCountOnSuccess)1068 TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1069 {
1070     constexpr size_t predefGroupCount = 4;
1071 
1072     EXPECT_THAT(allGroups().size(), predefGroupCount);
1073     for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1074     {
1075         std::string groupName = "openbmc_rfr_role";
1076         groupName += std::to_string(i);
1077         EXPECT_NO_THROW(createGroup(groupName));
1078     }
1079     EXPECT_THROW(
1080         createGroup("openbmc_rfr_AnotherRole"),
1081         sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
1082     for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1083     {
1084         std::string groupName = "openbmc_rfr_role";
1085         groupName += std::to_string(i);
1086         EXPECT_NO_THROW(deleteGroup(groupName));
1087     }
1088 }
1089 
TEST_F(UserMgrInTest,CheckAndThrowForGroupExist)1090 TEST_F(UserMgrInTest, CheckAndThrowForGroupExist)
1091 {
1092     std::string groupName = "openbmc_rfr_role";
1093     EXPECT_NO_THROW(createGroup(groupName));
1094     EXPECT_THROW(
1095         createGroup(groupName),
1096         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1097     EXPECT_NO_THROW(deleteGroup(groupName));
1098 }
1099 
TEST_F(UserMgrInTest,ByDefaultAllGroupsArePredefinedGroups)1100 TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1101 {
1102     EXPECT_THAT(allGroups(), testing::UnorderedElementsAre(
1103                                  "redfish", "ipmi", "ssh", "hostconsole"));
1104 }
1105 
TEST_F(UserMgrInTest,AddGroupThrowsIfPreDefinedGroupAdd)1106 TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1107 {
1108     EXPECT_THROW(
1109         createGroup("ipmi"),
1110         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1111     EXPECT_THROW(
1112         createGroup("redfish"),
1113         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1114     EXPECT_THROW(
1115         createGroup("ssh"),
1116         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1117     EXPECT_THROW(
1118         createGroup("hostconsole"),
1119         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1120 }
1121 
TEST_F(UserMgrInTest,DeleteGroupThrowsIfGroupIsNotAllowedToChange)1122 TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1123 {
1124     EXPECT_THROW(
1125         deleteGroup("ipmi"),
1126         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1127     EXPECT_THROW(
1128         deleteGroup("redfish"),
1129         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1130     EXPECT_THROW(
1131         deleteGroup("ssh"),
1132         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1133     EXPECT_THROW(
1134         deleteGroup("hostconsole"),
1135         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1136 }
1137 
TEST_F(UserMgrInTest,CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)1138 TEST_F(UserMgrInTest,
1139        CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)
1140 {
1141     EXPECT_CALL(*this, executeGroupCreation)
1142         .WillOnce(testing::Throw(
1143             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1144     EXPECT_THROW(
1145         createGroup("openbmc_rfr_role1"),
1146         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1147 }
1148 
TEST_F(UserMgrInTest,DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)1149 TEST_F(UserMgrInTest,
1150        DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)
1151 {
1152     std::string groupName = "openbmc_rfr_role1";
1153     EXPECT_NO_THROW(UserMgr::createGroup(groupName));
1154     EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName)))
1155         .WillOnce(testing::Throw(
1156             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1157         .WillOnce(testing::DoDefault());
1158 
1159     EXPECT_THROW(
1160         deleteGroup(groupName),
1161         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1162     EXPECT_NO_THROW(UserMgr::deleteGroup(groupName));
1163 }
1164 
TEST_F(UserMgrInTest,CheckAndThrowForGroupNotExist)1165 TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1166 {
1167     EXPECT_THROW(deleteGroup("whatever"),
1168                  sdbusplus::xyz::openbmc_project::User::Common::Error::
1169                      GroupNameDoesNotExist);
1170 }
1171 
TEST(ReadAllGroupsOnSystemTest,OnlyReturnsPredefinedGroups)1172 TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1173 {
1174     EXPECT_THAT(
1175         UserMgr::readAllGroupsOnSystem(),
1176         testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole"));
1177 }
1178 
1179 } // namespace user
1180 } // namespace phosphor
1181