1 /*****************************************************************************
2 * keystore.c: test vlc_credential API
3 *****************************************************************************
4 * Copyright © 2016 VLC authors, VideoLAN and VideoLabs
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
26 #include "../../libvlc/test.h"
27 #include "../../../lib/libvlc_internal.h"
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_interrupt.h>
32 #include <vlc_keystore.h>
33 #include <vlc_dialog.h>
49 const char *psz_realm
;
50 const char *psz_authtype
;
53 static const struct testcase
57 const char *psz_realm
;
58 const char *psz_authtype
;
59 struct cred_res result
;
65 #define HTTP(path, realm) "http://"path, realm, "Basic"
66 #define SMB(path) "smb://"path, NULL, NULL
67 #define SFTP(path) "sftp://"path, NULL, NULL
68 #define WIPE_MEMORY_KEYSTORE \
69 { false, NULL, NULL, NULL, {}, {}, {}, false }
71 /* First tests use sftp protocol: no realm and results doesn't depend on
73 { true, SFTP("user1:pwd1@ex.com/testing/deprecated_url"),
74 { "user1", "pwd1", NULL
, NULL
}, {} , {}, false },
76 { true, SFTP("ex.com/testing/opt"),
77 { "user1", "pwd1", NULL
, NULL
}, { "user1", "pwd1" }, {}, false },
79 { true, SFTP("ex.com/testing/dial"),
80 { "user1", "pwd1", NULL
, NULL
}, {}, { "user1", "pwd1" }, false },
84 { true, SFTP("user1@ex.com/testing/url_dial"),
85 { "user1", "pwd1", NULL
, NULL
}, { NULL
, NULL
}, { NULL
, "pwd1" }, false },
89 { true, SFTP("ex.com/testing/opt_dial"),
90 { "user1", "pwd1", NULL
, NULL
}, { "user1", NULL
}, { NULL
, "pwd1" }, false },
94 { true, SFTP("WRONG_USER@ex.com/testing/url_opt_dial"),
95 { "user1", "pwd1", NULL
, NULL
}, { "user1", NULL
}, { NULL
, "pwd1" }, false },
99 /* Order is important now since previously stored credentials could be
100 * found by future tests */
102 { true, SFTP("ex.com/testing/mem_ks_store"),
103 { "user1", "pwd1", NULL
, NULL
}, {}, { "user1", "pwd1" }, false },
105 { true, SFTP("ex.com/testing/mem_ks_find"),
106 { "user1", "pwd1", NULL
, NULL
}, {}, {}, false },
108 WIPE_MEMORY_KEYSTORE
,
110 { false, SFTP("ex.com/testing/mem_ks_find"),
111 { "user1", "pwd1", NULL
, NULL
}, {}, {}, false },
113 WIPE_MEMORY_KEYSTORE
,
115 /* Testing permanent keystore */
117 { true, SFTP("ex.com/testing/ks_store"),
118 { "user1", "pwd1", NULL
, NULL
}, {}, { "user1", "pwd1" }, true },
120 WIPE_MEMORY_KEYSTORE
,
122 { true, SFTP("ex.com/testing/ks_find"),
123 { "user1", "pwd1", NULL
, NULL
}, {}, {}, false },
125 { true, SFTP("ex.com:2022/testing/ks_store"),
126 { "user2", "pwd2", NULL
, NULL
}, {}, { "user2", "pwd2" }, true },
128 WIPE_MEMORY_KEYSTORE
,
130 { true, SFTP("user1@ex.com/testing/ks_find"),
131 { "user1", "pwd1", NULL
, NULL
}, {}, {}, false },
133 { true, SFTP("user2@ex.com:2022/testing/ks_find"),
134 { "user2", "pwd2", NULL
, NULL
}, {}, {}, false },
136 { false, SFTP("user2@wrong_host.com:2022/testing/ks_find"),
137 { "user2", "pwd2", NULL
, NULL
}, {}, {}, false },
139 { false, SFTP("user2@ex.com/testing/ks_find"),
140 { "user2", "pwd2", NULL
, NULL
}, {}, {}, false },
142 { false, SMB("user2@ex.com:2022/testing/ks_find"),
143 { "user2", "pwd2", NULL
, NULL
}, {}, {}, false },
145 WIPE_MEMORY_KEYSTORE
,
147 { true, SFTP("ex.com/testing/opt_not_storing_ks"),
148 { "user3", "pwd3", NULL
, NULL
}, { "user3", "pwd3" }, {}, true },
150 WIPE_MEMORY_KEYSTORE
,
152 { false, SFTP("ex.com/testing/opt_not_storing_ks"),
153 { "user3", "pwd3", NULL
, NULL
}, {}, {}, false },
155 WIPE_MEMORY_KEYSTORE
,
157 /* Testing reusing http credentials rfc7617#2.2 */
159 { true, HTTP("ex.com/testing/good_path/ks_store_realm", "Realm"),
160 { "user4", "pwd4", "Realm", "Basic" }, {}, { "user4", "pwd4" }, true },
162 { false, HTTP("ex.com/testing/good_path/ks_find_realm", "Wrong realm"),
163 { "user4", "pwd4", "Wrong realm", "Basic" }, {}, {}, false },
165 { true, HTTP("ex.com/testing/good_path/ks_find_realm", "Realm"),
166 { "user4", "pwd4", "Realm", "Basic" }, {}, {}, false },
168 { true, HTTP("ex.com/testing/good_path/another_path/ks_find_realm", "Realm"),
169 { "user4", "pwd4", "Realm", "Basic" }, {}, {}, false },
171 { false, HTTP("ex.com/testing/wrong_path/ks_find_realm", "Realm"),
172 { "user4", "pwd4", "Realm", "Basic" }, {}, {}, false },
174 /* Testing reusing smb credentials */
176 { true, SMB("host/share/path1/path2/path3/ks_store"),
177 { "user5", "pwd5", NULL
, NULL
}, {}, { "user5", "pwd5" }, false },
179 { true, SMB("host/share/path4/ks_find"),
180 { "user5", "pwd5", NULL
, NULL
}, {}, {}, false },
182 { false, SMB("wrong_host/share/path4/ks_find"),
183 { "user5", "pwd5", NULL
, NULL
}, {}, {}, false },
185 { false, SMB("host/wrong_share/path4/ks_find"),
186 { "user5", "pwd5", NULL
, NULL
}, {}, {}, false },
188 WIPE_MEMORY_KEYSTORE
,
190 /* Testing smb realm split */
192 { true, SMB("host/share/path1/ks_store"),
193 { "user6", "pwd6", "domain", NULL
}, {}, { "domain;user6", "pwd6" }, true },
195 WIPE_MEMORY_KEYSTORE
,
197 { true, SMB("host/share/path1/ks_store"),
198 { "user6", "pwd6", "domain", NULL
}, {}, {}, false },
200 { true, SMB("domain;user6@host/share/path1/ks_find"),
201 { "user6", "pwd6", "domain", NULL
}, {}, {}, false },
203 { false, SMB("wrong_domain;user6@host/share/path1/ks_find"),
204 { "user6", "pwd6", "wrong_domain", NULL
}, {}, {}, false },
206 WIPE_MEMORY_KEYSTORE
,
208 { false, "://invalid_url", NULL
, NULL
,
209 { "user1", "pwd1", NULL
, NULL
}, {}, { "user1", "pwd1" }, false },
211 { false, "/invalid_path", NULL
, NULL
,
212 { "user1", "pwd1", NULL
, NULL
}, {}, { "user1", "pwd1" }, false },
218 const struct testcase
*p_test
;
222 display_login_cb(void *p_data
, vlc_dialog_id
*p_id
, const char *psz_title
,
223 const char *psz_text
, const char *psz_default_username
,
228 (void) psz_default_username
;
230 struct dialog_ctx
*p_dialog_ctx
= p_data
;
231 const struct testcase
*p_testcase
= p_dialog_ctx
->p_test
;
233 const char *psz_user
= p_testcase
->dialog
.psz_user
!= NULL
?
234 p_testcase
->dialog
.psz_user
: psz_default_username
;
235 if (!p_dialog_ctx
->b_abort
&& psz_user
!= NULL
236 && p_testcase
->dialog
.psz_pwd
!= NULL
)
238 vlc_dialog_id_post_login(p_id
, psz_user
, p_testcase
->dialog
.psz_pwd
,
239 p_testcase
->b_dialog_store
);
240 p_dialog_ctx
->b_abort
= true;
243 vlc_dialog_id_dismiss(p_id
);
247 cancel_cb(void *p_data
, vlc_dialog_id
*p_id
)
250 vlc_dialog_id_dismiss(p_id
);
254 test(vlc_object_t
*p_obj
, unsigned int i_id
, const struct testcase
*p_test
)
256 printf("test(%u): url %s%s%s%s (%sexpected: %s:%s)\n", i_id
, p_test
->psz_url
,
257 p_test
->psz_realm
!= NULL
? " (realm: " : "",
258 p_test
->psz_realm
!= NULL
? p_test
->psz_realm
: "",
259 p_test
->psz_realm
!= NULL
? ")" : "",
260 p_test
->b_found
? "" : "not ", p_test
->result
.psz_user
,
261 p_test
->result
.psz_pwd
);
263 const vlc_dialog_cbs cbs
= {
264 .pf_display_login
= display_login_cb
,
265 .pf_cancel
= cancel_cb
,
267 struct dialog_ctx dialog_ctx
= {
271 vlc_dialog_provider_set_callbacks(p_obj
, &cbs
, &dialog_ctx
);
273 const char *psz_opt_user
= NULL
, *psz_opt_pwd
= NULL
;
274 if (p_test
->opt
.psz_user
!= NULL
)
276 psz_opt_user
= "test-user";
277 var_SetString(p_obj
, psz_opt_user
, p_test
->opt
.psz_user
);
279 if (p_test
->opt
.psz_pwd
!= NULL
)
281 psz_opt_pwd
= "test-pwd";
282 var_SetString(p_obj
, psz_opt_pwd
, p_test
->opt
.psz_pwd
);
286 vlc_UrlParse(&url
, p_test
->psz_url
);
288 vlc_credential credential
;
289 vlc_credential_init(&credential
, &url
);
290 credential
.psz_realm
= p_test
->psz_realm
;
291 credential
.psz_authtype
= p_test
->psz_authtype
;
293 bool b_found
= false;
294 while (vlc_credential_get(&credential
, p_obj
, psz_opt_user
, psz_opt_pwd
,
295 "test authentication", "this a test"))
297 bool realm_match
= !p_test
->result
.psz_realm
298 || (credential
.psz_realm
299 && strcmp(credential
.psz_realm
, p_test
->result
.psz_realm
) == 0);
300 bool authtype_match
= !p_test
->result
.psz_authtype
301 || (credential
.psz_authtype
302 && strcmp(credential
.psz_authtype
, p_test
->result
.psz_authtype
) == 0);
304 if (realm_match
&& authtype_match
305 && strcmp(credential
.psz_username
, p_test
->result
.psz_user
) == 0
306 && strcmp(credential
.psz_password
, p_test
->result
.psz_pwd
) == 0)
312 assert(b_found
== p_test
->b_found
);
313 vlc_credential_store(&credential
, p_obj
);
316 vlc_credential_clean(&credential
);
318 vlc_dialog_provider_set_callbacks(p_obj
, NULL
, NULL
);
321 static libvlc_instance_t
*
322 create_libvlc(int i_vlc_argc
, const char *const *ppsz_vlc_argv
)
324 libvlc_instance_t
*p_libvlc
= libvlc_new(i_vlc_argc
, ppsz_vlc_argv
);
325 assert(p_libvlc
!= NULL
);
328 i_ret
= var_Create(p_libvlc
->p_libvlc_int
, "test-user", VLC_VAR_STRING
);
329 assert(i_ret
== VLC_SUCCESS
);
330 i_ret
= var_Create(p_libvlc
->p_libvlc_int
, "test-pwd", VLC_VAR_STRING
);
331 assert(i_ret
== VLC_SUCCESS
);
341 printf("creating tmp plaintext keystore file\n");
342 char psz_tmp_path
[] = "/tmp/libvlc_XXXXXX";
344 i_tmp_fd
= vlc_mkstemp(psz_tmp_path
);
345 assert(i_tmp_fd
!= -1);
348 const char *ppsz_vlc_argv
[i_vlc_argc
];
349 ppsz_vlc_argv
[0] = "--keystore";
350 ppsz_vlc_argv
[1] = "file_plaintext,none";
351 ppsz_vlc_argv
[2] = "--keystore-file";
352 ppsz_vlc_argv
[3] = psz_tmp_path
;
354 libvlc_instance_t
*p_libvlc
= create_libvlc(i_vlc_argc
, ppsz_vlc_argv
);
356 for (unsigned int i
= 0; i
< sizeof(testcases
)/sizeof(*testcases
); ++i
)
358 if (testcases
[i
].psz_url
== NULL
)
360 printf("test(%u): wiping memory keystore\n", i
);
361 libvlc_release(p_libvlc
);
362 p_libvlc
= create_libvlc(i_vlc_argc
, ppsz_vlc_argv
);
365 test(VLC_OBJECT(p_libvlc
->p_libvlc_int
), i
, &testcases
[i
]);
368 libvlc_release(p_libvlc
);