Browse code
Refactor tokens and test random key generation
Ed Langley authored on 14/06/2017 00:07:37
Showing 5 changed files
Showing 5 changed files
... | ... |
@@ -253,7 +253,6 @@ int logs_authentication() |
253 | 253 |
"logged authorizer should be authorizer"); |
254 | 254 |
check (test_logger->logged_token() == token, |
255 | 255 |
"logged token should be token"); |
256 |
- std::cout <<test_logger->logged_reason() << std::endl; |
|
257 | 256 |
check (test_logger->logged_reason() == reason, |
258 | 257 |
"logged reason should be reason"); |
259 | 258 |
succeed(); |
... | ... |
@@ -306,4 +305,3 @@ int main (int argc, char *argv[]) |
306 | 305 |
{ |
307 | 306 |
return !runtests(); |
308 | 307 |
} |
309 |
- |
... | ... |
@@ -39,12 +39,13 @@ installer init_installer() |
39 | 39 |
fstreams fstreams (fstreams::create()); |
40 | 40 |
pwd pwd (pwd::create()); |
41 | 41 |
unistd unistd (unistd::create()); |
42 |
- directory directory (directory::create (unistd, pwd)); |
|
43 | 42 |
stdlib stdlib (stdlib::get()); |
44 | 43 |
sys_time time (sys_time::get()); |
45 | 44 |
int code_digits = 6; |
46 | 45 |
totp_generator generator = totp_generator (time, code_digits); |
47 |
- tokens tokens (tokens::create (fstreams, generator)); |
|
46 |
+ random_source rand (random_source::create(fstreams)); |
|
47 |
+ directory directory (directory::create (unistd, pwd)); |
|
48 |
+ tokens tokens (tokens::create (fstreams, generator, rand)); |
|
48 | 49 |
installer installer (installer::create (tokens, unistd, directory, |
49 | 50 |
generator)); |
50 | 51 |
|
... | ... |
@@ -29,9 +29,10 @@ class tokens_impl : public tokens_ifc |
29 | 29 |
private: |
30 | 30 |
fstreams fstreams_; |
31 | 31 |
totp_generator generator_; |
32 |
+ random_source rand_; |
|
32 | 33 |
public: |
33 |
- tokens_impl (const fstreams &fstreams, const totp_generator generator) : |
|
34 |
- fstreams_ (fstreams), generator_ (generator) {} |
|
34 |
+ tokens_impl (const fstreams &fstreams, const totp_generator generator, const random_source rand) : |
|
35 |
+ fstreams_ (fstreams), generator_ (generator), rand_ (rand) {} |
|
35 | 36 |
std::string token (const user &user) const override |
36 | 37 |
{ |
37 | 38 |
// Get key |
... | ... |
@@ -44,7 +45,6 @@ public: |
44 | 45 |
base32 codec; |
45 | 46 |
std::vector<uint8_t> key = codec.decode (line); |
46 | 47 |
|
47 |
- // TODO: generate the token |
|
48 | 48 |
return generator_.generate_token (std::string (key.begin(), key.end())); |
49 | 49 |
} |
50 | 50 |
|
... | ... |
@@ -62,18 +62,6 @@ private: |
62 | 62 |
return stream->good(); |
63 | 63 |
} |
64 | 64 |
|
65 |
- std::string generate_key() const |
|
66 |
- { |
|
67 |
- base32 codec; |
|
68 |
- random_source rand = random_source::create(fstreams_); |
|
69 |
- // get randomness |
|
70 |
- int length = 10; |
|
71 |
- std::vector<uint8_t> random_bytes (rand.get_random_bytes(length)); |
|
72 |
- // base32encode it |
|
73 |
- std::string key = codec.encode (random_bytes); |
|
74 |
- return key; |
|
75 |
- } |
|
76 |
- |
|
77 | 65 |
std::string read_key (const user &user) const |
78 | 66 |
{ |
79 | 67 |
std::string file_path = get_key_path (user); |
... | ... |
@@ -91,6 +79,18 @@ private: |
91 | 79 |
return line; |
92 | 80 |
} |
93 | 81 |
public: |
82 |
+ // TODO: test to make sure that generate_key's output is different for different random numbers |
|
83 |
+ std::string generate_key() const override |
|
84 |
+ { |
|
85 |
+ base32 codec; |
|
86 |
+ // get randomness |
|
87 |
+ int length = 10; |
|
88 |
+ std::vector<uint8_t> random_bytes (rand_.get_random_bytes(length)); |
|
89 |
+ // base32encode it |
|
90 |
+ std::string key = codec.encode (random_bytes); |
|
91 |
+ return key; |
|
92 |
+ } |
|
93 |
+ |
|
94 | 94 |
std::string ensure_key (const user &user) const override |
95 | 95 |
{ |
96 | 96 |
if (!key_exists (user)) { |
... | ... |
@@ -102,19 +102,20 @@ public: |
102 | 102 |
} |
103 | 103 |
} |
104 | 104 |
|
105 |
- void save (const user &user, const std::string &token) const override |
|
105 |
+ void save (const user &user, const std::string &key) const override |
|
106 | 106 |
{ |
107 | 107 |
std::string file_path = get_key_path (user); |
108 | 108 |
fstreams::postream stream (fstreams_.open_ofstream (file_path, |
109 | 109 |
std::ios_base::trunc)); |
110 |
- *stream << token << std::endl; |
|
110 |
+ *stream << key<< std::endl; |
|
111 | 111 |
} |
112 | 112 |
}; |
113 | 113 |
} |
114 | 114 |
|
115 | 115 |
tokens tokens::create (const fstreams &fstreams, |
116 |
- const totp_generator &generator) |
|
116 |
+ const totp_generator &generator, |
|
117 |
+ const random_source &rand) |
|
117 | 118 |
{ |
118 | 119 |
return tokens (tokens::delegate |
119 |
- (new tokens_impl (fstreams, generator))); |
|
120 |
+ (new tokens_impl (fstreams, generator, rand))); |
|
120 | 121 |
} |
... | ... |
@@ -19,6 +19,7 @@ |
19 | 19 |
#include "user.h" |
20 | 20 |
#include "sys_fstream.h" |
21 | 21 |
#include "generator.h" |
22 |
+#include "random_source.h" |
|
22 | 23 |
|
23 | 24 |
class tokens_ifc |
24 | 25 |
{ |
... | ... |
@@ -29,10 +30,13 @@ public: |
29 | 30 |
{ |
30 | 31 |
return ""; |
31 | 32 |
} |
33 |
+ virtual std::string generate_key() const { |
|
34 |
+ return ""; |
|
35 |
+ } |
|
32 | 36 |
virtual std::string ensure_key (const user &user) const |
33 | 37 |
{ |
34 | 38 |
return ""; |
35 |
- }; |
|
39 |
+ } |
|
36 | 40 |
virtual void save (const user &user, const std::string &token) const {} |
37 | 41 |
}; |
38 | 42 |
|
... | ... |
@@ -47,6 +51,10 @@ public: |
47 | 51 |
delegate_ (delegate) {} |
48 | 52 |
tokens() : tokens ( |
49 | 53 |
delegate (new tokens_ifc)) {} |
54 |
+ std::string generate_key (const user &user) const |
|
55 |
+ { |
|
56 |
+ return delegate_->generate_key (); |
|
57 |
+ } |
|
50 | 58 |
std::string ensure_key (const user &user) const |
51 | 59 |
{ |
52 | 60 |
return delegate_->ensure_key (user); |
... | ... |
@@ -60,8 +68,8 @@ public: |
60 | 68 |
return delegate_->save (user, token); |
61 | 69 |
} |
62 | 70 |
static tokens create (const fstreams &fstreams, |
63 |
- const totp_generator &generator); |
|
71 |
+ const totp_generator &generator, |
|
72 |
+ const random_source &rand); |
|
64 | 73 |
}; |
65 | 74 |
|
66 | 75 |
#endif |
67 |
- |
... | ... |
@@ -22,6 +22,7 @@ |
22 | 22 |
#include "user.h" |
23 | 23 |
#include "sys_fstream.h" |
24 | 24 |
#include "generator.h" |
25 |
+#include "base32.h" |
|
25 | 26 |
|
26 | 27 |
class fake_user : public user_ifc |
27 | 28 |
{ |
... | ... |
@@ -45,6 +46,13 @@ private: |
45 | 46 |
mutable std::string captured_filename_; |
46 | 47 |
mutable std::shared_ptr<std::ostringstream> capture_stream_; |
47 | 48 |
public: |
49 |
+ pstream open_fstream (const std::string &file_path) const override |
|
50 |
+ { |
|
51 |
+ pstream result = std::make_shared<std::istringstream>(""); |
|
52 |
+ std::string badinator (1, '\0'); |
|
53 |
+ result->read (&badinator[0], badinator.size()); |
|
54 |
+ return result; |
|
55 |
+ } |
|
48 | 56 |
postream open_ofstream (const std::string &file_path, |
49 | 57 |
std::ios_base::openmode mode) const override |
50 | 58 |
{ |
... | ... |
@@ -83,6 +91,34 @@ public: |
83 | 91 |
} |
84 | 92 |
}; |
85 | 93 |
|
94 |
+class fake_rand : public random_source_ifc |
|
95 |
+{ |
|
96 |
+public: |
|
97 |
+ fake_rand () |
|
98 |
+ {} |
|
99 |
+ |
|
100 |
+ std::vector<uint8_t> get_random_bytes (int length) const override |
|
101 |
+ { |
|
102 |
+ return {}; |
|
103 |
+ } |
|
104 |
+}; |
|
105 |
+ |
|
106 |
+using octet_vector = std::vector<uint8_t>; |
|
107 |
+class fake_rand_with_specified_result : public random_source_ifc |
|
108 |
+{ |
|
109 |
+private: |
|
110 |
+ octet_vector expected_bytes_; |
|
111 |
+public: |
|
112 |
+ fake_rand_with_specified_result (octet_vector expected_bytes) |
|
113 |
+ : expected_bytes_ (expected_bytes) |
|
114 |
+ {} |
|
115 |
+ |
|
116 |
+ std::vector<uint8_t> get_random_bytes (int length) const override |
|
117 |
+ { |
|
118 |
+ return expected_bytes_; |
|
119 |
+ } |
|
120 |
+}; |
|
121 |
+ |
|
86 | 122 |
class fake_totp_generator : public token_generator_ifc |
87 | 123 |
{ |
88 | 124 |
private: |
... | ... |
@@ -110,10 +146,11 @@ int reads_from_the_right_file () |
110 | 146 |
token))); |
111 | 147 |
totp_generator generator (totp_generator::delegate (new |
112 | 148 |
fake_totp_generator (token))); |
149 |
+ random_source fake_rand(random_source::delegate (new class fake_rand)); |
|
113 | 150 |
|
114 | 151 |
//file_reader test_file_reader (file_reader::delegate (new fake_file_reader)); |
115 | 152 |
user test_user (user::delegate (new fake_user (home_directory))); |
116 |
- tokens supplier (tokens::create (test_streams, generator)); |
|
153 |
+ tokens supplier (tokens::create (test_streams, generator, fake_rand)); |
|
117 | 154 |
|
118 | 155 |
//when |
119 | 156 |
std::string actual = supplier.token (test_user); |
... | ... |
@@ -133,9 +170,10 @@ int returns_empty_string_if_file_open_fail() |
133 | 170 |
"654321"))); |
134 | 171 |
totp_generator generator (totp_generator::delegate (new |
135 | 172 |
fake_totp_generator ())); |
173 |
+ random_source fake_rand(random_source::delegate (new class fake_rand)); |
|
136 | 174 |
|
137 | 175 |
user test_user (user::delegate (new fake_user (home_directory))); |
138 |
- tokens supplier (tokens::create (test_streams, generator)); |
|
176 |
+ tokens supplier (tokens::create (test_streams, generator, fake_rand)); |
|
139 | 177 |
|
140 | 178 |
//when |
141 | 179 |
std::string actual = supplier.token (test_user); |
... | ... |
@@ -158,10 +196,11 @@ int returns_empty_string_if_file_too_short() |
158 | 196 |
token))); |
159 | 197 |
totp_generator generator (totp_generator::delegate (new |
160 | 198 |
fake_totp_generator (token))); |
199 |
+ random_source fake_rand(random_source::delegate (new class fake_rand)); |
|
161 | 200 |
|
162 | 201 |
//file_reader test_file_reader (file_reader::delegate (new fake_file_reader)); |
163 | 202 |
user test_user (user::delegate (new fake_user (home_directory))); |
164 |
- tokens supplier (tokens::create (test_streams, generator)); |
|
203 |
+ tokens supplier (tokens::create (test_streams, generator, fake_rand)); |
|
165 | 204 |
|
166 | 205 |
//when |
167 | 206 |
std::string actual = supplier.token (test_user); |
... | ... |
@@ -171,7 +210,7 @@ int returns_empty_string_if_file_too_short() |
171 | 210 |
succeed(); |
172 | 211 |
} |
173 | 212 |
|
174 |
-int writes_the_token () |
|
213 |
+int writes_the_key () |
|
175 | 214 |
{ |
176 | 215 |
// given |
177 | 216 |
std::string home_directory ("/somedir"); |
... | ... |
@@ -181,7 +220,8 @@ int writes_the_token () |
181 | 220 |
totp_generator generator (totp_generator::delegate (new |
182 | 221 |
fake_totp_generator ())); |
183 | 222 |
std::string token ("token"); |
184 |
- tokens tokens (tokens::create (test_streams, generator)); |
|
223 |
+ random_source fake_rand(random_source::delegate (new class fake_rand)); |
|
224 |
+ tokens tokens (tokens::create (test_streams, generator, fake_rand)); |
|
185 | 225 |
|
186 | 226 |
//when |
187 | 227 |
tokens.save (test_user, token); |
... | ... |
@@ -198,12 +238,62 @@ int writes_the_token () |
198 | 238 |
succeed(); |
199 | 239 |
} |
200 | 240 |
|
241 |
+int ensure_key_creates_key_file_if_not_exists () |
|
242 |
+{ |
|
243 |
+ // given |
|
244 |
+ std::string home_directory ("/somedir"); |
|
245 |
+ user test_user (user::delegate (new fake_user (home_directory))); |
|
246 |
+ mock_write_fstreams *mockfs (new mock_write_fstreams); |
|
247 |
+ |
|
248 |
+ fstreams test_streams{fstreams::delegate (mockfs)}; |
|
249 |
+ |
|
250 |
+ totp_generator generator (totp_generator::delegate (new fake_totp_generator ())); |
|
251 |
+ |
|
252 |
+ std::vector<uint8_t> random_bytes {4,2,4, 2,4, 2,4,2, 4,2}; |
|
253 |
+ random_source fake_rand(random_source::delegate (new fake_rand_with_specified_result(random_bytes))); |
|
254 |
+ tokens tokens (tokens::create (test_streams, generator, fake_rand)); |
|
255 |
+ |
|
256 |
+ //when |
|
257 |
+ std::string actual = tokens.ensure_key (test_user); |
|
258 |
+ |
|
259 |
+ base32 codec; |
|
260 |
+ octet_vector actual_decoded = codec.decode(actual); |
|
261 |
+ // then |
|
262 |
+ std::string expected_filename (home_directory + "/.dual_control"); |
|
263 |
+ check (mockfs->captured_filename() == expected_filename, |
|
264 |
+ "filename does not match"); |
|
265 |
+ check (random_bytes == actual_decoded, |
|
266 |
+ "key does not match"); |
|
267 |
+ succeed(); |
|
268 |
+} |
|
269 |
+ |
|
270 |
+int ensure_key_reads_key_file_if_exists () |
|
271 |
+{ |
|
272 |
+ //given |
|
273 |
+ std::string home_directory ("/somedir"); |
|
274 |
+ std::string key_file = home_directory + "/.dual_control"; |
|
275 |
+ std::string key ("AAAAAAAAAAAAAAAA"); |
|
276 |
+ user test_user (user::delegate (new fake_user (home_directory))); |
|
277 |
+ fstreams test_streams (fstreams::delegate (new fake_fstreams (key_file, |
|
278 |
+ key))); |
|
279 |
+ totp_generator generator (totp_generator::delegate (new fake_totp_generator ())); |
|
280 |
+ random_source fake_rand(random_source::delegate (new class fake_rand)); |
|
281 |
+ tokens tokens (tokens::create (test_streams, generator, fake_rand)); |
|
282 |
+ |
|
283 |
+ //when |
|
284 |
+ std::string actual = tokens.ensure_key (test_user); |
|
285 |
+ //then |
|
286 |
+ check(actual == key, "read key does not match given key"); |
|
287 |
+ succeed(); |
|
288 |
+} |
|
289 |
+ |
|
201 | 290 |
int run_tests() |
202 | 291 |
{ |
203 | 292 |
test (reads_from_the_right_file); |
204 | 293 |
test (returns_empty_string_if_file_open_fail); |
205 | 294 |
test (returns_empty_string_if_file_too_short); |
206 |
- test (writes_the_token); |
|
295 |
+ test (ensure_key_creates_key_file_if_not_exists); |
|
296 |
+ test (ensure_key_reads_key_file_if_exists); |
|
207 | 297 |
succeed(); |
208 | 298 |
} |
209 | 299 |
|
... | ... |
@@ -211,4 +301,3 @@ int main (int argc, char *argv[]) |
211 | 301 |
{ |
212 | 302 |
return !run_tests(); |
213 | 303 |
} |
214 |
- |