#include #include #include #include #include #include #include "user.hpp" namespace phosphor { namespace user { namespace fs = std::experimental::filesystem; constexpr auto path = "/dummy/user"; constexpr auto testShadow = "/tmp/__tshadow__"; constexpr auto shadowCompare = "/tmp/__tshadowCompare__"; // New password constexpr auto password = "passw0rd"; constexpr auto MD5 = "1"; constexpr auto SHA512 = "6"; constexpr auto salt = "1G.cK/YP"; // Example entry matching /etc/shadow structure constexpr auto spPwdp = "$1$1G.cK/YP$JI5t0oliPxZveXOvLcZ/H.:17344:1:90:7:::"; class UserTest : public ::testing::Test { public: const std::string md5Salt = '$' + std::string(MD5) + '$' + std::string(salt) + '$'; const std::string shaSalt = '$' + std::string(SHA512) + '$' + std::string(salt) + '$'; const std::string entry = fs::path(path).filename().string() + ':' + std::string(spPwdp); sdbusplus::bus::bus bus; phosphor::user::User user; // Gets called as part of each TEST_F construction UserTest() : bus(sdbusplus::bus::new_default()), user(bus, path) { // Create a shadow file entry std::ofstream file(testShadow); file << entry; file.close(); // File to compare against std::ofstream compare(shadowCompare); compare << entry; compare.close(); } // Gets called as part of each TEST_F destruction ~UserTest() { if (fs::exists(testShadow)) { fs::remove(testShadow); } if (fs::exists(shadowCompare)) { fs::remove(shadowCompare); } } /** @brief wrapper for get crypt field */ auto getCryptField(char* data) { return User::getCryptField(std::forward(data)); } /** @brief wrapper for getSaltString */ auto getSaltString(const std::string& crypt, const std::string& salt) { return User::getSaltString(std::forward(crypt), std::forward(salt)); } /** @brief wrapper for generateHash */ auto generateHash(const std::string& password, const std::string& salt) { return User::generateHash(std::forward(password), std::forward(salt)); } /** @brief Applies the new password */ auto applyPassword() { return user.applyPassword(testShadow, password, salt); } }; /** @brief Makes sure that SHA512 crypt field is extracted */ TEST_F(UserTest, sha512GetCryptField) { auto salt = const_cast(shaSalt.c_str()); EXPECT_EQ(SHA512, this->getCryptField(salt)); } /** @brief Makes sure that MD5 crypt field is extracted as default */ TEST_F(UserTest, md55GetCryptFieldDefault) { auto salt = const_cast("hello"); EXPECT_EQ(MD5, this->getCryptField(salt)); } /** @brief Makes sure that MD5 crypt field is extracted */ TEST_F(UserTest, md55GetCryptField) { auto salt = const_cast(md5Salt.c_str()); EXPECT_EQ(MD5, this->getCryptField(salt)); } /** @brief Makes sure that salt string is put within $$ */ TEST_F(UserTest, getSaltString) { EXPECT_EQ(md5Salt, this->getSaltString(MD5, salt)); } /** @brief Makes sure hash is generated correctly */ TEST_F(UserTest, generateHash) { std::string sample = crypt(password, md5Salt.c_str()); std::string actual = generateHash(password, md5Salt); EXPECT_EQ(sample, actual); } /** @brief Verifies that the correct password is written to file */ TEST_F(UserTest, applyPassword) { // Update the password applyPassword(); // Read files and compare std::ifstream shadow(testShadow); std::ifstream copy(shadowCompare); std::string shadowEntry; shadow >> shadowEntry; std::string shadowCompareEntry; copy >> shadowCompareEntry; EXPECT_EQ(shadowEntry, shadowCompareEntry); } /** @brief Verifies the permissions are correct */ TEST_F(UserTest, verifyShadowPermission) { // Change the permission to 400-> -r-------- chmod(testShadow, S_IRUSR); chmod(shadowCompare, S_IRUSR); // Update the password so that the temp file is in action applyPassword(); // Compare the permission of 2 files. // file rename would make sure that the permissions // of old are moved to new struct stat shadow { }; struct stat compare { }; stat(testShadow, &shadow); stat(shadowCompare, &compare); EXPECT_EQ(shadow.st_mode, compare.st_mode); } } // namespace user } // namespace phosphor