diff --git a/src/Makefile.am b/src/Makefile.am index 7aaebf29..cbb92da3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -92,6 +92,7 @@ ___test_test_core_SOURCES=\ ___test_test_parse_id_list_SOURCES=\ ../test/test_parse_id_list.cpp +___test_test_basicauth_CPPFLAGS=$(AM_CPPFLAGS) $(CATCH2_CPPFLAGS) ___test_test_basicauth_SOURCES=\ ../test/test_basicauth.cpp \ ../test/test_request.cpp diff --git a/test/test_basicauth.cpp b/test/test_basicauth.cpp index 6148d956..c93ebf77 100644 --- a/test/test_basicauth.cpp +++ b/test/test_basicauth.cpp @@ -1,15 +1,8 @@ -#include -#include -#include -#include -#include -#include #include -#include -#include - -#include +#include +#include +#include #include "cgimap/basicauth.hpp" #include "cgimap/options.hpp" @@ -17,23 +10,9 @@ #include "cgimap/backend/apidb/transaction_manager.hpp" -template -std::ostream& operator<<(std::ostream& os, std::optional const& opt) -{ - return opt ? os << opt.value() : os; -} - +#define CATCH_CONFIG_MAIN +#include -#define ANNOTATE_EXCEPTION(stmt) \ - { \ - try { \ - stmt; \ - } catch (const std::exception &e) { \ - std::ostringstream ostr; \ - ostr << e.what() << ", during " #stmt ; \ - throw std::runtime_error(ostr.str()); \ - } \ - } Transaction_Owner_Void::Transaction_Owner_Void() {} @@ -45,28 +24,8 @@ std::set& Transaction_Owner_Void::get_prep_stmt() { throw std::runtime_error ("get_prep_stmt is not supported by Transaction_Owner_Void"); } - namespace { -template -void assert_equal(const T &actual, const T &expected) { - if (!(actual == expected)) { - std::ostringstream ostr; - ostr << "Expected `" << expected << "', but got `" << actual << "'"; - throw std::runtime_error(ostr.str()); - } -} - -template -void assert_equal(const T &actual, const T &expected, const std::string& scope) { - if (!(actual == expected)) { - std::ostringstream ostr; - ostr << scope << ": Expected `" << expected << "', but got `" << actual << "'"; - throw std::runtime_error(ostr.str()); - } -} - - class basicauth_test_data_selection : public data_selection { public: @@ -156,214 +115,142 @@ class global_settings_test_no_basic_auth : public global_settings_default { } // anonymous namespace +TEST_CASE("test_md5_without_salt", "[basicauth]") { + CHECK(PasswordHash::check("5f4dcc3b5aa765d61d8327deb882cf99", "","password") == true); + CHECK(PasswordHash::check("5f4dcc3b5aa765d61d8327deb882cf99", "", "wrong") == false); +} +TEST_CASE("test_md5_with_salt", "[basicauth]") { + CHECK(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "salt", "password") == true); + CHECK(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "salt", "wrong") == false); + CHECK(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "wrong","password") == false); +} -void test_password_hash() { - - // test_md5_without_salt - assert_equal(PasswordHash::check("5f4dcc3b5aa765d61d8327deb882cf99", "", - "password"), true); - - assert_equal(PasswordHash::check("5f4dcc3b5aa765d61d8327deb882cf99", "", "wrong"), false); - - // test_md5_with_salt - assert_equal(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "salt", - "password"), true); - assert_equal(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "salt", - "wrong"), false); - assert_equal(PasswordHash::check("67a1e09bb1f83f5007dc119c14d663aa", "wrong", - "password"), false); - - // test_pbkdf2_1000_32_sha512 - assert_equal(PasswordHash::check( +TEST_CASE("test_pbkdf2_1000_32_sha512", "[basicauth]") { + CHECK(PasswordHash::check( "ApT/28+FsTBLa/J8paWfgU84SoRiTfeY8HjKWhgHy08=", "sha512!1000!HR4z+hAvKV2ra1gpbRybtoNzm/CNKe4cf7bPKwdUNrk=", - "password"), true); + "password") == true); - assert_equal(PasswordHash::check( + CHECK(PasswordHash::check( "ApT/28+FsTBLa/J8paWfgU84SoRiTfeY8HjKWhgHy08=", "sha512!1000!HR4z+hAvKV2ra1gpbRybtoNzm/CNKe4cf7bPKwdUNrk=", - "wrong"), false); + "wrong") == false); - assert_equal(PasswordHash::check( + CHECK(PasswordHash::check( "ApT/28+FsTBLa/J8paWfgU84SoRiTfeY8HjKWhgHy08=", "sha512!1000!HR4z+hAvKV2ra1gwrongtoNzm/CNKe4cf7bPKwdUNrk=", - "password"), false); + "password") == false); +} + - // test_pbkdf2_10000_32_sha512 - assert_equal(PasswordHash::check( +TEST_CASE("test_pbkdf2_10000_32_sha512", "[basicauth]") { + + CHECK(PasswordHash::check( "3wYbPiOxk/tU0eeIDjUhdvi8aDP3AbFtwYKKxF1IhGg=", "sha512!10000!OUQLgtM7eD8huvanFT5/WtWaCwdOdrir8QOtFwxhO0A=", - "password"), true); + "password") == true); - assert_equal(PasswordHash::check( + CHECK(PasswordHash::check( "3wYbPiOxk/tU0eeIDjUhdvi8aDP3AbFtwYKKxF1IhGg=", "sha512!10000!OUQLgtM7eD8huvanFT5/WtWaCwdOdrir8QOtFwxhO0A=", - "wrong"), false); + "wrong") == false); - assert_equal(PasswordHash::check( + CHECK(PasswordHash::check( "3wYbPiOxk/tU0eeIDjUhdvi8aDP3AbFtwYKKxF1IhGg=", "sha512!10000!OUQLgtMwronguvanFT5/WtWaCwdOdrir8QOtFwxhO0A=", - "password"), false); + "password") == false); +} + +TEST_CASE("test argon2", "[basicauth]") { - // test argon2 - assert_equal(PasswordHash::check( + CHECK(PasswordHash::check( "$argon2id$v=19$m=65536,t=1,p=1$KXGHWfWMf5H5kY4uU3ua8A$YroVvX6cpJpljTio62k19C6UpuIPtW7me2sxyU2dyYg", "", - "password"), true); + "password") == true); - assert_equal(PasswordHash::check( + CHECK(PasswordHash::check( "$argon2id$v=19$m=65536,t=1,p=1$KXGHWfWMf5H5kY4uU3ua8A$YroVvX6cpJpljTio62k19C6UpuIPtW7me2sxyU2dyYg", "", - "wrong"), false); + "wrong") == false); } -void test_authenticate_user() { +TEST_CASE("test_authenticate_user", "[basicauth]") { auto factory = std::make_shared(); - auto txn_readonly = factory->get_default_transaction(); auto sel = factory->make_selection(*txn_readonly); + test_request req; - { - test_request req; + SECTION("Missing Header") { auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{}, "Missing Header"); + CHECK(res == std::optional{}); } - { - test_request req; + SECTION("Empty AUTH header"){ req.set_header("HTTP_AUTHORIZATION",""); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{}, "Empty AUTH header"); + CHECK(res == std::optional{}); } - { - test_request req; + SECTION("Empty AUTH header"){ req.set_header("HTTP_AUTHORIZATION","Basic "); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{}, "Empty AUTH header"); + CHECK(res == std::optional{}); } - { - test_request req; + SECTION("User without password"){ req.set_header("HTTP_AUTHORIZATION","Basic ZGVtbw=="); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{}, "User without password"); + CHECK(res == std::optional{}); } - { - test_request req; + SECTION("User and colon without password"){ req.set_header("HTTP_AUTHORIZATION","Basic ZGVtbzo="); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res,std::optional{}, "User and colon without password"); + CHECK(res == std::optional{}); } - { - test_request req; + SECTION("Known user with correct password"){ req.set_header("HTTP_AUTHORIZATION","Basic ZGVtbzpwYXNzd29yZA=="); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{4711}, "Known user with correct password"); + CHECK(res == std::optional{4711}); } - { - test_request req; + SECTION("Known user with correct password, argon2") { req.set_header("HTTP_AUTHORIZATION","Basic YXJnb24yOnBhc3N3b3Jk"); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{4712}, "Known user with correct password, argon2"); + CHECK(res == std::optional{4712}); } - { - test_request req; + SECTION("Crap data") { req.set_header("HTTP_AUTHORIZATION","Basic TotalCrapData=="); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{}, "Crap data"); + CHECK(res == std::optional{}); } - // Test with known user and incorrect password - { - test_request req; + SECTION("Test with known user and incorrect password") { req.set_header("HTTP_AUTHORIZATION","Basic ZGVtbzppbmNvcnJlY3Q="); - try { - static_cast(basicauth::authenticate_user(req, *sel)); - throw std::runtime_error("Known user, incorrect password: expected http unauthorized exception"); - - } catch (http::exception &e) { - if (e.code() != 401) - throw std::runtime_error( - "Known user / incorrect password: Expected HTTP 401"); - } + REQUIRE_THROWS_AS(static_cast(basicauth::authenticate_user(req, *sel)), http::unauthorized); } - // Test with known user and incorrect password, argon2 - { - test_request req; + SECTION("Test with known user and incorrect password, argon2") { req.set_header("HTTP_AUTHORIZATION","Basic YXJnb24yOndyb25n"); - try { - static_cast(basicauth::authenticate_user(req, *sel)); - throw std::runtime_error("Known user, incorrect password: expected http unauthorized exception"); - - } catch (http::exception &e) { - if (e.code() != 401) - throw std::runtime_error( - "Known user / incorrect password: Expected HTTP 401"); - } + REQUIRE_THROWS_AS(static_cast(basicauth::authenticate_user(req, *sel)), http::unauthorized); } - // Test with unknown user and incorrect password - { - test_request req; + SECTION("Test with unknown user and incorrect password") { req.set_header("HTTP_AUTHORIZATION","Basic ZGVtbzI6aW5jb3JyZWN0"); - try { - static_cast(basicauth::authenticate_user(req, *sel)); - throw std::runtime_error("Unknown user / incorrect password: expected http unauthorized exception"); - - } catch (http::exception &e) { - if (e.code() != 401) - throw std::runtime_error( - "Unknown user / incorrect password: Expected HTTP 401"); - } + REQUIRE_THROWS_AS(static_cast(basicauth::authenticate_user(req, *sel)), http::unauthorized); } -} - -void test_basic_auth_disabled_by_global_config() { - - auto factory = std::make_shared(); - - auto txn_readonly = factory->get_default_transaction(); - auto sel = factory->make_selection(*txn_readonly); - // Known user with correct password, but basic auth has been disabled in global config settings - { + SECTION("Known user with correct password; basicauth disabled in config") { auto test_settings = std::unique_ptr(new global_settings_test_no_basic_auth()); global_settings::set_configuration(std::move(test_settings)); - - test_request req; req.set_header("HTTP_AUTHORIZATION","Basic ZGVtbzpwYXNzd29yZA=="); auto res = basicauth::authenticate_user(req, *sel); - assert_equal >(res, std::optional{}, "Known user with correct password, but basic auth disabled in global config"); - } -} - - -int main() { - try { - ANNOTATE_EXCEPTION(test_password_hash()); - ANNOTATE_EXCEPTION(test_authenticate_user()); - ANNOTATE_EXCEPTION(test_basic_auth_disabled_by_global_config()); - - } catch (const std::exception &e) { - std::cerr << "EXCEPTION: " << e.what() << std::endl; - return 1; - - } catch (...) { - std::cerr << "UNKNOWN EXCEPTION" << std::endl; - return 1; + CHECK(res == std::optional{}); } - - return 0; } - -