blob: 33e0576caba83a44d8f9700580d846e543fa71bb [file] [log] [blame]
Vishwanatha Subbanna035a9692017-09-15 18:50:43 +05301#include <sys/stat.h>
2#include <string>
3#include <fstream>
4#include <experimental/filesystem>
5#include <gtest/gtest.h>
6#include <sdbusplus/bus.hpp>
7#include "user.hpp"
8namespace phosphor
9{
10namespace user
11{
12
13namespace fs = std::experimental::filesystem;
14
15constexpr auto path = "/dummy/user";
16constexpr auto testShadow = "/tmp/__tshadow__";
Vishwanatha Subbanna035a9692017-09-15 18:50:43 +053017constexpr auto shadowCompare = "/tmp/__tshadowCompare__";
18
19// New password
20constexpr auto password = "passw0rd";
21
22constexpr auto MD5 = "1";
23constexpr auto SHA512 = "6";
24constexpr auto salt = "1G.cK/YP";
25
26// Example entry matching /etc/shadow structure
27constexpr auto spPwdp = "$1$1G.cK/YP$JI5t0oliPxZveXOvLcZ/H.:17344:1:90:7:::";
28
29class UserTest : public ::testing::Test
30{
31 public:
32 const std::string md5Salt = '$' + std::string(MD5) + '$'
33 + std::string(salt) + '$';
34 const std::string shaSalt = '$' + std::string(SHA512) + '$'
35 + std::string(salt) + '$';
36
37 const std::string entry = fs::path(path).filename().string() +
38 ':' + std::string(spPwdp);
39 sdbusplus::bus::bus bus;
40 phosphor::user::User user;
41
42 // Gets called as part of each TEST_F construction
43 UserTest()
44 : bus(sdbusplus::bus::new_default()),
45 user(bus, path)
46 {
47 // Create a shadow file entry
48 std::ofstream file(testShadow);
49 file << entry;
50 file.close();
51
52 // File to compare against
53 std::ofstream compare(shadowCompare);
54 compare << entry;
55 compare.close();
56 }
57
58 // Gets called as part of each TEST_F destruction
59 ~UserTest()
60 {
61 if (fs::exists(testShadow))
62 {
63 fs::remove(testShadow);
64 }
65
Vishwanatha Subbanna035a9692017-09-15 18:50:43 +053066 if (fs::exists(shadowCompare))
67 {
68 fs::remove(shadowCompare);
69 }
70 }
71
72 /** @brief wrapper for get crypt field */
73 auto getCryptField(char* data)
74 {
75 return User::getCryptField(
76 std::forward<decltype(data)>(data));
77 }
78
79 /** @brief wrapper for getSaltString */
80 auto getSaltString(const std::string& crypt,
81 const std::string& salt)
82 {
83 return User::getSaltString(
84 std::forward<decltype(crypt)>(crypt),
85 std::forward<decltype(salt)>(salt));
86 }
87
88 /** @brief wrapper for generateHash */
89 auto generateHash(const std::string& password,
90 const std::string& salt)
91 {
92 return User::generateHash(
93 std::forward<decltype(password)>(password),
94 std::forward<decltype(salt)>(salt));
95 }
96
97 /** @brief Applies the new password */
98 auto applyPassword()
99 {
Richard Marian Thomaiyar1f5a0022017-12-16 15:11:47 +0530100 return user.applyPassword(testShadow, password, salt);
Vishwanatha Subbanna035a9692017-09-15 18:50:43 +0530101 }
102};
103
104/** @brief Makes sure that SHA512 crypt field is extracted
105 */
106TEST_F(UserTest, sha512GetCryptField)
107{
108 auto salt = const_cast<char*>(shaSalt.c_str());
109 EXPECT_EQ(SHA512, this->getCryptField(salt));
110}
111
112/** @brief Makes sure that MD5 crypt field is extracted as default
113 */
114TEST_F(UserTest, md55GetCryptFieldDefault)
115{
116 auto salt = const_cast<char*>("hello");
117 EXPECT_EQ(MD5, this->getCryptField(salt));
118}
119
120/** @brief Makes sure that MD5 crypt field is extracted
121 */
122TEST_F(UserTest, md55GetCryptField)
123{
124 auto salt = const_cast<char*>(md5Salt.c_str());
125 EXPECT_EQ(MD5, this->getCryptField(salt));
126}
127
128/** @brief Makes sure that salt string is put within $$
129 */
130TEST_F(UserTest, getSaltString)
131{
132 EXPECT_EQ(md5Salt, this->getSaltString(MD5, salt));
133}
134
135/** @brief Makes sure hash is generated correctly
136 */
137TEST_F(UserTest, generateHash)
138{
139 std::string sample = crypt(password, md5Salt.c_str());
140 std::string actual = generateHash(password, md5Salt);
141 EXPECT_EQ(sample, actual);
142}
143
144/** @brief Verifies that the correct password is written to file
145 */
146TEST_F(UserTest, applyPassword)
147{
148 // Update the password
149 applyPassword();
150
151 // Read files and compare
152 std::ifstream shadow(testShadow);
153 std::ifstream copy(shadowCompare);
154
155 std::string shadowEntry;
156 shadow >> shadowEntry;
157
158 std::string shadowCompareEntry;
159 copy >> shadowCompareEntry;
160
161 EXPECT_EQ(shadowEntry, shadowCompareEntry);
162}
163
Vishwanatha Subbanna035a9692017-09-15 18:50:43 +0530164/** @brief Verifies the permissions are correct
165 */
166TEST_F(UserTest, verifyShadowPermission)
167{
168 // Change the permission to 400-> -r--------
169 chmod(testShadow, S_IRUSR);
170 chmod(shadowCompare, S_IRUSR);
171
172 // Update the password so that the temp file is in action
173 applyPassword();
174
175 // Compare the permission of 2 files.
176 // file rename would make sure that the permissions
177 // of old are moved to new
178 struct stat shadow{};
179 struct stat compare{};
180
181 stat(testShadow, &shadow);
182 stat(shadowCompare, &compare);
183 EXPECT_EQ(shadow.st_mode, compare.st_mode);
184}
185
186} // namespace user
187} // namespace phosphor