2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/ConfigProcessor.h>
|
2017-11-27 21:31:13 +00:00
|
|
|
#include <Interpreters/SecurityManager.h>
|
2016-06-07 08:23:15 +00:00
|
|
|
|
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <tuple>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
|
|
|
|
struct TestEntry
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
std::string user_name;
|
|
|
|
std::string database_name;
|
|
|
|
bool is_allowed;
|
2016-06-07 08:23:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
using TestEntries = std::vector<TestEntry>;
|
|
|
|
|
|
|
|
struct TestDescriptor
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
const char * config_content;
|
|
|
|
TestEntries entries;
|
2016-06-07 08:23:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
using TestSet = std::vector<TestDescriptor>;
|
|
|
|
|
2017-04-02 17:37:49 +00:00
|
|
|
/// Tests description.
|
2016-06-07 08:23:15 +00:00
|
|
|
|
|
|
|
TestSet test_set =
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
"<?xml version=\"1.0\"?><yandex>"
|
|
|
|
" <profiles><default></default></profiles>"
|
|
|
|
" <users>"
|
|
|
|
" <default>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" <allow_databases>"
|
|
|
|
" <database>default</database>"
|
|
|
|
" <database>test</database>"
|
|
|
|
" </allow_databases>"
|
|
|
|
" </default>"
|
|
|
|
" <web>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" </web>"
|
|
|
|
" </users>"
|
|
|
|
" <quotas><default></default></quotas>"
|
|
|
|
"</yandex>",
|
|
|
|
|
|
|
|
{
|
|
|
|
{ "default", "default", true },
|
|
|
|
{ "default", "test", true },
|
|
|
|
{ "default", "stats", false },
|
|
|
|
{ "web", "default", true },
|
|
|
|
{ "web", "test", true },
|
|
|
|
{ "web", "stats", true },
|
|
|
|
{ "analytics", "default", false },
|
|
|
|
{ "analytics", "test", false },
|
|
|
|
{ "analytics", "stats", false }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"<?xml version=\"1.0\"?><yandex>"
|
|
|
|
" <profiles><default></default></profiles>"
|
|
|
|
" <users>"
|
|
|
|
" <default>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" <allow_databases>"
|
|
|
|
" <database>default</database>"
|
|
|
|
" </allow_databases>"
|
|
|
|
" </default>"
|
|
|
|
" <web>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" </web>"
|
|
|
|
" </users>"
|
|
|
|
" <quotas><default></default></quotas>"
|
|
|
|
"</yandex>",
|
|
|
|
|
|
|
|
{
|
|
|
|
{ "default", "default", true },
|
|
|
|
{ "default", "test", false },
|
|
|
|
{ "default", "stats", false },
|
|
|
|
{ "web", "default", true },
|
|
|
|
{ "web", "test", true },
|
|
|
|
{ "web", "stats", true },
|
|
|
|
{ "analytics", "default", false },
|
|
|
|
{ "analytics", "test", false },
|
|
|
|
{ "analytics", "stats", false }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"<?xml version=\"1.0\"?><yandex>"
|
|
|
|
" <profiles><default></default></profiles>"
|
|
|
|
" <users>"
|
|
|
|
" <default>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" <allow_databases>"
|
|
|
|
" </allow_databases>"
|
|
|
|
" </default>"
|
|
|
|
" <web>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" </web>"
|
|
|
|
" </users>"
|
|
|
|
" <quotas><default></default></quotas>"
|
|
|
|
"</yandex>",
|
|
|
|
|
|
|
|
{
|
|
|
|
{ "default", "default", true },
|
|
|
|
{ "default", "test", true },
|
|
|
|
{ "default", "stats", true },
|
|
|
|
{ "web", "default", true },
|
|
|
|
{ "web", "test", true },
|
|
|
|
{ "web", "stats", true },
|
|
|
|
{ "analytics", "default", false },
|
|
|
|
{ "analytics", "test", false },
|
|
|
|
{ "analytics", "stats", false }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"<?xml version=\"1.0\"?><yandex>"
|
|
|
|
" <profiles><default></default></profiles>"
|
|
|
|
" <users>"
|
|
|
|
" <default>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" <allow_databases>"
|
|
|
|
" <database>default</database>"
|
|
|
|
" </allow_databases>"
|
|
|
|
" </default>"
|
|
|
|
" <web>"
|
|
|
|
" <password></password><profile>default</profile><quota>default</quota>"
|
|
|
|
" <allow_databases>"
|
|
|
|
" <database>test</database>"
|
|
|
|
" </allow_databases>"
|
|
|
|
" </web>"
|
|
|
|
" </users>"
|
|
|
|
" <quotas><default></default></quotas>"
|
|
|
|
"</yandex>",
|
|
|
|
|
|
|
|
{
|
|
|
|
{ "default", "default", true },
|
|
|
|
{ "default", "test", false },
|
|
|
|
{ "default", "stats", false },
|
|
|
|
{ "web", "default", false },
|
|
|
|
{ "web", "test", true },
|
|
|
|
{ "web", "stats", false },
|
|
|
|
{ "analytics", "default", false },
|
|
|
|
{ "analytics", "test", false },
|
|
|
|
{ "analytics", "stats", false }
|
|
|
|
}
|
|
|
|
}
|
2016-06-07 08:23:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
std::string createTmpPath(const std::string & filename);
|
|
|
|
void createFile(const std::string & filename, const char * data);
|
2017-12-02 02:47:12 +00:00
|
|
|
void runOneTest(const TestDescriptor & test_descriptor);
|
2016-06-07 08:23:15 +00:00
|
|
|
auto runTestSet(const TestSet & test_set);
|
|
|
|
|
|
|
|
std::string createTmpPath(const std::string & filename)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
char pattern[] = "/tmp/fileXXXXXX";
|
|
|
|
char * dir = mkdtemp(pattern);
|
|
|
|
if (dir == nullptr)
|
|
|
|
throw std::runtime_error("Could not create directory");
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return std::string(dir) + "/" + filename;
|
2016-06-07 08:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void createFile(const std::string & filename, const char * data)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
std::ofstream ofs(filename.c_str());
|
|
|
|
if (!ofs.is_open())
|
|
|
|
throw std::runtime_error("Could not open file " + filename);
|
|
|
|
ofs << data;
|
2016-06-07 08:23:15 +00:00
|
|
|
}
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
void runOneTest(const TestDescriptor & test_descriptor)
|
2016-06-07 08:23:15 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
const auto path_name = createTmpPath("users.xml");
|
|
|
|
createFile(path_name, test_descriptor.config_content);
|
|
|
|
|
|
|
|
ConfigurationPtr config;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2017-11-21 16:54:25 +00:00
|
|
|
config = ConfigProcessor(path_name).loadConfig().configuration;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
catch (const Poco::Exception & ex)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Error: " << ex.what() << ": " << ex.displayText();
|
|
|
|
throw std::runtime_error(os.str());
|
|
|
|
}
|
|
|
|
|
2017-11-27 21:31:13 +00:00
|
|
|
DB::SecurityManager security_manager;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2017-11-27 21:31:13 +00:00
|
|
|
security_manager.loadFromConfig(*config);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
catch (const Poco::Exception & ex)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Error: " << ex.what() << ": " << ex.displayText();
|
|
|
|
throw std::runtime_error(os.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto & entry : test_descriptor.entries)
|
|
|
|
{
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2017-11-27 21:31:13 +00:00
|
|
|
res = security_manager.hasAccessToDatabase(entry.user_name, entry.database_name);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
catch (const Poco::Exception &)
|
|
|
|
{
|
|
|
|
res = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res != entry.is_allowed)
|
|
|
|
{
|
|
|
|
auto to_string = [](bool access){ return (access ? "'granted'" : "'denied'"); };
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "(user=" << entry.user_name << ", database=" << entry.database_name << "): ";
|
|
|
|
os << "Expected " << to_string(entry.is_allowed) << " but got " << to_string(res);
|
|
|
|
throw std::runtime_error(os.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::remove_all(fs::path(path_name).parent_path().string());
|
2016-06-07 08:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto runTestSet(const TestSet & test_set)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t test_num = 1;
|
|
|
|
size_t failure_count = 0;
|
|
|
|
|
|
|
|
for (const auto & test_descriptor : test_set)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2017-12-02 02:47:12 +00:00
|
|
|
runOneTest(test_descriptor);
|
2017-04-01 07:20:54 +00:00
|
|
|
std::cout << "Test " << test_num << " passed\n";
|
|
|
|
}
|
|
|
|
catch (const std::runtime_error & ex)
|
|
|
|
{
|
|
|
|
std::cerr << "Test " << test_num << " failed with reason: " << ex.what() << "\n";
|
|
|
|
++failure_count;
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
std::cerr << "Test " << test_num << " failed with unknown reason\n";
|
|
|
|
++failure_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
++test_num;
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_tuple(test_set.size(), failure_count);
|
2016-06-07 08:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t test_count;
|
|
|
|
size_t failure_count;
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
std::tie(test_count, failure_count) = runTestSet(test_set);
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
std::cout << (test_count - failure_count) << " test(s) passed out of " << test_count << "\n";
|
2016-06-07 08:23:15 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return (failure_count == 0) ? 0 : EXIT_FAILURE;
|
2016-06-07 08:23:15 +00:00
|
|
|
}
|