From 5e90853ecfe52009ef30ea35c39bf00d9e190342 Mon Sep 17 00:00:00 2001 From: Falk Werner Date: Tue, 17 Mar 2020 13:17:33 +0100 Subject: [PATCH] added implementation of file_authenticator --- CMakeLists.txt | 7 + src/webfused/auth/authenticator.c | 10 ++ src/webfused/auth/authenticator.h | 4 + src/webfused/auth/file_authenticator.c | 70 +++++++- test/mock_credentials.cc | 64 ++++++++ test/mock_credentials.hpp | 29 ++++ test/test_file_authenticator.cc | 211 +++++++++++++++++++++++++ test/test_passwd.json | 14 ++ 8 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 test/mock_credentials.cc create mode 100644 test/mock_credentials.hpp create mode 100644 test/test_file_authenticator.cc create mode 100644 test/test_passwd.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 29da226..47392c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,10 +112,12 @@ pkg_check_modules(GMOCK gmock) add_executable(alltests test/mock_config_builder.cc test/mock_logger.cc + test/mock_credentials.cc test/test_config_factory.cc test/test_config.cc test/test_auth_settings.cc test/test_auth_factory.cc + test/test_file_authenticator.cc test/test_log.cc ) @@ -128,10 +130,14 @@ target_include_directories(alltests PRIVATE target_compile_options(alltests PRIVATE ${GMOCK_CFLAGS} ${GTEST_CFLAGS} "-pthread") target_link_libraries(alltests PRIVATE + -Wl,--wrap=wf_credentials_type + -Wl,--wrap=wf_credentials_get webfused-static + userdb ${LIBCONFIG_LIBRARIES} ${WEBFUSE_LIBRARIES} ${UUID_LIBRARIES} + ${OPENSSL_LIBRARIES} ${GMOCK_LIBRARIES} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} @@ -140,6 +146,7 @@ target_link_libraries(alltests PRIVATE # copy test data configure_file(etc/webfused.conf webfused.conf COPYONLY) configure_file(test/invalid.conf invalid.conf COPYONLY) +configure_file(test/test_passwd.json test_passwd.json COPYONLY) enable_testing() gtest_discover_tests(alltests TEST_PREFIX alltests:) diff --git a/src/webfused/auth/authenticator.c b/src/webfused/auth/authenticator.c index 4e9342b..ff7732a 100644 --- a/src/webfused/auth/authenticator.c +++ b/src/webfused/auth/authenticator.c @@ -6,3 +6,13 @@ wfd_authenticator_dispose( { authenticator.vtable->dispose(authenticator.data); } + +extern bool +wfd_authenticator_authenticate( + struct wfd_authenticator authenticator, + struct wf_credentials * credentials) +{ + return authenticator.vtable->authenticate( + credentials, authenticator.data); +} + diff --git a/src/webfused/auth/authenticator.h b/src/webfused/auth/authenticator.h index 2300b9e..1665a03 100644 --- a/src/webfused/auth/authenticator.h +++ b/src/webfused/auth/authenticator.h @@ -28,6 +28,10 @@ extern void wfd_authenticator_dispose( struct wfd_authenticator authenticator); +extern bool +wfd_authenticator_authenticate( + struct wfd_authenticator authenticator, + struct wf_credentials * credentials); #ifdef __cplusplus } diff --git a/src/webfused/auth/file_authenticator.c b/src/webfused/auth/file_authenticator.c index 02ee81e..1a0bf49 100644 --- a/src/webfused/auth/file_authenticator.c +++ b/src/webfused/auth/file_authenticator.c @@ -1,9 +1,77 @@ #include "webfused/auth/file_authenticator.h" +#include "webfused/auth/settings.h" +#include "webfused/auth/authenticator.h" + +#include "webfuse/adapter/credentials.h" +#include "userdb/userdb.h" + +#include +#include + +struct wfd_file_authenticator +{ + char * filename; +}; + +static void +wfd_file_authenticator_dispose( + void * data) +{ + struct wfd_file_authenticator * authenticator = data; + + free(authenticator->filename); + free(authenticator); +} + +static bool +wfd_file_authenticator_authenticate( + struct wf_credentials * credentials, + void * user_data) +{ + bool result = false; + struct wfd_file_authenticator * authenticator = user_data; + + char const * username = wf_credentials_get(credentials, "username"); + char const * password = wf_credentials_get(credentials, "password"); + if ((NULL != username) && (NULL != password)) + { + struct userdb * db = userdb_create(""); + result = userdb_load(db, authenticator->filename); + if (result) + { + result = userdb_check(db, username, password); + } + + userdb_dispose(db); + } + + return result; +} + +static struct wfd_authenticator_vtable +wfd_file_authenticator_vtable = +{ + .dispose = &wfd_file_authenticator_dispose, + .authenticate = &wfd_file_authenticator_authenticate +}; bool wfd_file_authenticator_create( struct wfd_auth_settings * settings, struct wfd_authenticator * authenticator) { - return false; + bool result = false; + + char const * filename = wfd_auth_settings_get(settings, "file"); + if (NULL != filename) + { + struct wfd_file_authenticator * data = malloc(sizeof(struct wfd_file_authenticator)); + data->filename = strdup(filename); + + authenticator->vtable = &wfd_file_authenticator_vtable; + authenticator->data = data; + result = true; + } + + return result; } diff --git a/test/mock_credentials.cc b/test/mock_credentials.cc new file mode 100644 index 0000000..a6023b1 --- /dev/null +++ b/test/mock_credentials.cc @@ -0,0 +1,64 @@ +#include "mock_credentials.hpp" + + +extern "C" +{ +using webfused_test::ICredentials; + +static ICredentials * wfd_mock_credentials = nullptr; + +extern char const * +__real_wf_credentials_type( + struct wf_credentials const * credentials); + +char const * +__wrap_wf_credentials_type( + struct wf_credentials const * credentials) +{ + if (nullptr == wfd_mock_credentials) + { + return __real_wf_credentials_type(credentials); + } + else + { + return wfd_mock_credentials->type(); + } +} + +extern char const * __real_wf_credentials_get( + struct wf_credentials const * credentials, + char const * key); + + +char const * __wrap_wf_credentials_get( + struct wf_credentials const * credentials, + char const * key) +{ + if (nullptr == wfd_mock_credentials) + { + return __real_wf_credentials_get(credentials, key); + } + else + { + return wfd_mock_credentials->get(key); + } +} + + +} + + +namespace webfused_test +{ + +MockCredentials::MockCredentials() +{ + wfd_mock_credentials = this; +} + +MockCredentials::~MockCredentials() +{ + wfd_mock_credentials = nullptr; +} + +} diff --git a/test/mock_credentials.hpp b/test/mock_credentials.hpp new file mode 100644 index 0000000..02b88c9 --- /dev/null +++ b/test/mock_credentials.hpp @@ -0,0 +1,29 @@ +#ifndef WFD_MOCK_CREDENTIALS_HPP +#define WFD_MOCK_CREDENTIALS_HPP + +#include "gmock/gmock.h" +#include "webfuse/adapter/credentials.h" + +namespace webfused_test +{ + +class ICredentials +{ +public: + virtual ~ICredentials() = default; + virtual char const * type() = 0; + virtual char const * get(char const * key) = 0; +}; + +class MockCredentials: public ICredentials +{ +public: + MockCredentials(); + virtual ~MockCredentials(); + MOCK_METHOD0(type, char const*()); + MOCK_METHOD1(get, char const *(char const * key)); +}; + +} + +#endif diff --git a/test/test_file_authenticator.cc b/test/test_file_authenticator.cc new file mode 100644 index 0000000..a864afe --- /dev/null +++ b/test/test_file_authenticator.cc @@ -0,0 +1,211 @@ +#include "webfused/auth/file_authenticator.h" +#include "webfused/auth/authenticator.h" +#include "webfused/config/auth_settings.h" +#include "webfused/auth/factory.h" + +#include "mock_credentials.hpp" + +#include +#include + +using ::webfused_test::MockCredentials; +using ::testing::Return; +using ::testing::StrEq; + +TEST(file_authenticator, create) +{ + char const config_text[] = + "file = \"/tmp/webfuse_passwd.json\"\n" + ; + config_t config; + config_init(&config); + config_read_string(&config, config_text); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_file_authenticator_create(auth_settings, &authenticator); + ASSERT_TRUE(success); + + wfd_auth_settings_dispose(auth_settings); + wfd_authenticator_dispose(authenticator); + config_destroy(&config); +} + +TEST(file_authenticator, create_fail_missing_file) +{ + config_t config; + config_init(&config); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_file_authenticator_create(auth_settings, &authenticator); + ASSERT_FALSE(success); + + wfd_auth_settings_dispose(auth_settings); + config_destroy(&config); +} + +TEST(file_authenticator, create_via_factory) +{ + char const config_text[] = + "file = \"/tmp/webfuse_passwd.json\"\n" + ; + config_t config; + config_init(&config); + config_read_string(&config, config_text); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_authenticator_create(auth_settings, &authenticator); + ASSERT_TRUE(success); + + wfd_auth_settings_dispose(auth_settings); + wfd_authenticator_dispose(authenticator); + config_destroy(&config); +} + +TEST(file_authenticator, authenticate) +{ + char const config_text[] = + "file = \"test_passwd.json\"\n" + ; + config_t config; + config_init(&config); + config_read_string(&config, config_text); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_authenticator_create(auth_settings, &authenticator); + ASSERT_TRUE(success); + + MockCredentials creds; + EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob")); + EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("secret")); + + bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr); + ASSERT_TRUE(is_authenticated); + + wfd_auth_settings_dispose(auth_settings); + wfd_authenticator_dispose(authenticator); + config_destroy(&config); +} + +TEST(file_authenticator, authenticate_fail_wrong_passwd) +{ + char const config_text[] = + "file = \"test_passwd.json\"\n" + ; + config_t config; + config_init(&config); + config_read_string(&config, config_text); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_authenticator_create(auth_settings, &authenticator); + ASSERT_TRUE(success); + + MockCredentials creds; + EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob")); + EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("unkown")); + + bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr); + ASSERT_FALSE(is_authenticated); + + wfd_auth_settings_dispose(auth_settings); + wfd_authenticator_dispose(authenticator); + config_destroy(&config); +} + +TEST(file_authenticator, authenticate_fail_no_passwd_file) +{ + char const config_text[] = + "file = \"non_existing_passwd.json\"\n" + ; + config_t config; + config_init(&config); + config_read_string(&config, config_text); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_authenticator_create(auth_settings, &authenticator); + ASSERT_TRUE(success); + + MockCredentials creds; + EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob")); + EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("secred")); + + bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr); + ASSERT_FALSE(is_authenticated); + + wfd_auth_settings_dispose(auth_settings); + wfd_authenticator_dispose(authenticator); + config_destroy(&config); +} + +TEST(file_authenticator, authenticate_fail_missing_username) +{ + char const config_text[] = + "file = \"test_passwd.json\"\n" + ; + config_t config; + config_init(&config); + config_read_string(&config, config_text); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_authenticator_create(auth_settings, &authenticator); + ASSERT_TRUE(success); + + MockCredentials creds; + EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return(nullptr)); + EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("unkown")); + + bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr); + ASSERT_FALSE(is_authenticated); + + wfd_auth_settings_dispose(auth_settings); + wfd_authenticator_dispose(authenticator); + config_destroy(&config); +} + +TEST(file_authenticator, authenticate_fail_missing_password) +{ + char const config_text[] = + "file = \"test_passwd.json\"\n" + ; + config_t config; + config_init(&config); + config_read_string(&config, config_text); + config_setting_t * settings = config_root_setting(&config); + + wfd_auth_settings * auth_settings = wfd_auth_settings_create("file", settings); + + wfd_authenticator authenticator; + bool success = wfd_authenticator_create(auth_settings, &authenticator); + ASSERT_TRUE(success); + + MockCredentials creds; + EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob")); + EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return(nullptr)); + + bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr); + ASSERT_FALSE(is_authenticated); + + wfd_auth_settings_dispose(auth_settings); + wfd_authenticator_dispose(authenticator); + config_destroy(&config); +} \ No newline at end of file diff --git a/test/test_passwd.json b/test/test_passwd.json new file mode 100644 index 0000000..595c06d --- /dev/null +++ b/test/test_passwd.json @@ -0,0 +1,14 @@ +{ + "meta": { + "type": "wf-userdb", + "major": 1, + "minor": 0, + "hash_algorithm": "sha512" + }, + "users": { + "bob": { + "password_hash": "e51e27ce47054feead3d83068d47f2a07307d4877ac67da668ef43e0e466fe8c7b66651af14fdb8d48c51592ef5afa0c63f874d20861c6b9ef8e6513bfcaa330", + "salt": "b3be6979921edecfea88c50d0d1ec40b7f8c383831b2276c65969ead18e47c03" + } + } +} \ No newline at end of file