git.fiddlerwoaroof.com
Browse code

Refactor tokens and test random key generation

Ed Langley authored on 14/06/2017 00:07:37
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
-