OpenVPN 3 Core Library
Loading...
Searching...
No Matches
test_userpass.cpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12
13#include "test_common.hpp"
14
16
17using namespace openvpn;
18
19const std::string optname = "auth";
20const std::string user_simple(
21 "auth username\n");
22const std::string user_tag(
23 "<auth>\n"
24 "username\n"
25 "</auth>\n");
26const std::string user_file_fn(UNITTEST_SOURCE_DIR "/userpass/user.txt");
27const std::string user_file(
28 "auth " + user_file_fn + "\n");
29const std::vector<std::string> user_only{
32};
33const std::string userpass_tag(
34 "<auth>\n"
35 "username\n"
36 "password\n"
37 "</auth>\n");
38const std::string userpass_file_fn(
39 UNITTEST_SOURCE_DIR "/userpass/userpass.txt");
40const std::string userpass_file(
41 "auth " + userpass_file_fn + "\n");
42const std::vector<std::string> user_pass{
45};
46const std::vector<std::string> onearg{
51const std::vector<std::string> overflow_files{
52 UNITTEST_SOURCE_DIR "/userpass/useroverflow.txt",
53 UNITTEST_SOURCE_DIR "/userpass/passoverflow.txt",
54};
55
62const std::vector<unsigned int> flag_combos_noargs_okay{
63 0,
65};
99
100TEST(UserPass, Missing)
101{
103 {
104 std::string user;
105 std::string pass;
106 std::vector<std::string> userpass;
107 OptionList cfg;
108 cfg.parse_from_config("otheropt", nullptr);
109 cfg.update_map();
110 UserPass::parse(cfg, optname, flags, user, pass);
111 ASSERT_TRUE(user.empty()) << "flags: " << flags;
112 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
113 user = "otheruser";
114 pass = "otherpass";
115 UserPass::parse(cfg, optname, flags, user, pass);
116 ASSERT_TRUE(user.empty()) << "flags: " << flags;
117 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
118 const bool ret = UserPass::parse(cfg, optname, flags, &userpass);
119 ASSERT_FALSE(ret) << "flags: " << flags;
120 ASSERT_EQ(userpass.size(), 0) << "flags: " << flags;
121 }
122 for (auto flags : flag_combos_required)
123 {
124 std::string user;
125 std::string pass;
126 std::vector<std::string> userpass;
127 OptionList cfg;
128 cfg.parse_from_config("otheropt", nullptr);
129 cfg.update_map();
130 ASSERT_THROW(
131 UserPass::parse(cfg, optname, flags, user, pass),
132 UserPass::creds_error)
133 << "flags: " << flags;
134 ASSERT_TRUE(user.empty()) << "flags: " << flags;
135 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
136 user = "otheruser";
137 pass = "otherpass";
138 ASSERT_THROW(
139 UserPass::parse(cfg, optname, flags, user, pass),
140 UserPass::creds_error)
141 << "flags: " << flags;
142 ASSERT_TRUE(user.empty()) << "flags: " << flags;
143 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
144 ASSERT_THROW(
145 UserPass::parse(cfg, optname, flags, &userpass),
146 UserPass::creds_error)
147 << "flags: " << flags;
148 ASSERT_EQ(userpass.size(), 0) << "flags: " << flags;
149 }
150}
151
152TEST(UserPass, NoArgs)
153{
154 for (auto flags : flag_combos_noargs_okay)
155 {
156 std::string user;
157 std::string pass;
158 std::vector<std::string> userpass;
159 OptionList cfg;
160 cfg.parse_from_config(optname, nullptr);
161 cfg.update_map();
162 UserPass::parse(cfg, optname, flags, user, pass);
163 ASSERT_TRUE(user.empty()) << "flags: " << flags;
164 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
165 user = "otheruser";
166 pass = "otherpass";
167 UserPass::parse(cfg, optname, flags, user, pass);
168 ASSERT_TRUE(user.empty()) << "flags: " << flags;
169 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
170 const bool ret = UserPass::parse(cfg, optname, flags, &userpass);
171 ASSERT_TRUE(ret) << "flags: " << flags;
172 ASSERT_EQ(userpass.size(), 0) << "flags: " << flags;
173 }
174 for (auto flags : flag_combos_required)
175 {
176 std::string user;
177 std::string pass;
178 std::vector<std::string> userpass;
179 OptionList cfg;
180 cfg.parse_from_config(optname, nullptr);
181 cfg.update_map();
182 ASSERT_THROW(
183 UserPass::parse(cfg, optname, flags, user, pass),
184 UserPass::creds_error)
185 << "flags: " << flags;
186 ASSERT_TRUE(user.empty()) << "flags: " << flags;
187 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
188 user = "otheruser";
189 pass = "otherpass";
190 ASSERT_THROW(
191 UserPass::parse(cfg, optname, flags, user, pass),
192 UserPass::creds_error)
193 << "flags: " << flags;
194 ASSERT_TRUE(user.empty()) << "flags: " << flags;
195 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
196 ASSERT_THROW(
197 UserPass::parse(cfg, optname, flags, &userpass),
198 UserPass::creds_error)
199 << "flags: " << flags;
200 ASSERT_EQ(userpass.size(), 0) << "flags: " << flags;
201 }
202}
203
204TEST(UserPass, UserOnly)
205{
207 {
208 for (auto &config_text : user_only)
209 {
210 std::string user;
211 std::string pass;
212 std::vector<std::string> userpass;
213 OptionList cfg;
214 cfg.parse_from_config(config_text, nullptr);
215 cfg.update_map();
216 UserPass::parse(cfg, optname, flags, user, pass);
217 ASSERT_EQ(user, "username") << "config: " << config_text << "flags: " << flags;
218 ASSERT_TRUE(pass.empty()) << "config: " << config_text << "flags: " << flags;
219 user = "otheruser";
220 pass = "otherpass";
221 UserPass::parse(cfg, optname, flags, user, pass);
222 ASSERT_EQ(user, "username") << "config: " << config_text << "flags: " << flags;
223 ASSERT_TRUE(pass.empty()) << "config: " << config_text << "flags: " << flags;
224 const bool ret = UserPass::parse(cfg, optname, flags, &userpass);
225 ASSERT_TRUE(ret) << "config: " << config_text << "flags: " << flags;
226 ASSERT_EQ(userpass.size(), 1) << "config: " << config_text << "flags: " << flags;
227 ASSERT_EQ(userpass[0], "username") << "config: " << config_text << "flags: " << flags;
228 }
229 /* filename instead of username */
230 {
231 std::string user;
232 std::string pass;
233 std::vector<std::string> userpass;
234 OptionList cfg;
235 cfg.parse_from_config(userpass_file, nullptr);
236 cfg.update_map();
237 UserPass::parse(cfg, optname, flags, user, pass);
238 ASSERT_EQ(user, userpass_file_fn) << "flags: " << flags;
239 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
240 user = "otheruser";
241 pass = "otherpass";
242 UserPass::parse(cfg, optname, flags, user, pass);
243 ASSERT_EQ(user, userpass_file_fn) << "flags: " << flags;
244 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
245 const bool ret = UserPass::parse(cfg, optname, flags, &userpass);
246 ASSERT_TRUE(ret) << "flags: " << flags;
247 ASSERT_EQ(userpass.size(), 1) << "flags: " << flags;
248 ASSERT_EQ(userpass[0], userpass_file_fn) << "flags: " << flags;
249 }
250 }
251 for (auto flags : flag_combos_pw_required)
252 {
253 for (auto &config_text : onearg)
254 {
255 std::string user;
256 std::string pass;
257 std::vector<std::string> userpass;
258 OptionList cfg;
259 cfg.parse_from_config(config_text, nullptr);
260 cfg.update_map();
261 ASSERT_THROW(
262 UserPass::parse(cfg, optname, flags, user, pass),
263 UserPass::creds_error)
264 << "config: " << config_text << "flags: " << flags;
265 user = "otheruser";
266 pass = "otherpass";
267 ASSERT_THROW(
268 UserPass::parse(cfg, optname, flags, user, pass),
269 UserPass::creds_error)
270 << "config: " << config_text << "flags: " << flags;
271 const bool ret = UserPass::parse(cfg, optname, flags, &userpass);
272 // FIXME?
273 ASSERT_TRUE(ret) << "config: " << config_text << "flags: " << flags;
274 }
275 }
276}
277
278TEST(UserPass, UserPass)
279{
280 for (auto flags : flag_combos_nofile)
281 {
282 for (auto &config_text : user_pass)
283 {
284 std::string user;
285 std::string pass;
286 std::vector<std::string> userpass;
287 auto flags_try_file = flags | UserPass::TRY_FILE;
288 OptionList cfg;
289 cfg.parse_from_config(config_text, nullptr);
290 cfg.update_map();
291 UserPass::parse(cfg, optname, flags_try_file, user, pass);
292 ASSERT_EQ(user, "username") << "config: " << config_text << "flags: " << flags;
293 ASSERT_EQ(pass, "password") << "config: " << config_text << "flags: " << flags;
294 user = "otheruser";
295 pass = "otherpass";
296 UserPass::parse(cfg, optname, flags_try_file, user, pass);
297 ASSERT_EQ(user, "username") << "config: " << config_text << "flags: " << flags;
298 ASSERT_EQ(pass, "password") << "config: " << config_text << "flags: " << flags;
299 const bool ret = UserPass::parse(cfg, optname, flags_try_file, &userpass);
300 ASSERT_TRUE(ret) << "config: " << config_text << "flags: " << flags;
301 ASSERT_EQ(userpass.size(), 2) << "config: " << config_text << "flags: " << flags;
302 ASSERT_EQ(userpass[0], "username") << "config: " << config_text << "flags: " << flags;
303 ASSERT_EQ(userpass[1], "password") << "config: " << config_text << "flags: " << flags;
304 }
305 }
306}
307
308TEST(UserPass, ParseFileUserOnly)
309{
311 {
312 std::string user;
313 std::string pass;
315 ASSERT_EQ(user, "username") << "flags: " << flags;
316 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
317 user = "otheruser";
318 pass = "otherpass";
320 ASSERT_EQ(user, "username") << "flags: " << flags;
321 ASSERT_TRUE(pass.empty()) << "flags: " << flags;
322 }
323 for (auto flags : flag_combos_pw_required)
324 {
325 for (auto &config_text : onearg)
326 {
327 std::string user;
328 std::string pass;
329 ASSERT_THROW(
331 UserPass::creds_error)
332 << "config: " << config_text << "flags: " << flags;
333 user = "otheruser";
334 pass = "otherpass";
335 ASSERT_THROW(
337 UserPass::creds_error)
338 << "config: " << config_text << "flags: " << flags;
339 }
340 }
341}
342
343TEST(UserPass, ParseFileUserPass)
344{
345 for (auto flags : flag_combos_nofile)
346 {
347 std::string user;
348 std::string pass;
350 ASSERT_EQ(user, "username") << "flags: " << flags;
351 ASSERT_EQ(pass, "password") << "flags: " << flags;
352 user = "otheruser";
353 pass = "otherpass";
355 ASSERT_EQ(user, "username") << "flags: " << flags;
356 ASSERT_EQ(pass, "password") << "flags: " << flags;
357 }
358}
359
360TEST(UserPass, ParseFileOverflow)
361{
362 for (auto flags : flag_combos_nofile)
363 {
364 for (auto &filename : overflow_files)
365 {
366 std::string user;
367 std::string pass;
368 ASSERT_ANY_THROW(UserPass::parse_file(filename, flags, user, pass))
369 << "file: " << filename << "flags: " << flags;
370 user = "otheruser";
371 pass = "otherpass";
372 ASSERT_ANY_THROW(UserPass::parse_file(filename, flags, user, pass))
373 << "file: " << filename << "flags: " << flags;
374 auto flags_try_file = flags | UserPass::TRY_FILE;
375 const std::string config_text = std::string("auth ") + filename;
376 std::vector<std::string> userpass;
377 OptionList cfg;
378 cfg.parse_from_config(config_text, nullptr);
379 cfg.update_map();
380 ASSERT_ANY_THROW(UserPass::parse(cfg, optname, flags_try_file, &userpass))
381 << "file: " << filename << "flags: " << flags;
382 }
383 }
384}
void parse_from_config(const std::string &str, Limits *lim)
Definition options.hpp:973
@ OPT_REQUIRED
option must be present
Definition userpass.hpp:31
@ PASSWORD_REQUIRED
password must be present
Definition userpass.hpp:34
@ USERNAME_REQUIRED
username must be present
Definition userpass.hpp:33
@ OPT_OPTIONAL
if option is not present, USERNAME_REQUIRED and PASSWORD_REQUIRED are ignored
Definition userpass.hpp:32
@ TRY_FILE
option argument might be a filename, try to load creds from it
Definition userpass.hpp:35
bool parse(const OptionList &options, const std::string &opt_name, const unsigned int flags, std::vector< std::string > *user_pass)
interpret user-pass option
Definition userpass.hpp:74
void parse_file(const std::string &path, const unsigned int flags, std::string &user, std::string &pass)
read username/password from file
Definition userpass.hpp:186
reroute_gw flags
std::string ret
const std::vector< unsigned int > flag_combos_noargs_okay
const std::vector< unsigned int > flag_combos_nofile
TEST(UserPass, Missing)
const std::vector< unsigned int > flag_combos_pw_not_required
const std::string optname
const std::vector< std::string > user_pass
const std::string userpass_tag("<auth>\n" "username\n" "password\n" "</auth>\n")
const std::string userpass_file("auth "+userpass_file_fn+"\n")
const std::string user_file_fn(UNITTEST_SOURCE_DIR "/userpass/user.txt")
const std::vector< unsigned int > flag_combos_missing_okay
const std::vector< std::string > user_only
const std::vector< std::string > overflow_files
const std::vector< std::string > onearg
const std::string user_simple("auth username\n")
const std::vector< unsigned int > flag_combos_pw_required
const std::vector< unsigned int > flag_combos_required
const std::string userpass_file_fn(UNITTEST_SOURCE_DIR "/userpass/userpass.txt")
const std::string user_tag("<auth>\n" "username\n" "</auth>\n")
const std::string user_file("auth "+user_file_fn+"\n")