From a2e2814c8e237590ef6a212389796224965251c4 Mon Sep 17 00:00:00 2001 From: julianbermudez Date: Mon, 20 Jan 2020 08:16:07 +0000 Subject: [PATCH] Add test_security_directory test from rcl. --- CMakeLists.txt | 14 ++ .../dummy_node/.gitkeep | 0 test/test_security_directory.cpp | 216 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 test/resources/test_security_directory/dummy_node/.gitkeep create mode 100644 test/test_security_directory.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f61a09f..8240c803 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,9 @@ if(BUILD_TESTING) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") endif() + set(test_resources_dir_name "test/resources") + add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/${test_resources_dir_name}") + find_package(ament_cmake_gmock REQUIRED) find_package(ament_cmake_gtest REQUIRED) find_package(ament_cmake_pytest REQUIRED) @@ -364,6 +367,17 @@ if(BUILD_TESTING) if(TARGET test_hash_map) target_link_libraries(test_hash_map ${PROJECT_NAME}) endif() + + rcutils_custom_add_gtest(test_security_directory + test/test_security_directory.cpp + ) + if(TARGET test_security_directory) + target_link_libraries(test_security_directory ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools) + endif() + + install(DIRECTORY ${test_resources_dir_name} + DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + ) endif() ament_export_dependencies(ament_cmake) diff --git a/test/resources/test_security_directory/dummy_node/.gitkeep b/test/resources/test_security_directory/dummy_node/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/test/test_security_directory.cpp b/test/test_security_directory.cpp new file mode 100644 index 00000000..bf1b7f2b --- /dev/null +++ b/test/test_security_directory.cpp @@ -0,0 +1,216 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include "rcutils/security_directory.h" +#include "rcutils/filesystem.h" +#include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "rcutils/error_handling.h" + +#define ROOT_NAMESPACE "/" +#define TEST_SECURITY_DIRECTORY_RESOURCES_DIR_NAME "test_security_directory" +#define TEST_NODE_NAME "dummy_node" +#define TEST_NODE_NAMESPACE ROOT_NAMESPACE TEST_SECURITY_DIRECTORY_RESOURCES_DIR_NAME + +char g_envstring[512] = {0}; + +static int putenv_wrapper(const char * env_var) +{ +#ifdef _WIN32 + return _putenv(env_var); +#else + return putenv(reinterpret_cast(const_cast(env_var))); +#endif +} + +static int unsetenv_wrapper(const char * var_name) +{ +#ifdef _WIN32 + // On windows, putenv("VAR=") deletes VAR from environment + std::string var(var_name); + var += "="; + return _putenv(var.c_str()); +#else + return unsetenv(var_name); +#endif +} + +class TestGetSecureRoot : public ::testing::Test +{ +protected: + void SetUp() final + { + // Reset rcutils error global state in case a previously + // running test has failed. + rcutils_reset_error(); + + // Always make sure the variable we set is unset at the beginning of a test + unsetenv_wrapper(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME); + unsetenv_wrapper(ROS_SECURITY_NODE_DIRECTORY_VAR_NAME); + unsetenv_wrapper(ROS_SECURITY_LOOKUP_TYPE_VAR_NAME); + allocator = rcutils_get_default_allocator(); + root_path = nullptr; + secure_root = nullptr; + base_lookup_dir_fqn = nullptr; + } + + void TearDown() final + { + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ + allocator.deallocate(root_path, allocator.state); + }); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ + allocator.deallocate(secure_root, allocator.state); + }); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ + allocator.deallocate(base_lookup_dir_fqn, allocator.state); + }); + } + + void set_base_lookup_dir_fqn(const char * resource_dir, const char * resource_dir_name) + { + base_lookup_dir_fqn = rcutils_join_path(resource_dir, + resource_dir_name, allocator); + std::string putenv_input = ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "="; + putenv_input += base_lookup_dir_fqn; + memcpy(g_envstring, putenv_input.c_str(), + std::min(putenv_input.length(), sizeof(g_envstring) - 1)); + putenv_wrapper(g_envstring); + } + + rcutils_allocator_t allocator; + char * root_path; + char * secure_root; + char * base_lookup_dir_fqn; +}; + +TEST_F(TestGetSecureRoot, failureScenarios) { + ASSERT_EQ(rcutils_get_secure_root(TEST_NODE_NAME, TEST_NODE_NAMESPACE, &allocator), + (char *) NULL); + + putenv_wrapper(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + + /* Security directory is set, but there's no matching directory */ + /// Wrong namespace + ASSERT_EQ(rcutils_get_secure_root(TEST_NODE_NAME, "/some_other_namespace", &allocator), + (char *) NULL); + /// Wrong node name + ASSERT_EQ(rcutils_get_secure_root("not_" TEST_NODE_NAME, TEST_NODE_NAMESPACE, &allocator), + (char *) NULL); +} + +TEST_F(TestGetSecureRoot, successScenarios_local_exactMatch) { + putenv_wrapper(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + + /* -------------------------- + * Namespace : Custom (local) + * Match type : Exact + * -------------------------- + * Root: ${CMAKE_BINARY_DIR}/tests/resources + * Namespace: /test_security_directory + * Node: dummy_node + */ + secure_root = rcutils_get_secure_root(TEST_NODE_NAME, TEST_NODE_NAMESPACE, &allocator); + std::string secure_root_str(secure_root); + ASSERT_STREQ(TEST_NODE_NAME, + secure_root_str.substr(secure_root_str.size() - (sizeof(TEST_NODE_NAME) - 1)).c_str()); +} + +TEST_F(TestGetSecureRoot, successScenarios_local_prefixMatch) { + putenv_wrapper(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + secure_root = rcutils_get_secure_root(TEST_NODE_NAME, TEST_NODE_NAMESPACE, &allocator); + + /* -------------------------- + * Namespace : Custom (local) + * Match type : Prefix + * -------------------------- + * Root: ${CMAKE_BINARY_DIR}/tests/resources + * Namespace: /test_security_directory + * Node: dummy_node_and_some_suffix_added */ + root_path = rcutils_get_secure_root(TEST_NODE_NAME "_and_some_suffix_added", + TEST_NODE_NAMESPACE, &allocator); + ASSERT_STRNE(root_path, secure_root); + putenv_wrapper(ROS_SECURITY_LOOKUP_TYPE_VAR_NAME "=MATCH_PREFIX"); + root_path = rcutils_get_secure_root(TEST_NODE_NAME "_and_some_suffix_added", + TEST_NODE_NAMESPACE, &allocator); + ASSERT_STREQ(root_path, secure_root); +} + +TEST_F(TestGetSecureRoot, successScenarios_root_exactMatch) { + putenv_wrapper(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + putenv_wrapper(ROS_SECURITY_LOOKUP_TYPE_VAR_NAME "=MATCH_PREFIX"); + secure_root = rcutils_get_secure_root(TEST_NODE_NAME, TEST_NODE_NAMESPACE, &allocator); + + /* Include the namespace as part of the root security directory and test root namespace */ + set_base_lookup_dir_fqn(TEST_RESOURCES_DIRECTORY, TEST_SECURITY_DIRECTORY_RESOURCES_DIR_NAME); + /* -------------------------- + * Namespace : Root + * Match type : Exact + * -------------------------- + * Root: ${CMAKE_BINARY_DIR}/tests/resources/test_security_directory + * Namespace: / + * Node: dummy_node */ + root_path = rcutils_get_secure_root(TEST_NODE_NAME, ROOT_NAMESPACE, &allocator); + ASSERT_STREQ(root_path, secure_root); +} + +TEST_F(TestGetSecureRoot, successScenarios_root_prefixMatch) { + putenv_wrapper(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + putenv_wrapper(ROS_SECURITY_LOOKUP_TYPE_VAR_NAME "=MATCH_PREFIX"); + secure_root = rcutils_get_secure_root(TEST_NODE_NAME, TEST_NODE_NAMESPACE, &allocator); + + /* Include the namespace as part of the root security directory and test root namespace */ + set_base_lookup_dir_fqn(TEST_RESOURCES_DIRECTORY, TEST_SECURITY_DIRECTORY_RESOURCES_DIR_NAME); + /* -------------------------- + * Namespace : Root + * Match type : Prefix + * -------------------------- + * Root dir: ${CMAKE_BINARY_DIR}/tests/resources/test_security_directory + * Namespace: / + * Node: dummy_node_and_some_suffix_added */ + root_path = rcutils_get_secure_root(TEST_NODE_NAME "_and_some_suffix_added", + ROOT_NAMESPACE, &allocator); + ASSERT_STREQ(root_path, secure_root); +} + +TEST_F(TestGetSecureRoot, nodeSecurityDirectoryOverride_validDirectory) { + /* Specify a valid directory */ + putenv_wrapper(ROS_SECURITY_NODE_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + root_path = rcutils_get_secure_root("name shouldn't matter", + "namespace shouldn't matter", &allocator); + ASSERT_STREQ(root_path, TEST_RESOURCES_DIRECTORY); +} + +TEST_F(TestGetSecureRoot, + nodeSecurityDirectoryOverride_validDirectory_overrideRootDirectoryAttempt) { + /* Setting root dir has no effect */ + putenv_wrapper(ROS_SECURITY_NODE_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + root_path = rcutils_get_secure_root("name shouldn't matter", + "namespace shouldn't matter", &allocator); + putenv_wrapper(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "=" TEST_RESOURCES_DIRECTORY); + ASSERT_STREQ(root_path, TEST_RESOURCES_DIRECTORY); +} + +TEST_F(TestGetSecureRoot, nodeSecurityDirectoryOverride_invalidDirectory) { + /* The override provided should exist. Providing correct node/namespace/root dir won't help + * if the node override is invalid. */ + putenv_wrapper( + ROS_SECURITY_NODE_DIRECTORY_VAR_NAME + "=TheresN_oWayThi_sDirectory_Exists_hence_this_would_fail"); + ASSERT_EQ(rcutils_get_secure_root(TEST_NODE_NAME, TEST_NODE_NAMESPACE, &allocator), + (char *) NULL); +}