/* * Copyright (c) 2019 - 2024 Stefan Strobel * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * @file test_integration_auth.cpp * @brief integration test implementation for the authentication functions * @author Stefan Strobel */ #include "test/framework/catch.hpp" extern "C" { #include "shellmatta.h" } #include static uint32_t write_callCnt = 0u; static char write_data[1024]; static uint32_t write_length; static uint32_t userIdTemp; static bool successTemp; #define TEST_SHELLMATTA_SETUP shellmatta_retCode_t ret; \ shellmatta_instance_t inst; \ shellmatta_handle_t handle; \ char buffer[1024] = {0}; \ char historyBuffer[1024] = {0}; \ \ shellmatta_doInit( &inst, \ &handle, \ buffer, \ sizeof(buffer), \ historyBuffer, \ sizeof(historyBuffer), \ "shellmatta->", \ NULL, \ writeFct); \ \ write_callCnt = 0u; \ memset(write_data, 0, sizeof(write_data)); \ write_length = 0u; \ userIdTemp = 255u; \ successTemp = false; \ \ shellmatta_addCmd(handle, &publicCmd); \ shellmatta_addCmd(handle, &privateCmd); #define TEST_SHELLMATTA_AUTH_SETUP shellmatta_auth_user_t userList[] = { \ {1, false, "shimatta", "12345678"}, \ {2, false, "not_shimatta", "87654321"}, \ {3, true, "root", "rootpw"} \ }; \ \ uint32_t privateCmdPerms[] = {1}; \ shellmatta_auth_perm_t permList[] = { \ {"private", privateCmdPerms, sizeof(privateCmdPerms)/sizeof(privateCmdPerms[0])} \ }; \ \ shellmatta_auth_init(handle, userList, 3, permList, 1, false, NULL, NULL); static shellmatta_retCode_t writeFct(const char* data, uint32_t length) { write_callCnt ++; while((length > 0) && (write_length < sizeof(write_data))) { write_data[write_length] = *data; data ++; length --; write_length ++; } return SHELLMATTA_OK; } static shellmatta_retCode_t publicCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void) handle; (void) arguments; (void) length; shellmatta_retCode_t ret = SHELLMATTA_OK; return ret; } shellmatta_cmd_t publicCmd = {(char*)"public", (char*)"p", NULL, NULL, publicCmdFct, NULL, NULL}; static shellmatta_retCode_t privateCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void) handle; (void) arguments; (void) length; return SHELLMATTA_OK; } shellmatta_cmd_t privateCmd = {(char*)"private", (char*)"r", NULL, NULL, privateCmdFct, NULL, NULL}; SCENARIO("Check help auth uninitialized") { GIVEN("An initialized shellmatta instance without initialized auth") { TEST_SHELLMATTA_SETUP; WHEN("The help command is called") { ret = shellmatta_processData(handle, (char*)"help\r", 5); CHECK(ret == SHELLMATTA_OK); THEN("The help command prints all commands.") { char *dummyData = (char*) "help\r\n" "help ? help [command] - print help or usage information\r\n" "login li Login command\r\n" "logout lo Logout command\r\n" "private r\r\n" "public p\r\n" "\r\n" "shellmatta->"; CHECK(ret == SHELLMATTA_OK); CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); } } } } SCENARIO("Check help auth unauthorized") { GIVEN("An initialized shellmatta instance with initialized auth") { TEST_SHELLMATTA_SETUP; TEST_SHELLMATTA_AUTH_SETUP; WHEN("The help command is called") { ret = shellmatta_processData(handle, (char*)"help\r", 5); CHECK(ret == SHELLMATTA_OK); THEN("The help command prints only public commands.") { char *dummyData = (char*) "help\r\n" "help ? help [command] - print help or usage information\r\n" "login li Login command\r\n" "logout lo Logout command\r\n" "public p\r\n" "\r\n" "shellmatta->"; CHECK(ret == SHELLMATTA_OK); CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); } } } } SCENARIO("Check help authorized") { GIVEN("An initialized shellmatta instance with initialized auth") { TEST_SHELLMATTA_SETUP; TEST_SHELLMATTA_AUTH_SETUP; WHEN("The user shellmatta is logged in") { ret = shellmatta_auth_login(handle, 1); CHECK(ret == SHELLMATTA_OK); AND_WHEN("The help command is called") { ret = shellmatta_processData(handle, (char*)"help\r", 5); CHECK(ret == SHELLMATTA_OK); THEN("The help command prints all commands.") { char *dummyData = (char*) "help\r\n" "help ? help [command] - print help or usage information\r\n" "login li Login command\r\n" "logout lo Logout command\r\n" "private r\r\n" "public p\r\n" "\r\n" "shimatta@shellmatta->"; CHECK(ret == SHELLMATTA_OK); CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is logged in") { char usernameBuffer[16] = {0}; uint32_t usernameBufferLength = sizeof(usernameBuffer); CHECK(1 == shellmatta_auth_getLoggedInUserId(handle)); ret = shellmatta_auth_getLoggedInUserName(handle, usernameBuffer, &usernameBufferLength); CHECK(ret == SHELLMATTA_OK); CHECK(usernameBufferLength == strlen("shimatta")); REQUIRE_THAT(usernameBuffer, Catch::Matchers::Equals("shimatta")); } } AND_WHEN("The user is logged out using the logout command") { write_length = 0; memset(write_data, 0, sizeof(write_data)); ret = shellmatta_processData(handle, (char*)"logout\r", 7); CHECK(ret == SHELLMATTA_OK); THEN("The Shellmatta prints the logout message") { char *dummyData = (char*) "logout\r\n" "good bye\r\n\r\n" "shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); } AND_WHEN("The help command is called") { write_length = 0; memset(write_data, 0, sizeof(write_data)); ret = shellmatta_processData(handle, (char*)"help\r", 5); CHECK(ret == SHELLMATTA_OK); THEN("The help command prints only public commands.") { char *dummyData = (char*) "help\r\n" "help ? help [command] - print help or usage information\r\n" "login li Login command\r\n" "logout lo Logout command\r\n" "public p\r\n" "\r\n" "shellmatta->"; CHECK(ret == SHELLMATTA_OK); CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); } } } } } WHEN("The user not_shellmatta is logged in") { ret = shellmatta_auth_login(handle, 2); CHECK(ret == SHELLMATTA_OK); AND_WHEN("The help command is called") { ret = shellmatta_processData(handle, (char*)"help\r", 5); CHECK(ret == SHELLMATTA_OK); THEN("The help command prints not all commands.") { char *dummyData = (char*) "help\r\n" "help ? help [command] - print help or usage information\r\n" "login li Login command\r\n" "logout lo Logout command\r\n" "public p\r\n" "\r\n" "not_shimatta@shellmatta->"; CHECK(ret == SHELLMATTA_OK); CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The not_shimatta user is logged in") { char usernameBuffer[16] = {0}; uint32_t usernameBufferLength = sizeof(usernameBuffer); CHECK(2 == shellmatta_auth_getLoggedInUserId(handle)); ret = shellmatta_auth_getLoggedInUserName(handle, usernameBuffer, &usernameBufferLength); CHECK(ret == SHELLMATTA_OK); CHECK(usernameBufferLength == strlen("not_shimatta")); REQUIRE_THAT(usernameBuffer, Catch::Matchers::Equals("not_shimatta")); } } } } WHEN("The user root is logged in") { ret = shellmatta_auth_login(handle, 3); CHECK(ret == SHELLMATTA_OK); AND_WHEN("The help command is called") { ret = shellmatta_processData(handle, (char*)"help\r", 5); CHECK(ret == SHELLMATTA_OK); THEN("The help command prints all commands.") { char *dummyData = (char*) "help\r\n" "help ? help [command] - print help or usage information\r\n" "login li Login command\r\n" "logout lo Logout command\r\n" "private r\r\n" "public p\r\n" "\r\n" "root@shellmatta->"; CHECK(ret == SHELLMATTA_OK); CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); } } } } } SCENARIO("Check login command with privileged user") { GIVEN("An initialized shellmatta instance with initialized auth") { TEST_SHELLMATTA_SETUP; TEST_SHELLMATTA_AUTH_SETUP; WHEN("The user shellmatta logges in interactively using the correct credentials") { ret = shellmatta_processData(handle, (char*)"login\r\n" "shimatta\r\n" "12345678\r", 26); CHECK(ret == SHELLMATTA_OK); THEN("The login message is printed - password is hidden") { char *dummyData = (char*) "login\r\n" "enter username:\r\n" "shimatta\r\n" "enter password:\r\n" "\r\n" "login successful\r\n" "\r\n" "shimatta@shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is logged in") { REQUIRE(1 == shellmatta_auth_getLoggedInUserId(handle)); } } } WHEN("The user shellmatta logges in interactively using wrong credentials") { ret = shellmatta_processData(handle, (char*)"login\r\n" "shimatta\r\n" "11111111\r", 26); CHECK(ret == SHELLMATTA_OK); THEN("A warning message is printed") { char *dummyData = (char*) "login\r\n" "enter username:\r\n" "shimatta\r\n" "enter password:\r\n" "\r\n" "username or password is wrong\r\n" "\r\n" "shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is not logged in") { REQUIRE(0 == shellmatta_auth_getLoggedInUserId(handle)); } } } WHEN("The user shellmatta logges in interactively manipulating the input") { ret = shellmatta_processData(handle, (char*)"login\r" "shimg\batta\r" "1h" "\x7f" "2346\033[D5\033[C78\b8\r", 36); CHECK(ret == SHELLMATTA_OK); THEN("The login message is printed - password is hidden") { char *dummyData = (char*) "login\r\n" "enter username:\r\n" "shimg\033[1D\033[K\033[s\033[uatta\r\n" "enter password:\r\n" "\r\n" "login successful\r\n" "\r\n" "shimatta@shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is logged in") { REQUIRE(1 == shellmatta_auth_getLoggedInUserId(handle)); } } } WHEN("The user shellmatta logges in passing the credentials none interactive") { ret = shellmatta_processData(handle, (char*)"login -u shimatta -p 12345678\r", 30); CHECK(ret == SHELLMATTA_OK); THEN("The login message is printed") { char *dummyData = (char*) "login -u shimatta -p 12345678\r\n" "login successful\r\n" "\r\n" "shimatta@shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is logged in") { REQUIRE(1 == shellmatta_auth_getLoggedInUserId(handle)); } } } WHEN("The user shellmatta logges in passing the credentials half interactive") { ret = shellmatta_processData(handle, (char*)"login -u shimatta\r12345678\r", 27); CHECK(ret == SHELLMATTA_OK); THEN("The login message is printed - password is hidden") { char *dummyData = (char*) "login -u shimatta\r\n\r\n" "enter password:\r\n" "\r\n" "login successful\r\n" "\r\n" "shimatta@shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is logged in") { REQUIRE(1 == shellmatta_auth_getLoggedInUserId(handle)); } } } WHEN("The user shellmatta tries to login non interactive without username") { ret = shellmatta_processData(handle, (char*)"login -p 12345678\r", 18); CHECK(ret == SHELLMATTA_OK); THEN("A warning message is printed") { char *dummyData = (char*) "login -p 12345678\r\n" "Missing username\r\n" "\r\n" "shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is not logged in") { REQUIRE(0 == shellmatta_auth_getLoggedInUserId(handle)); } } } WHEN("The user shellmatta tries to login using the wrong options") { ret = shellmatta_processData(handle, (char*)"login -o meow\r", 14); CHECK(ret == SHELLMATTA_OK); THEN("A warning message is printed") { char *dummyData = (char*) "login -o meow\r\n" "Unknown option\r\n" "\r\n" "shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is not logged in") { REQUIRE(0 == shellmatta_auth_getLoggedInUserId(handle)); } } } } } SCENARIO("Check login command with unprivileged user") { GIVEN("An initialized shellmatta instance with initialized auth") { TEST_SHELLMATTA_SETUP; TEST_SHELLMATTA_AUTH_SETUP; WHEN("The user not_shimatta logges in interactively using the correct credentials") { ret = shellmatta_processData(handle, (char*)"login\r" "not_shimatta\r" "87654321\r", 28); CHECK(ret == SHELLMATTA_OK); THEN("The login message is printed - password is hidden") { char *dummyData = (char*) "login\r\n" "enter username:\r\n" "not_shimatta\r\n" "enter password:\r\n" "\r\n" "login successful\r\n" "\r\n" "not_shimatta@shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The not_shimatta user is logged in") { REQUIRE(2 == shellmatta_auth_getLoggedInUserId(handle)); } } } } } shellmatta_retCode_t customLogin(const uint32_t userId, const char *password) { if ((userId == 1) && (0 == strcmp(password, "12345678"))) { return SHELLMATTA_OK; } else if ((userId == 2) && (0 == strcmp(password, "87654321"))) { return SHELLMATTA_OK; } return SHELLMATTA_ERROR; } void logFct(const uint32_t userId, bool success) { userIdTemp = userId; successTemp = success; } SCENARIO("Check custom login") { GIVEN("An initialized shellmatta instance with initialized auth with custom login and log") { TEST_SHELLMATTA_SETUP; shellmatta_auth_user_t userList[] = { {1, false, "shimatta", "12345678"}, {2, false, "not_shimatta", "87654321"} }; uint32_t privateCmdPerms[] = {1}; shellmatta_auth_perm_t permList[] = { {"private", privateCmdPerms, sizeof(privateCmdPerms)/sizeof(privateCmdPerms[0])} }; shellmatta_auth_init(handle, userList, 2, permList, 1, false, customLogin, logFct); WHEN("The user not_shimatta logges in interactively using the correct credentials") { ret = shellmatta_processData(handle, (char*)"login\r" "shimatta\r" "12345678\r", 24); CHECK(ret == SHELLMATTA_OK); THEN("The login message is printed - password is hidden") { char *dummyData = (char*) "login\r\n" "enter username:\r\n" "shimatta\r\n" "enter password:\r\n" "\r\n" "login successful\r\n" "\r\n" "shimatta@shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); AND_THEN("The shimatta user is logged in") { REQUIRE(1 == shellmatta_auth_getLoggedInUserId(handle)); } AND_THEN("The login event is logged") { CHECK(1 == userIdTemp); REQUIRE(true == successTemp); } } } } } SCENARIO("Check custom login with custom login function") { GIVEN("An initialized shellmatta instance with initialized auth with custom login and log") { TEST_SHELLMATTA_SETUP; shellmatta_auth_user_t userList[] = { {1, false, "shimatta", "12345678"}, {2, false, "not_shimatta", "87654321"} }; uint32_t privateCmdPerms[] = {1}; shellmatta_auth_perm_t permList[] = { {"private", privateCmdPerms, sizeof(privateCmdPerms)/sizeof(privateCmdPerms[0])} }; shellmatta_auth_init(handle, userList, 2, permList, 1, true, customLogin, logFct); WHEN("The help command is called") { ret = shellmatta_processData(handle, (char*)"help\r", 5); CHECK(ret == SHELLMATTA_OK); THEN("There is no login command") { char *dummyData = (char*) "help\r\n" "help ? help [command] - print help or usage information\r\n" "logout lo Logout command\r\n" "public p\r\n" "\r\n" "shellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE_THAT(write_data, Catch::Matchers::Equals(dummyData)); } } } }