From ff191a303328c5211e9707e80f0d833d0791906f Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 15 Dec 2014 13:58:31 +0100 Subject: [PATCH] Implement --set-policy option in Cyad Policies can be added or altered one by one or in bulk mode. Option --bulk accepts file name as an argument. The "-" value means standard input. Change-Id: I479a29fd5ff43463f6f78d7865468bd84e1642ee --- .../CommandlineParser/CyadCommandlineParser.cpp | 107 ++++++++++++++++++++- src/cyad/CommandlineParser/CyadCommandlineParser.h | 19 ++++ src/cyad/CommandsDispatcher.h | 2 +- test/cyad/commandline.cpp | 76 +++++++++++++++ test/cyad/commandline_errors.cpp | 26 +++++ 5 files changed, 228 insertions(+), 2 deletions(-) diff --git a/src/cyad/CommandlineParser/CyadCommandlineParser.cpp b/src/cyad/CommandlineParser/CyadCommandlineParser.cpp index 713b506..c72967a 100644 --- a/src/cyad/CommandlineParser/CyadCommandlineParser.cpp +++ b/src/cyad/CommandlineParser/CyadCommandlineParser.cpp @@ -47,6 +47,24 @@ namespace CyadCmdlineArgs { const char METADATA = 'm'; const char * const METADATA_LONG = "metadata"; + + const char BUCKET = 'k'; + const char * const BUCKET_LONG = "bucket"; + + const char SET_POLICY = 's'; + const char * const SET_POLICY_LONG = "set-policy"; + + const char CLIENT = 'c'; + const char * const CLIENT_LONG = "client"; + + const char USER = 'u'; + const char * const USER_LONG = "user"; + + const char PRIVILEGE = 'r'; + const char * const PRIVILEGE_LONG = "privilege"; + + const char BULK = 'f'; + const char * const BULK_LONG = "bulk"; } namespace CyadCmdlineErrors { @@ -55,9 +73,12 @@ namespace CyadCmdlineErrors { const char * const UNKNOWN_OPTION = "Unknown option"; const char * const UNKNOWN_OPTION_SET_BUCKET = "Unknown option in --set-bucket"; const char * const UNKNOWN_OPTION_DELETE_BUCKET = "Unknown option in --delete-bucket"; + const char * const UNKNOWN_OPTION_SET_POLICY = "Unknown option in --set-policy"; const char * const NO_POLICY = "No --policy specified"; const char * const NO_BUCKET = "No bucket specified"; const char * const INVALID_POLICY = "Invalid --policy option"; + const char * const OPTION_MISSING_SET_POLICY = "One or more option missing in --set-policy"; + const char * const ARGUMENT_MISSING_SET_POLICY = "One or more argument missing in --set-policy"; } CyadCommandlineParser::CyadCommandlineParser(int argc, char * const *argv) @@ -72,6 +93,7 @@ std::shared_ptr CyadCommandlineParser::parseMain(void) { { Args::HELP_LONG, no_argument, nullptr, Args::HELP }, { Args::SET_BUCKET_LONG, required_argument, nullptr, Args::SET_BUCKET }, { Args::DELETE_BUCKET_LONG, required_argument, nullptr, Args::DELETE_BUCKET }, + { Args::SET_POLICY_LONG, no_argument, nullptr, Args::SET_POLICY }, { nullptr, 0, nullptr, 0 } }; @@ -80,7 +102,8 @@ std::shared_ptr CyadCommandlineParser::parseMain(void) { std::stringstream optstr; optstr << ":" << Args::HELP << Args::SET_BUCKET << ":" - << Args::DELETE_BUCKET << ":"; + << Args::DELETE_BUCKET << ":" + << Args::SET_POLICY; while ((opt = getopt_long(m_argc, m_argv, optstr.str().c_str(), long_options, nullptr)) != -1) { switch (opt) { @@ -93,6 +116,9 @@ std::shared_ptr CyadCommandlineParser::parseMain(void) { case Args::DELETE_BUCKET: return parseDeleteBucket(optarg); + case Args::SET_POLICY: + return parseSetPolicy(); + case '?': // Unknown option return std::make_shared(CyadCmdlineErrors::UNKNOWN_OPTION); @@ -171,6 +197,85 @@ std::shared_ptr CyadCommandlineParser::parseDeleteBucket(const std: } } +std::shared_ptr CyadCommandlineParser::parseSetPolicy(void) { + namespace Args = CyadCmdlineArgs; + namespace Errors = CyadCmdlineErrors; + + const struct option long_options[] = { + { Args::CLIENT_LONG, required_argument, nullptr, Args::CLIENT }, + { Args::USER_LONG, required_argument, nullptr, Args::USER }, + { Args::PRIVILEGE_LONG, required_argument, nullptr, Args::PRIVILEGE }, + { Args::BUCKET_LONG, required_argument, nullptr, Args::BUCKET }, + { Args::POLICY_LONG, required_argument, nullptr, Args::POLICY }, + { Args::METADATA_LONG, required_argument, nullptr, Args::METADATA }, + { Args::BULK_LONG, required_argument, nullptr, Args::BULK }, + { nullptr, 0, nullptr, 0 } + }; + + typedef std::map OptionsValues; + OptionsValues values = { { Args::CLIENT, std::string() }, + { Args::USER, std::string() }, + { Args::PRIVILEGE, std::string() }, + { Args::POLICY, std::string() } }; + + std::string metadata; + std::string bucket; + + int opt; + std::stringstream optstr; + optstr << ":" + << Args::CLIENT << ":" + << Args::USER << ":" + << Args::PRIVILEGE << ":" + << Args::BUCKET << ":" + << Args::POLICY << ":" + << Args::METADATA << ":" + << Args::BULK << ":"; + + while ((opt = getopt_long(m_argc, m_argv, optstr.str().c_str(), long_options, nullptr)) != -1) { + switch(opt) { + case Args::CLIENT: + case Args::USER: + case Args::PRIVILEGE: + case Args::POLICY: + values[opt] = optarg; + break; + case Args::BUCKET: + bucket = optarg; + break; + case Args::METADATA: + metadata = optarg; + break; + case Args::BULK: + return std::make_shared(optarg); + case ':': // Missing argument + return std::make_shared(Errors::ARGUMENT_MISSING_SET_POLICY); + default: + return std::make_shared(Errors::UNKNOWN_OPTION_SET_POLICY); + } + } + + for (const auto &val : values) { + if (val.second.empty()) { + // TODO: Identify actual option + return std::make_shared(Errors::OPTION_MISSING_SET_POLICY); + } + } + + try { + auto policyType = parsePolicyType(values[Args::POLICY]); + auto policyResult = PolicyResult(policyType, metadata); + return std::make_shared(bucket, policyResult, + PolicyKey(values[Args::CLIENT], + values[Args::USER], + values[Args::PRIVILEGE])); + } catch (const PolicyParsingException &) { + return std::make_shared(Errors::INVALID_POLICY); + } + + return std::make_shared(Errors::UNKNOWN_ERROR); +} + PolicyType CyadCommandlineParser::parsePolicyType(const std::string &rawPolicy) { if (rawPolicy == "DENY") return CYNARA_ADMIN_DENY; diff --git a/src/cyad/CommandlineParser/CyadCommandlineParser.h b/src/cyad/CommandlineParser/CyadCommandlineParser.h index 4b629c4..891751e 100644 --- a/src/cyad/CommandlineParser/CyadCommandlineParser.h +++ b/src/cyad/CommandlineParser/CyadCommandlineParser.h @@ -44,6 +44,21 @@ namespace CyadCmdlineArgs { extern const char METADATA; extern const char * const METADATA_LONG; + + extern const char BUCKET; + extern const char * const BUCKET_LONG; + + extern const char CLIENT; + extern const char * const CLIENT_LONG; + + extern const char USER; + extern const char * const USER_LONG; + + extern const char PRIVILEGE; + extern const char * const PRIVILEGE_LONG; + + extern const char BULK; + extern const char * const BULK_LONG; } namespace CyadCmdlineErrors { @@ -52,9 +67,12 @@ namespace CyadCmdlineErrors { extern const char * const UNKNOWN_OPTION; extern const char * const UNKNOWN_OPTION_SET_BUCKET; extern const char * const UNKNOWN_OPTION_DELETE_BUCKET; + extern const char * const UNKNOWN_OPTION_SET_POLICY; extern const char * const NO_POLICY; extern const char * const NO_BUCKET; extern const char * const INVALID_POLICY; + extern const char * const OPTION_MISSING_SET_POLICY; + extern const char * const ARGUMENT_MISSING_SET_POLICY; } class CyadCommandlineParser { @@ -68,6 +86,7 @@ public: protected: std::shared_ptr parseSetBucket(const std::string &bucketId); std::shared_ptr parseDeleteBucket(const std::string &bucketId); + std::shared_ptr parseSetPolicy(void); private: int m_argc; diff --git a/src/cyad/CommandsDispatcher.h b/src/cyad/CommandsDispatcher.h index 4193a95..5193e1d 100644 --- a/src/cyad/CommandsDispatcher.h +++ b/src/cyad/CommandsDispatcher.h @@ -57,7 +57,7 @@ private: " -d, --delete-bucket= name of bucket to delete\n" "\n" "Policy set options (with -s or --set-policy)\n" - " -l, --client= client value\n" + " -c, --client= client value\n" " -u, --user= user value\n" " -r, --privilege= privilege value\n" " -p, --policy= policy\n" diff --git a/test/cyad/commandline.cpp b/test/cyad/commandline.cpp index 31b0771..60bb69a 100644 --- a/test/cyad/commandline.cpp +++ b/test/cyad/commandline.cpp @@ -73,6 +73,64 @@ TEST_F(CyadCommandlineTest, setBucketWithMetadata) { ASSERT_EQ(ultimateAnswer, result->policyResult().metadata()); } +TEST_F(CyadCommandlineTest, setPolicy) { + prepare_argv({ "./cyad", "--set-policy", "--bucket=some-bucket", + "--client=client", "--user=user", "--privilege=privilege", + "--policy=42" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("some-bucket", result->bucketId()); + + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ(42, result->policyResult().policyType()); + ASSERT_TRUE(result->policyResult().metadata().empty()); +} + +TEST_F(CyadCommandlineTest, setPolicyWithMetadata) { + prepare_argv({ "./cyad", "--set-policy", "--bucket=some-bucket", + "--client=client", "--user=user", "--privilege=privilege", + "--policy=42", "--metadata=some-metadata" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("some-bucket", result->bucketId()); + + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ(42, result->policyResult().policyType()); + ASSERT_EQ("some-metadata", result->policyResult().metadata()); +} + +TEST_F(CyadCommandlineTest, setPolicyInDefaultBucket) { + prepare_argv({ "./cyad", "--set-policy", "--bucket=", + "--client=client", "--user=user", "--privilege=privilege", + "--policy=ALLOW", "--metadata=some-metadata" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("", result->bucketId()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, result->policyResult().policyType()); + ASSERT_EQ("some-metadata", result->policyResult().metadata()); +} + +TEST_F(CyadCommandlineTest, setPolicyInDefaultBucketNoOption) { + prepare_argv({ "./cyad", "--set-policy", + "--client=client", "--user=user", "--privilege=privilege", + "--policy=ALLOW", "--metadata=some-metadata" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("", result->bucketId()); + ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey()); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, result->policyResult().policyType()); + ASSERT_EQ("some-metadata", result->policyResult().metadata()); +} + TEST_F(CyadCommandlineTest, parsePolicyTypeBase10) { auto parsePolicyType = [] (const char *rawPolicy) -> Cynara::PolicyType { return Cynara::CyadCommandlineParser::parsePolicyType(rawPolicy); @@ -105,3 +163,21 @@ TEST_F(CyadCommandlineTest, parsePolicyTypeHuman) { ASSERT_EQ(CYNARA_ADMIN_BUCKET, parsePolicyType("BUCKET")); ASSERT_EQ(CYNARA_ADMIN_ALLOW, parsePolicyType("ALLOW")); } + +TEST_F(CyadCommandlineTest, setPoliciesBulkFilename) { + prepare_argv({ "./cyad", "--set-policy", "--bulk=/tmp/input_file" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("/tmp/input_file", result->filename()); +} + +TEST_F(CyadCommandlineTest, setPoliciesBulkStdin) { + prepare_argv({ "./cyad", "--set-policy", "--bulk=-" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("-", result->filename()); +} diff --git a/test/cyad/commandline_errors.cpp b/test/cyad/commandline_errors.cpp index 5aa358f..fb2fa30 100644 --- a/test/cyad/commandline_errors.cpp +++ b/test/cyad/commandline_errors.cpp @@ -90,3 +90,29 @@ TEST_F(CyadCommandlineTest, setBucketMetadataNoPolicy) { Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::NO_POLICY, parser.parseMain()); } + +TEST_F(CyadCommandlineTest, setPolicyNoOption) { + prepare_argv({ "./cyad", "--set-policy" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::OPTION_MISSING_SET_POLICY, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setPolicyUnknownOption) { + prepare_argv({ "./cyad", "--set-policy", "--unknown-option" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::UNKNOWN_OPTION_SET_POLICY, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setPolicyArgumentMissing) { + prepare_argv({ "./cyad", "--set-policy", "--bucket" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::ARGUMENT_MISSING_SET_POLICY, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setPolicyNoPolicy) { + // TODO: In the future, we can identify actual options being missed + prepare_argv({ "./cyad", "--set-policy", "--bucket=some-bucket", + "--client=client", "--user=user", "--privilege=privilege" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::OPTION_MISSING_SET_POLICY, parser.parseMain()); +} -- 2.7.4