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(std::ofstream::failbit | std::ofstream::badbit |
240                                 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).WillByDefault(testing::Return(true));
278             testing::Return();
279         });
280 
281         ON_CALL(*this, executeUserAdd(testing::_, testing::_, testing::_,
282                                       testing::Eq(false)))
283             .WillByDefault([this]() {
284             ON_CALL(*this, isUserEnabled).WillByDefault(testing::Return(false));
285             testing::Return();
286         });
287 
288         ON_CALL(*this, executeUserDelete).WillByDefault(testing::Return());
289 
290         ON_CALL(*this, executeUserClearFailRecords)
291             .WillByDefault(testing::Return());
292 
293         ON_CALL(*this, getIpmiUsersCount).WillByDefault(testing::Return(0));
294 
295         ON_CALL(*this, executeUserRename).WillByDefault(testing::Return());
296 
297         ON_CALL(*this, executeUserModify(testing::_, testing::_, testing::_))
298             .WillByDefault(testing::Return());
299 
300         ON_CALL(*this,
301                 executeUserModifyUserEnable(testing::_, testing::Eq(true)))
302             .WillByDefault([this]() {
303             ON_CALL(*this, isUserEnabled).WillByDefault(testing::Return(true));
304             testing::Return();
305         });
306 
307         ON_CALL(*this,
308                 executeUserModifyUserEnable(testing::_, testing::Eq(false)))
309             .WillByDefault([this]() {
310             ON_CALL(*this, isUserEnabled).WillByDefault(testing::Return(false));
311             testing::Return();
312         });
313 
314         ON_CALL(*this, executeGroupCreation(testing::_))
315             .WillByDefault(testing::Return());
316 
317         ON_CALL(*this, executeGroupDeletion(testing::_))
318             .WillByDefault(testing::Return());
319 
320         ON_CALL(*this, executeGroupCreation).WillByDefault(testing::Return());
321 
322         ON_CALL(*this, executeGroupDeletion).WillByDefault(testing::Return());
323     }
324 
~UserMgrInTest()325     ~UserMgrInTest() override
326     {
327         EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
328         EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
329         EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
330     }
331 
332     MOCK_METHOD(void, executeUserAdd, (const char*, const char*, bool, bool),
333                 (override));
334 
335     MOCK_METHOD(void, executeUserDelete, (const char*), (override));
336 
337     MOCK_METHOD(void, executeUserClearFailRecords, (const char*), (override));
338 
339     MOCK_METHOD(size_t, getIpmiUsersCount, (), (override));
340 
341     MOCK_METHOD(void, executeUserRename, (const char*, const char*),
342                 (override));
343 
344     MOCK_METHOD(void, executeUserModify, (const char*, const char*, bool),
345                 (override));
346 
347     MOCK_METHOD(void, executeUserModifyUserEnable, (const char*, bool),
348                 (override));
349 
350     MOCK_METHOD(std::vector<std::string>, getFailedAttempt, (const char*),
351                 (override));
352 
353     MOCK_METHOD(void, executeGroupCreation, (const char*), (override));
354 
355     MOCK_METHOD(void, executeGroupDeletion, (const char*), (override));
356 
357     MOCK_METHOD(bool, isUserEnabled, (const std::string& userName), (override));
358 
359   protected:
360     static sdbusplus::bus_t busInTest;
361     std::string tempFaillockConfigFile;
362     std::string tempPWHistoryConfigFile;
363     std::string tempPWQualityConfigFile;
364 };
365 
366 sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
367 
TEST_F(UserMgrInTest,GetPamModuleConfValueOnSuccess)368 TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
369 {
370     std::string minlen;
371     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
372               0);
373     EXPECT_EQ(minlen, "8");
374     std::string deny;
375     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
376     EXPECT_EQ(deny, "2");
377     std::string remember;
378     EXPECT_EQ(
379         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
380         0);
381     EXPECT_EQ(remember, "0");
382 }
383 
TEST_F(UserMgrInTest,SetPamModuleConfValueOnSuccess)384 TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
385 {
386     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
387               0);
388     std::string minlen;
389     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
390               0);
391     EXPECT_EQ(minlen, "16");
392 
393     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
394     std::string deny;
395     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
396     EXPECT_EQ(deny, "3");
397 
398     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
399               0);
400     std::string remember;
401     EXPECT_EQ(
402         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
403         0);
404     EXPECT_EQ(remember, "1");
405 }
406 
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnSuccess)407 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
408 {
409     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
410               0);
411 
412     std::string tmpFile = tempPWQualityConfigFile + "_tmp";
413     EXPECT_FALSE(std::filesystem::exists(tmpFile));
414 
415     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), 0);
416 
417     tmpFile = tempFaillockConfigFile + "_tmp";
418     EXPECT_FALSE(std::filesystem::exists(tmpFile));
419 
420     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
421               0);
422 
423     tmpFile = tempPWHistoryConfigFile + "_tmp";
424     EXPECT_FALSE(std::filesystem::exists(tmpFile));
425 }
426 
TEST_F(UserMgrInTest,GetPamModuleConfValueOnFailure)427 TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
428 {
429     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
430     std::string minlen;
431     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
432               -1);
433 
434     EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
435     EXPECT_EQ(getPamModuleConfValue(tempPWQualityConfigFile, "minlen", minlen),
436               -1);
437 
438     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
439     std::string deny;
440     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
441 
442     EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
443     EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
444 
445     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
446     std::string remember;
447     EXPECT_EQ(
448         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
449         -1);
450 
451     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
452     EXPECT_EQ(
453         getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
454         -1);
455 }
456 
TEST_F(UserMgrInTest,SetPamModuleConfValueOnFailure)457 TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
458 {
459     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
460     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
461               -1);
462 
463     EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
464     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
465               -1);
466 
467     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
468     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
469 
470     EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
471     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
472 
473     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
474     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
475               -1);
476 
477     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
478     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
479               -1);
480 }
481 
TEST_F(UserMgrInTest,SetPamModuleConfValueTempFileOnFailure)482 TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
483 {
484     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
485     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
486               -1);
487 
488     std::string tmpFile = tempPWQualityConfigFile + "_tmp";
489     EXPECT_FALSE(std::filesystem::exists(tmpFile));
490 
491     EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
492     EXPECT_EQ(setPamModuleConfValue(tempPWQualityConfigFile, "minlen", "16"),
493               -1);
494 
495     EXPECT_FALSE(std::filesystem::exists(tmpFile));
496 
497     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
498     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
499 
500     tmpFile = tempFaillockConfigFile + "_tmp";
501     EXPECT_FALSE(std::filesystem::exists(tmpFile));
502 
503     EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
504     EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
505 
506     EXPECT_FALSE(std::filesystem::exists(tmpFile));
507 
508     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
509     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
510               -1);
511 
512     tmpFile = tempPWHistoryConfigFile + "_tmp";
513     EXPECT_FALSE(std::filesystem::exists(tmpFile));
514 
515     EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
516     EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
517               -1);
518 
519     EXPECT_FALSE(std::filesystem::exists(tmpFile));
520 }
521 
TEST_F(UserMgrInTest,IsUserExistEmptyInputThrowsError)522 TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
523 {
524     EXPECT_THROW(
525         isUserExist(""),
526         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
527 }
528 
TEST_F(UserMgrInTest,ThrowForUserDoesNotExistThrowsError)529 TEST_F(UserMgrInTest, ThrowForUserDoesNotExistThrowsError)
530 {
531     EXPECT_THROW(throwForUserDoesNotExist("whatever"),
532                  sdbusplus::xyz::openbmc_project::User::Common::Error::
533                      UserNameDoesNotExist);
534 }
535 
TEST_F(UserMgrInTest,ThrowForUserExistsThrowsError)536 TEST_F(UserMgrInTest, ThrowForUserExistsThrowsError)
537 {
538     EXPECT_THROW(
539         throwForUserExists("root"),
540         sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameExists);
541 }
542 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)543 TEST_F(
544     UserMgrInTest,
545     ThrowForUserNameConstraintsExceedIpmiMaxUserNameLenThrowsUserNameGroupFail)
546 {
547     std::string strWith17Chars(17, 'A');
548     EXPECT_THROW(throwForUserNameConstraints(strWith17Chars, {"ipmi"}),
549                  sdbusplus::xyz::openbmc_project::User::Common::Error::
550                      UserNameGroupFail);
551 }
552 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)553 TEST_F(
554     UserMgrInTest,
555     ThrowForUserNameConstraintsExceedSystemMaxUserNameLenThrowsInvalidArgument)
556 {
557     std::string strWith31Chars(31, 'A');
558     EXPECT_THROW(
559         throwForUserNameConstraints(strWith31Chars, {}),
560         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
561 }
562 
TEST_F(UserMgrInTest,ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)563 TEST_F(UserMgrInTest,
564        ThrowForUserNameConstraintsRegexMismatchThrowsInvalidArgument)
565 {
566     std::string startWithNumber = "0ABC";
567     std::string startWithDisallowedCharacter = "[test";
568     EXPECT_THROW(
569         throwForUserNameConstraints(startWithNumber, {"ipmi"}),
570         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
571     EXPECT_THROW(
572         throwForUserNameConstraints(startWithDisallowedCharacter, {"ipmi"}),
573         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
574 }
575 
TEST_F(UserMgrInTest,UserAddNotRootFailedWithInternalFailure)576 TEST_F(UserMgrInTest, UserAddNotRootFailedWithInternalFailure)
577 {
578     EXPECT_THROW(
579         UserMgr::executeUserAdd("user0", "ipmi,ssh", true, true),
580         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
581 }
582 
TEST_F(UserMgrInTest,UserDeleteNotRootFailedWithInternalFailure)583 TEST_F(UserMgrInTest, UserDeleteNotRootFailedWithInternalFailure)
584 {
585     EXPECT_THROW(
586         UserMgr::executeUserDelete("user0"),
587         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
588 }
589 
TEST_F(UserMgrInTest,ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)590 TEST_F(UserMgrInTest,
591        ThrowForMaxGrpUserCountThrowsNoResourceWhenIpmiUserExceedLimit)
592 {
593     EXPECT_CALL(*this, getIpmiUsersCount()).WillOnce(Return(ipmiMaxUsers));
594     EXPECT_THROW(
595         throwForMaxGrpUserCount({"ipmi"}),
596         sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
597 }
598 
TEST_F(UserMgrInTest,CreateUserThrowsInternalFailureWhenExecuteUserAddFails)599 TEST_F(UserMgrInTest, CreateUserThrowsInternalFailureWhenExecuteUserAddFails)
600 {
601     EXPECT_CALL(*this, executeUserAdd)
602         .WillOnce(testing::Throw(
603             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
604     EXPECT_THROW(
605         createUser("whatever", {"redfish"}, "", true),
606         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
607 }
608 
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)609 TEST_F(UserMgrInTest, DeleteUserThrowsInternalFailureWhenExecuteUserDeleteFails)
610 {
611     std::string username = "user";
612     EXPECT_NO_THROW(
613         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
614     EXPECT_CALL(*this, executeUserDelete(testing::StrEq(username)))
615         .WillOnce(testing::Throw(
616             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
617         .WillOnce(testing::DoDefault());
618 
619     EXPECT_THROW(
620         deleteUser(username),
621         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
622     EXPECT_NO_THROW(UserMgr::deleteUser(username));
623 }
624 
TEST_F(UserMgrInTest,DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)625 TEST_F(UserMgrInTest,
626        DeleteUserThrowsInternalFailureWhenExecuteUserClearFailRecords)
627 {
628     const char* username = "user";
629     EXPECT_NO_THROW(
630         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
631     EXPECT_CALL(*this, executeUserClearFailRecords(testing::StrEq(username)))
632         .WillOnce(testing::Throw(
633             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
634         .WillOnce(testing::DoDefault());
635 
636     EXPECT_THROW(
637         deleteUser(username),
638         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
639     EXPECT_NO_THROW(UserMgr::deleteUser(username));
640 }
641 
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)642 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeThrowsWhenPrivilegeIsInvalid)
643 {
644     EXPECT_THROW(
645         throwForInvalidPrivilege("whatever"),
646         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
647 }
648 
TEST_F(UserMgrInTest,ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)649 TEST_F(UserMgrInTest, ThrowForInvalidPrivilegeNoThrowWhenPrivilegeIsValid)
650 {
651     EXPECT_NO_THROW(throwForInvalidPrivilege("priv-admin"));
652     EXPECT_NO_THROW(throwForInvalidPrivilege("priv-operator"));
653     EXPECT_NO_THROW(throwForInvalidPrivilege("priv-user"));
654 }
655 
TEST_F(UserMgrInTest,ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)656 TEST_F(UserMgrInTest, ThrowForInvalidGroupsThrowsWhenGroupIsInvalid)
657 {
658     EXPECT_THROW(
659         throwForInvalidGroups({"whatever"}),
660         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
661     EXPECT_THROW(
662         throwForInvalidGroups({"web"}),
663         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
664 }
665 
TEST_F(UserMgrInTest,ThrowForInvalidGroupsNoThrowWhenGroupIsValid)666 TEST_F(UserMgrInTest, ThrowForInvalidGroupsNoThrowWhenGroupIsValid)
667 {
668     EXPECT_NO_THROW(throwForInvalidGroups({"ipmi"}));
669     EXPECT_NO_THROW(throwForInvalidGroups({"ssh"}));
670     EXPECT_NO_THROW(throwForInvalidGroups({"redfish"}));
671     EXPECT_NO_THROW(throwForInvalidGroups({"hostconsole"}));
672 }
673 
TEST_F(UserMgrInTest,RenameUserOnSuccess)674 TEST_F(UserMgrInTest, RenameUserOnSuccess)
675 {
676     std::string username = "user001";
677     EXPECT_NO_THROW(
678         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
679     std::string newUsername = "user002";
680 
681     EXPECT_NO_THROW(UserMgr::renameUser(username, newUsername));
682 
683     // old username doesn't exist
684     EXPECT_THROW(getUserInfo(username),
685                  sdbusplus::xyz::openbmc_project::User::Common::Error::
686                      UserNameDoesNotExist);
687 
688     UserInfoMap userInfo = getUserInfo(newUsername);
689     EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
690     EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
691                 testing::UnorderedElementsAre("redfish", "ssh"));
692     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
693 
694     EXPECT_NO_THROW(UserMgr::deleteUser(newUsername));
695 }
696 
TEST_F(UserMgrInTest,RenameUserThrowsInternalFailureIfExecuteUserModifyFails)697 TEST_F(UserMgrInTest, RenameUserThrowsInternalFailureIfExecuteUserModifyFails)
698 {
699     std::string username = "user001";
700     EXPECT_NO_THROW(
701         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
702     std::string newUsername = "user002";
703 
704     EXPECT_CALL(*this, executeUserRename(testing::StrEq(username),
705                                          testing::StrEq(newUsername)))
706         .WillOnce(testing::Throw(
707             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
708     EXPECT_THROW(
709         UserMgr::renameUser(username, newUsername),
710         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
711 
712     // The original user is unchanged
713     UserInfoMap userInfo = getUserInfo(username);
714     EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-user");
715     EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
716                 testing::UnorderedElementsAre("redfish", "ssh"));
717     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
718 
719     EXPECT_NO_THROW(UserMgr::deleteUser(username));
720 }
721 
TEST_F(UserMgrInTest,DefaultUserModifyFailedWithInternalFailure)722 TEST_F(UserMgrInTest, DefaultUserModifyFailedWithInternalFailure)
723 {
724     EXPECT_THROW(
725         UserMgr::executeUserRename("user0", "user1"),
726         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
727     EXPECT_THROW(
728         UserMgr::executeUserModify("user0", "ssh", true),
729         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
730 }
731 
TEST_F(UserMgrInTest,UpdateGroupsAndPrivOnSuccess)732 TEST_F(UserMgrInTest, UpdateGroupsAndPrivOnSuccess)
733 {
734     std::string username = "user001";
735     EXPECT_NO_THROW(
736         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
737     EXPECT_NO_THROW(
738         updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"));
739     UserInfoMap userInfo = getUserInfo(username);
740     EXPECT_EQ(std::get<Privilege>(userInfo["UserPrivilege"]), "priv-admin");
741     EXPECT_THAT(std::get<GroupList>(userInfo["UserGroups"]),
742                 testing::UnorderedElementsAre("ipmi", "ssh"));
743     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
744     EXPECT_NO_THROW(UserMgr::deleteUser(username));
745 }
746 
TEST_F(UserMgrInTest,UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)747 TEST_F(UserMgrInTest,
748        UpdateGroupsAndPrivThrowsInternalFailureIfExecuteUserModifyFail)
749 {
750     std::string username = "user001";
751     EXPECT_NO_THROW(
752         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
753     EXPECT_CALL(*this, executeUserModify(testing::StrEq(username), testing::_,
754                                          testing::_))
755         .WillOnce(testing::Throw(
756             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
757     EXPECT_THROW(
758         updateGroupsAndPriv(username, {"ipmi", "ssh"}, "priv-admin"),
759         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
760     EXPECT_NO_THROW(UserMgr::deleteUser(username));
761 }
762 
TEST_F(UserMgrInTest,MinPasswordLengthReturnsIfValueIsTheSame)763 TEST_F(UserMgrInTest, MinPasswordLengthReturnsIfValueIsTheSame)
764 {
765     initializeAccountPolicy();
766     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
767     UserMgr::minPasswordLength(8);
768     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
769 }
770 
TEST_F(UserMgrInTest,MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)771 TEST_F(UserMgrInTest,
772        MinPasswordLengthRejectsTooShortPasswordWithInvalidArgument)
773 {
774     initializeAccountPolicy();
775     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
776     EXPECT_THROW(
777         UserMgr::minPasswordLength(minPasswdLength - 1),
778         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
779     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
780 }
781 
TEST_F(UserMgrInTest,MinPasswordLengthOnSuccess)782 TEST_F(UserMgrInTest, MinPasswordLengthOnSuccess)
783 {
784     initializeAccountPolicy();
785     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
786     UserMgr::minPasswordLength(16);
787     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 16);
788 }
789 
TEST_F(UserMgrInTest,MinPasswordLengthOnFailure)790 TEST_F(UserMgrInTest, MinPasswordLengthOnFailure)
791 {
792     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWQualityConfigFile));
793     initializeAccountPolicy();
794     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
795     EXPECT_THROW(
796         UserMgr::minPasswordLength(16),
797         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
798     EXPECT_EQ(AccountPolicyIface::minPasswordLength(), 8);
799 }
800 
TEST_F(UserMgrInTest,RememberOldPasswordTimesReturnsIfValueIsTheSame)801 TEST_F(UserMgrInTest, RememberOldPasswordTimesReturnsIfValueIsTheSame)
802 {
803     initializeAccountPolicy();
804     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
805     UserMgr::rememberOldPasswordTimes(8);
806     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
807     UserMgr::rememberOldPasswordTimes(8);
808     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 8);
809 }
810 
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnSuccess)811 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnSuccess)
812 {
813     initializeAccountPolicy();
814     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
815     UserMgr::rememberOldPasswordTimes(16);
816     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 16);
817 }
818 
TEST_F(UserMgrInTest,RememberOldPasswordTimesOnFailure)819 TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
820 {
821     EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
822     initializeAccountPolicy();
823     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
824     EXPECT_THROW(
825         UserMgr::rememberOldPasswordTimes(16),
826         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
827     EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
828 }
829 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)830 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutReturnsIfValueIsTheSame)
831 {
832     initializeAccountPolicy();
833     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
834     UserMgr::maxLoginAttemptBeforeLockout(2);
835     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
836 }
837 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnSuccess)838 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnSuccess)
839 {
840     initializeAccountPolicy();
841     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
842     UserMgr::maxLoginAttemptBeforeLockout(16);
843     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 16);
844 }
845 
TEST_F(UserMgrInTest,MaxLoginAttemptBeforeLockoutOnFailure)846 TEST_F(UserMgrInTest, MaxLoginAttemptBeforeLockoutOnFailure)
847 {
848     initializeAccountPolicy();
849     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
850     EXPECT_THROW(
851         UserMgr::maxLoginAttemptBeforeLockout(16),
852         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
853     EXPECT_EQ(AccountPolicyIface::maxLoginAttemptBeforeLockout(), 2);
854 }
855 
TEST_F(UserMgrInTest,AccountUnlockTimeoutReturnsIfValueIsTheSame)856 TEST_F(UserMgrInTest, AccountUnlockTimeoutReturnsIfValueIsTheSame)
857 {
858     initializeAccountPolicy();
859     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
860     UserMgr::accountUnlockTimeout(3);
861     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
862 }
863 
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnSuccess)864 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnSuccess)
865 {
866     initializeAccountPolicy();
867     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
868     UserMgr::accountUnlockTimeout(16);
869     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 16);
870 }
871 
TEST_F(UserMgrInTest,AccountUnlockTimeoutOnFailure)872 TEST_F(UserMgrInTest, AccountUnlockTimeoutOnFailure)
873 {
874     initializeAccountPolicy();
875     EXPECT_NO_THROW(dumpStringToFile("whatever", tempFaillockConfigFile));
876     EXPECT_THROW(
877         UserMgr::accountUnlockTimeout(16),
878         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
879     EXPECT_EQ(AccountPolicyIface::accountUnlockTimeout(), 3);
880 }
881 
TEST_F(UserMgrInTest,UserEnableOnSuccess)882 TEST_F(UserMgrInTest, UserEnableOnSuccess)
883 {
884     std::string username = "user001";
885     EXPECT_NO_THROW(
886         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
887     UserInfoMap userInfo = getUserInfo(username);
888     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
889 
890     EXPECT_NO_THROW(userEnable(username, false));
891 
892     userInfo = getUserInfo(username);
893     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), false);
894 
895     EXPECT_NO_THROW(UserMgr::deleteUser(username));
896 }
897 
TEST_F(UserMgrInTest,CreateDeleteUserSuccessForHostConsole)898 TEST_F(UserMgrInTest, CreateDeleteUserSuccessForHostConsole)
899 {
900     std::string username = "user001";
901     EXPECT_NO_THROW(
902         UserMgr::createUser(username, {"hostconsole"}, "priv-user", true));
903     EXPECT_NO_THROW(UserMgr::deleteUser(username));
904     EXPECT_NO_THROW(
905         UserMgr::createUser(username, {"hostconsole"}, "priv-admin", true));
906     EXPECT_NO_THROW(UserMgr::deleteUser(username));
907     EXPECT_NO_THROW(
908         UserMgr::createUser(username, {"hostconsole"}, "priv-operator", true));
909     EXPECT_NO_THROW(UserMgr::deleteUser(username));
910 }
911 
TEST_F(UserMgrInTest,UserEnableThrowsInternalFailureIfExecuteUserModifyFail)912 TEST_F(UserMgrInTest, UserEnableThrowsInternalFailureIfExecuteUserModifyFail)
913 {
914     std::string username = "user001";
915     EXPECT_NO_THROW(
916         UserMgr::createUser(username, {"redfish", "ssh"}, "priv-user", true));
917     UserInfoMap userInfo = getUserInfo(username);
918     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
919 
920     EXPECT_CALL(*this, executeUserModifyUserEnable(testing::StrEq(username),
921                                                    testing::Eq(false)))
922         .WillOnce(testing::Throw(
923             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
924     EXPECT_THROW(
925         userEnable(username, false),
926         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
927 
928     userInfo = getUserInfo(username);
929     // Stay unchanged
930     EXPECT_EQ(std::get<UserEnabled>(userInfo["UserEnabled"]), true);
931 
932     EXPECT_NO_THROW(UserMgr::deleteUser(username));
933 }
934 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)935 TEST_F(
936     UserMgrInTest,
937     UserLockedForFailedAttemptReturnsFalseIfMaxLoginAttemptBeforeLockoutIsZero)
938 {
939     EXPECT_FALSE(userLockedForFailedAttempt("whatever"));
940 }
941 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptZeroFailuresReturnsFalse)942 TEST_F(UserMgrInTest, UserLockedForFailedAttemptZeroFailuresReturnsFalse)
943 {
944     std::string username = "user001";
945     initializeAccountPolicy();
946     // Example output from BMC
947     // root:~# faillock --user root
948     // root:
949     // When   Type   Source   Valid
950     std::vector<std::string> output = {"whatever",
951                                        "When   Type   Source   Valid"};
952     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
953         .WillOnce(testing::Return(output));
954 
955     EXPECT_FALSE(userLockedForFailedAttempt(username));
956 }
957 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptFailIfGetFailedAttemptFail)958 TEST_F(UserMgrInTest, UserLockedForFailedAttemptFailIfGetFailedAttemptFail)
959 {
960     std::string username = "user001";
961     initializeAccountPolicy();
962     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
963         .WillOnce(testing::Throw(
964             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
965 
966     EXPECT_THROW(
967         userLockedForFailedAttempt(username),
968         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
969 }
970 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)971 TEST_F(UserMgrInTest,
972        UserLockedForFailedAttemptThrowsInternalFailureIfWrongDateFormat)
973 {
974     std::string username = "user001";
975     initializeAccountPolicy();
976 
977     // Choose a date in the past.
978     std::vector<std::string> output = {"whatever",
979                                        "10/24/2002 00:00:00 type source V"};
980     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
981         .WillOnce(testing::Return(output));
982 
983     EXPECT_THROW(
984         userLockedForFailedAttempt(username),
985         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
986 }
987 
TEST_F(UserMgrInTest,UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)988 TEST_F(UserMgrInTest,
989        UserLockedForFailedAttemptReturnsFalseIfLastFailTimeHasTimedOut)
990 {
991     std::string username = "user001";
992     initializeAccountPolicy();
993 
994     // Choose a date in the past.
995     std::vector<std::string> output = {"whatever",
996                                        "2002-10-24 00:00:00 type source V"};
997     EXPECT_CALL(*this, getFailedAttempt(testing::StrEq(username.c_str())))
998         .WillOnce(testing::Return(output));
999 
1000     EXPECT_EQ(userLockedForFailedAttempt(username), false);
1001 }
1002 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationOnSuccess)1003 TEST_F(UserMgrInTest, CheckAndThrowForDisallowedGroupCreationOnSuccess)
1004 {
1005     // Base Redfish Roles
1006     EXPECT_NO_THROW(
1007         checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Administrator"));
1008     EXPECT_NO_THROW(
1009         checkAndThrowForDisallowedGroupCreation("openbmc_rfr_Operator"));
1010     EXPECT_NO_THROW(
1011         checkAndThrowForDisallowedGroupCreation("openbmc_rfr_ReadOnly"));
1012     // Base Redfish Privileges
1013     EXPECT_NO_THROW(
1014         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_Login"));
1015     EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1016         "openbmc_rfp_ConfigureManager"));
1017     EXPECT_NO_THROW(
1018         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureUsers"));
1019     EXPECT_NO_THROW(
1020         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_ConfigureSelf"));
1021     EXPECT_NO_THROW(checkAndThrowForDisallowedGroupCreation(
1022         "openbmc_rfp_ConfigureComponents"));
1023     // OEM Redfish Roles
1024     EXPECT_NO_THROW(
1025         checkAndThrowForDisallowedGroupCreation("openbmc_orfr_PowerService"));
1026     // OEM Redfish Privileges
1027     EXPECT_NO_THROW(
1028         checkAndThrowForDisallowedGroupCreation("openbmc_orfp_PowerService"));
1029 }
1030 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)1031 TEST_F(UserMgrInTest,
1032        CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameTooLong)
1033 {
1034     std::string groupName(maxSystemGroupNameLength + 1, 'A');
1035     EXPECT_THROW(
1036         checkAndThrowForDisallowedGroupCreation(groupName),
1037         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1038 }
1039 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)1040 TEST_F(
1041     UserMgrInTest,
1042     CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedCharacters)
1043 {
1044     EXPECT_THROW(
1045         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_?owerService"),
1046         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1047     EXPECT_THROW(
1048         checkAndThrowForDisallowedGroupCreation("openbmc_rfp_-owerService"),
1049         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1050 }
1051 
TEST_F(UserMgrInTest,CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)1052 TEST_F(
1053     UserMgrInTest,
1054     CheckAndThrowForDisallowedGroupCreationThrowsIfGroupNameHasDisallowedPrefix)
1055 {
1056     EXPECT_THROW(
1057         checkAndThrowForDisallowedGroupCreation("google_rfp_"),
1058         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1059     EXPECT_THROW(
1060         checkAndThrowForDisallowedGroupCreation("com_rfp_"),
1061         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1062 }
1063 
TEST_F(UserMgrInTest,CheckAndThrowForMaxGroupCountOnSuccess)1064 TEST_F(UserMgrInTest, CheckAndThrowForMaxGroupCountOnSuccess)
1065 {
1066     constexpr size_t predefGroupCount = 4;
1067 
1068     EXPECT_THAT(allGroups().size(), predefGroupCount);
1069     for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1070     {
1071         std::string groupName = "openbmc_rfr_role";
1072         groupName += std::to_string(i);
1073         EXPECT_NO_THROW(createGroup(groupName));
1074     }
1075     EXPECT_THROW(
1076         createGroup("openbmc_rfr_AnotherRole"),
1077         sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource);
1078     for (size_t i = 0; i < maxSystemGroupCount - predefGroupCount; ++i)
1079     {
1080         std::string groupName = "openbmc_rfr_role";
1081         groupName += std::to_string(i);
1082         EXPECT_NO_THROW(deleteGroup(groupName));
1083     }
1084 }
1085 
TEST_F(UserMgrInTest,CheckAndThrowForGroupExist)1086 TEST_F(UserMgrInTest, CheckAndThrowForGroupExist)
1087 {
1088     std::string groupName = "openbmc_rfr_role";
1089     EXPECT_NO_THROW(createGroup(groupName));
1090     EXPECT_THROW(
1091         createGroup(groupName),
1092         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1093     EXPECT_NO_THROW(deleteGroup(groupName));
1094 }
1095 
TEST_F(UserMgrInTest,ByDefaultAllGroupsArePredefinedGroups)1096 TEST_F(UserMgrInTest, ByDefaultAllGroupsArePredefinedGroups)
1097 {
1098     EXPECT_THAT(allGroups(), testing::UnorderedElementsAre(
1099                                  "redfish", "ipmi", "ssh", "hostconsole"));
1100 }
1101 
TEST_F(UserMgrInTest,AddGroupThrowsIfPreDefinedGroupAdd)1102 TEST_F(UserMgrInTest, AddGroupThrowsIfPreDefinedGroupAdd)
1103 {
1104     EXPECT_THROW(
1105         createGroup("ipmi"),
1106         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1107     EXPECT_THROW(
1108         createGroup("redfish"),
1109         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1110     EXPECT_THROW(
1111         createGroup("ssh"),
1112         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1113     EXPECT_THROW(
1114         createGroup("hostconsole"),
1115         sdbusplus::xyz::openbmc_project::User::Common::Error::GroupNameExists);
1116 }
1117 
TEST_F(UserMgrInTest,DeleteGroupThrowsIfGroupIsNotAllowedToChange)1118 TEST_F(UserMgrInTest, DeleteGroupThrowsIfGroupIsNotAllowedToChange)
1119 {
1120     EXPECT_THROW(
1121         deleteGroup("ipmi"),
1122         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1123     EXPECT_THROW(
1124         deleteGroup("redfish"),
1125         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1126     EXPECT_THROW(
1127         deleteGroup("ssh"),
1128         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1129     EXPECT_THROW(
1130         deleteGroup("hostconsole"),
1131         sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
1132 }
1133 
TEST_F(UserMgrInTest,CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)1134 TEST_F(UserMgrInTest,
1135        CreateGroupThrowsInternalFailureWhenExecuteGroupCreateFails)
1136 {
1137     EXPECT_CALL(*this, executeGroupCreation)
1138         .WillOnce(testing::Throw(
1139             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()));
1140     EXPECT_THROW(
1141         createGroup("openbmc_rfr_role1"),
1142         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1143 }
1144 
TEST_F(UserMgrInTest,DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)1145 TEST_F(UserMgrInTest,
1146        DeleteGroupThrowsInternalFailureWhenExecuteGroupDeleteFails)
1147 {
1148     std::string groupName = "openbmc_rfr_role1";
1149     EXPECT_NO_THROW(UserMgr::createGroup(groupName));
1150     EXPECT_CALL(*this, executeGroupDeletion(testing::StrEq(groupName)))
1151         .WillOnce(testing::Throw(
1152             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure()))
1153         .WillOnce(testing::DoDefault());
1154 
1155     EXPECT_THROW(
1156         deleteGroup(groupName),
1157         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure);
1158     EXPECT_NO_THROW(UserMgr::deleteGroup(groupName));
1159 }
1160 
TEST_F(UserMgrInTest,CheckAndThrowForGroupNotExist)1161 TEST_F(UserMgrInTest, CheckAndThrowForGroupNotExist)
1162 {
1163     EXPECT_THROW(deleteGroup("whatever"),
1164                  sdbusplus::xyz::openbmc_project::User::Common::Error::
1165                      GroupNameDoesNotExist);
1166 }
1167 
TEST(ReadAllGroupsOnSystemTest,OnlyReturnsPredefinedGroups)1168 TEST(ReadAllGroupsOnSystemTest, OnlyReturnsPredefinedGroups)
1169 {
1170     EXPECT_THAT(
1171         UserMgr::readAllGroupsOnSystem(),
1172         testing::UnorderedElementsAre("redfish", "ipmi", "ssh", "hostconsole"));
1173 }
1174 
1175 } // namespace user
1176 } // namespace phosphor
1177