From 729569e6c1d40f974c92f6e71acdc7af69837a89 Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Thu, 25 Feb 2016 18:38:03 +0100 Subject: [PATCH] vlc_credential: add a test This test passing credentials via url, option, dialog, memory keystore, permanent keystore. This also test reusing credentials with http and smb protocols. --- test/Makefile.am | 3 + test/src/misc/keystore.c | 329 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+) create mode 100644 test/src/misc/keystore.c diff --git a/test/Makefile.am b/test/Makefile.am index 28e20a18ff..f8d4125e74 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -25,6 +25,7 @@ check_PROGRAMS = \ test_src_interface_dialog \ test_src_misc_bits \ test_src_misc_epg \ + test_src_misc_keystore \ test_modules_packetizer_hxxx \ test_modules_keystore \ test_modules_tls \ @@ -96,6 +97,8 @@ test_src_misc_bits_SOURCES = src/misc/bits.c test_src_misc_bits_LDADD = $(LIBVLC) test_src_misc_epg_SOURCES = src/misc/epg.c test_src_misc_epg_LDADD = $(LIBVLCCORE) $(LIBVLC) +test_src_misc_keystore_SOURCES = src/misc/keystore.c +test_src_misc_keystore_LDADD = $(LIBVLCCORE) $(LIBVLC) test_src_interface_dialog_SOURCES = src/interface/dialog.c test_src_interface_dialog_LDADD = $(LIBVLCCORE) $(LIBVLC) test_modules_packetizer_hxxx_SOURCES = modules/packetizer/hxxx.c diff --git a/test/src/misc/keystore.c b/test/src/misc/keystore.c new file mode 100644 index 0000000000..e52c3d708b --- /dev/null +++ b/test/src/misc/keystore.c @@ -0,0 +1,329 @@ +/***************************************************************************** + * keystore.c: test vlc_credential API + ***************************************************************************** + * Copyright © 2016 VLC authors, VideoLAN and VideoLabs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "../../../lib/libvlc_internal.h" + +#include +#include +#include +#include +#include +#include + +#undef NDEBUG +#include + + +struct cred +{ + const char *psz_user; + const char *psz_pwd; +}; + +static const struct testcase +{ + bool b_found; + const char *psz_url; + const char *psz_realm; + const char *psz_authtype; + struct cred result; + struct cred opt; + struct cred dialog; + bool b_dialog_store; +} testcases[] = +{ +#define HTTP(path, realm) "http://"path, realm, "Basic" +#define SMB(path) "smb://"path, NULL, NULL +#define SFTP(path) "sftp://"path, NULL, NULL +#define WIPE_MEMORY_KEYSTORE \ + { false, NULL, NULL, NULL, {}, {}, {}, false } + + /* First tests use sftp protocol: no realm and results doesn't depend on + * path */ + { true, SFTP("user1:pwd1@ex.com/testing/deprecated_url"), + { "user1", "pwd1" }, {} , {}, false, false }, + + { true, SFTP("ex.com/testing/opt"), + { "user1", "pwd1" }, { "user1", "pwd1" }, {}, false }, + + { true, SFTP("ex.com/testing/dial"), + { "user1", "pwd1" }, {}, { "user1", "pwd1" }, false }, + + WIPE_MEMORY_KEYSTORE, + + { true, SFTP("user1@ex.com/testing/url_dial"), + { "user1", "pwd1" }, { NULL, NULL }, { NULL, "pwd1" }, false }, + + WIPE_MEMORY_KEYSTORE, + + { true, SFTP("ex.com/testing/opt_dial"), + { "user1", "pwd1" }, { "user1", NULL }, { NULL, "pwd1" }, false }, + + WIPE_MEMORY_KEYSTORE, + + { true, SFTP("WRONG_USER@ex.com/testing/url_opt_dial"), + { "user1", "pwd1" }, { "user1", NULL }, { NULL, "pwd1" }, false }, + + WIPE_MEMORY_KEYSTORE, + + /* Order is important now since previously stored credentials could be + * found by future tests */ + + { true, SFTP("ex.com/testing/mem_ks_store"), + { "user1", "pwd1" }, {}, { "user1", "pwd1" }, false }, + + { true, SFTP("ex.com/testing/mem_ks_find"), + { "user1", "pwd1" }, {}, {}, false }, + + WIPE_MEMORY_KEYSTORE, + + { false, SFTP("ex.com/testing/mem_ks_find"), + { "user1", "pwd1" }, {}, {}, false }, + + WIPE_MEMORY_KEYSTORE, + + /* Testing permanent keystore */ + + { true, SFTP("ex.com/testing/ks_store"), + { "user1", "pwd1" }, {}, { "user1", "pwd1" }, true }, + + WIPE_MEMORY_KEYSTORE, + + { true, SFTP("ex.com/testing/ks_find"), + { "user1", "pwd1" }, {}, {}, false }, + + { true, SFTP("ex.com:2022/testing/ks_store"), + { "user2", "pwd2" }, {}, { "user2", "pwd2" }, true }, + + WIPE_MEMORY_KEYSTORE, + + { true, SFTP("user1@ex.com/testing/ks_find"), + { "user1", "pwd1" }, {}, {}, false }, + + { true, SFTP("user2@ex.com:2022/testing/ks_find"), + { "user2", "pwd2" }, {}, {}, false }, + + { false, SFTP("user2@wrong_host.com:2022/testing/ks_find"), + { "user2", "pwd2" }, {}, {}, false }, + + { false, SFTP("user2@ex.com/testing/ks_find"), + { "user2", "pwd2" }, {}, {}, false }, + + { false, SMB("user2@ex.com:2022/testing/ks_find"), + { "user2", "pwd2" }, {}, {}, false }, + + WIPE_MEMORY_KEYSTORE, + + { true, SFTP("ex.com/testing/opt_not_storing_ks"), + { "user3", "pwd3" }, { "user3", "pwd3" }, {}, true }, + + WIPE_MEMORY_KEYSTORE, + + { false, SFTP("ex.com/testing/opt_not_storing_ks"), + { "user3", "pwd3" }, {}, {}, false }, + + WIPE_MEMORY_KEYSTORE, + + /* Testing reusing http credentials rfc7617#2.2 */ + + { true, HTTP("ex.com/testing/good_path/ks_store_realm", "Realm"), + { "user4", "pwd4" }, {}, { "user4", "pwd4" }, true }, + + { false, HTTP("ex.com/testing/good_path/ks_find_realm", "Wrong realm"), + { "user4", "pwd4" }, {}, {}, false }, + + { true, HTTP("ex.com/testing/good_path/ks_find_realm", "Realm"), + { "user4", "pwd4" }, {}, {}, false }, + + { true, HTTP("ex.com/testing/good_path/another_path/ks_find_realm", "Realm"), + { "user4", "pwd4" }, {}, {}, false }, + + { false, HTTP("ex.com/testing/wrong_path/ks_find_realm", "Realm"), + { "user4", "pwd4" }, {}, {}, false }, + + /* Testing reusing smb credentials */ + + { true, SMB("host/share/path1/path2/path3/ks_store"), + { "user5", "pwd5" }, {}, { "user5", "pwd5" }, false }, + + { true, SMB("host/share/path4/ks_find"), + { "user5", "pwd5" }, {}, {}, false }, + + { false, SMB("wrong_host/share/path4/ks_find"), + { "user5", "pwd5" }, {}, {}, false }, + + { false, SMB("host/wrong_share/path4/ks_find"), + { "user5", "pwd5" }, {}, {}, false }, + + WIPE_MEMORY_KEYSTORE, + + /* Testing smb realm split */ + + { true, SMB("host/share/path1/ks_store"), + { "user6", "pwd6" }, {}, { "user6;domain", "pwd6" }, false }, + + { true, SMB("user6;domain@host/share/path1/ks_find"), + { "user6", "pwd6" }, {}, {}, false }, + + { false, SMB("user6;wrong_domain@host/share/path1/ks_find"), + { "user6", "pwd6" }, {}, {}, false }, +}; + +static void +display_login_cb(vlc_dialog_id *p_id, const char *psz_title, + const char *psz_text, const char *psz_default_username, + bool b_ask_store, void *p_data) +{ + (void) psz_title; + (void) psz_text; + (void) psz_default_username; + (void) b_ask_store; + struct testcase *p_testcase = p_data; + + const char *psz_user = p_testcase->dialog.psz_user != NULL ? + p_testcase->dialog.psz_user : psz_default_username; + if (psz_user != NULL && p_testcase->dialog.psz_pwd != NULL) + vlc_dialog_id_post_login(p_id, psz_user, p_testcase->dialog.psz_pwd, + p_testcase->b_dialog_store); + else + vlc_dialog_id_dismiss(p_id); +} + +static void +cancel_cb(vlc_dialog_id *p_id, void *p_data) +{ + (void) p_data; + vlc_dialog_id_dismiss(p_id); +} + +static void +test(vlc_object_t *p_obj, unsigned int i_id, const struct testcase *p_test) +{ + printf("test(%u): url %s%s%s%s (%sexpected: %s:%s)\n", i_id, p_test->psz_url, + p_test->psz_realm != NULL ? " (realm: " : "", + p_test->psz_realm != NULL ? p_test->psz_realm : "", + p_test->psz_realm != NULL ? ")" : "", + p_test->b_found ? "" : "not ", p_test->result.psz_user, + p_test->result.psz_pwd); + + const vlc_dialog_cbs cbs = { + .pf_display_login = display_login_cb, + .pf_cancel = cancel_cb, + }; + vlc_dialog_provider_set_callbacks(p_obj, &cbs, (void *)p_test); + + const char *psz_opt_user = NULL, *psz_opt_pwd = NULL; + if (p_test->opt.psz_user != NULL) + { + psz_opt_user = "test-user"; + var_SetString(p_obj, psz_opt_user, p_test->opt.psz_user); + } + if (p_test->opt.psz_pwd != NULL) + { + psz_opt_pwd = "test-pwd"; + var_SetString(p_obj, psz_opt_pwd, p_test->opt.psz_pwd); + } + + vlc_url_t url; + vlc_UrlParse(&url, p_test->psz_url); + assert(url.psz_protocol != NULL && url.psz_host != NULL); + + vlc_credential credential; + vlc_credential_init(&credential, &url); + credential.psz_realm = p_test->psz_realm; + credential.psz_authtype = p_test->psz_authtype; + + bool b_found = false; + while (vlc_credential_get(&credential, p_obj, psz_opt_user, psz_opt_pwd, + "test authentication", "this a test")) + { + if (strcmp(credential.psz_username, p_test->result.psz_user) == 0 + && strcmp(credential.psz_password, p_test->result.psz_pwd) == 0) + { + b_found = true; + vlc_credential_store(&credential, p_obj); + break; + } + } + assert(b_found == p_test->b_found); + + vlc_UrlClean(&url); + vlc_credential_clean(&credential); + + vlc_dialog_provider_set_callbacks(p_obj, NULL, NULL); +} + +static libvlc_instance_t * +create_libvlc(int i_vlc_argc, const char *const *ppsz_vlc_argv) +{ + libvlc_instance_t *p_libvlc = libvlc_new(i_vlc_argc, ppsz_vlc_argv); + assert(p_libvlc != NULL); + + int i_ret; + i_ret = var_Create(p_libvlc->p_libvlc_int, "test-user", VLC_VAR_STRING); + assert(i_ret == VLC_SUCCESS); + i_ret = var_Create(p_libvlc->p_libvlc_int, "test-pwd", VLC_VAR_STRING); + assert(i_ret == VLC_SUCCESS); + + return p_libvlc; +} + +int +main(void) +{ + setenv("VLC_PLUGIN_PATH", "../modules", 1); + + printf("creating tmp plaintext keystore file\n"); + char psz_tmp_path[] = "/tmp/libvlc_XXXXXX"; + int i_tmp_fd = -1; + i_tmp_fd = mkstemp(psz_tmp_path); + assert(i_tmp_fd != -1); + + int i_vlc_argc = 4; + const char *ppsz_vlc_argv[i_vlc_argc]; + ppsz_vlc_argv[0] = "--keystore"; + ppsz_vlc_argv[1] = "file_plaintext,none"; + ppsz_vlc_argv[2] = "--keystore-file"; + ppsz_vlc_argv[3] = psz_tmp_path; + + libvlc_instance_t *p_libvlc = create_libvlc(i_vlc_argc, ppsz_vlc_argv); + + for (unsigned int i = 0; i < sizeof(testcases)/sizeof(*testcases); ++i) + { + if (testcases[i].psz_url == NULL) + { + printf("test(%u): wiping memory keystore\n", i); + libvlc_release(p_libvlc); + p_libvlc = create_libvlc(i_vlc_argc, ppsz_vlc_argv); + } + else + test(VLC_OBJECT(p_libvlc->p_libvlc_int), i, &testcases[i]); + } + + libvlc_release(p_libvlc); + close(i_tmp_fd); + + return 0; +} -- GitLab