Implement --list-policies option in Cyad 88/33888/4
authorAleksander Zdyb <a.zdyb@samsung.com>
Fri, 16 Jan 2015 09:06:12 +0000 (10:06 +0100)
committerAleksander Zdyb <a.zdyb@samsung.com>
Fri, 16 Jan 2015 10:06:29 +0000 (11:06 +0100)
Change-Id: Ib20721f04dc4c43ee92f5e279cdf764dbaf2cc2a

18 files changed:
src/cyad/AdminApiWrapper.cpp
src/cyad/AdminApiWrapper.h
src/cyad/BaseAdminApiWrapper.h
src/cyad/CommandlineParser/CmdlineOpts.cpp
src/cyad/CommandlineParser/CmdlineOpts.h
src/cyad/CommandlineParser/CyadCommand.cpp
src/cyad/CommandlineParser/CyadCommand.h
src/cyad/CommandlineParser/CyadCommandlineParser.cpp
src/cyad/CommandlineParser/CyadCommandlineParser.h
src/cyad/CommandsDispatcher.cpp
src/cyad/CommandsDispatcher.h
src/cyad/CynaraAdminPolicies.cpp
src/cyad/CynaraAdminPolicies.h
test/cyad/FakeAdminApiWrapper.h
test/cyad/commandline.cpp
test/cyad/commandline_errors.cpp
test/cyad/commandline_options.cpp
test/cyad/commands_dispatcher.cpp

index 5cfc6ae..6224a1b 100644 (file)
@@ -62,4 +62,11 @@ int AdminApiWrapper::cynara_admin_erase(struct cynara_admin *p_cynara_admin,
     return ::cynara_admin_erase(p_cynara_admin, start_bucket, recursive, client, user, privilege);
 }
 
+int AdminApiWrapper::cynara_admin_list_policies(struct cynara_admin *p_cynara_admin,
+                                                const char *bucket, const char *client,
+                                                const char *user, const char *privilege,
+                                                struct cynara_admin_policy ***policies) {
+    return ::cynara_admin_list_policies(p_cynara_admin, bucket, client, user, privilege, policies);
+}
+
 } /* namespace Cynara */
index 369a0f4..19663dc 100644 (file)
@@ -45,6 +45,10 @@ public:
                                    const char *start_bucket, const int recursive,
                                    const char *client, const char *user, const char *privilege,
                                    int *result, char **result_extra);
+    virtual int cynara_admin_list_policies(struct cynara_admin *p_cynara_admin, const char *bucket,
+                                           const char *client, const char *user,
+                                           const char *privilege,
+                                           struct cynara_admin_policy ***policies);
     virtual int cynara_admin_erase(struct cynara_admin *p_cynara_admin, const char *start_bucket,
                                    int recursive, const char *client, const char *user,
                                    const char *privilege);
index e44b130..41710f9 100644 (file)
@@ -41,6 +41,10 @@ public:
                                    const char *start_bucket, const int recursive,
                                    const char *client, const char *user, const char *privilege,
                                    int *result, char **result_extra) = 0;
+    virtual int cynara_admin_list_policies(struct cynara_admin *p_cynara_admin, const char *bucket,
+                                           const char *client, const char *user,
+                                           const char *privilege,
+                                           struct cynara_admin_policy ***policies) = 0;
     virtual int cynara_admin_erase(struct cynara_admin *p_cynara_admin, const char *start_bucket,
                                    int recursive, const char *client, const char *user,
                                    const char *privilege) = 0;
index 1e8f2bc..a356287 100644 (file)
@@ -45,6 +45,9 @@ const OptionsMap commandlineOptions = {
     { CmdlineOpt::Check,
         { "check", CmdlineOpt::Check, "check",
           "", OptHasArg::NoArgument } },
+    { CmdlineOpt::ListPolicies,
+        { "list-policies", CmdlineOpt::ListPolicies, "list-policies=<bucket>",
+          "name of bucket to erase policies from", OptHasArg::RequiredArgument } },
 
     { CmdlineOpt::Type,
         { "type", CmdlineOpt::Type, "type=<type>",
@@ -162,6 +165,13 @@ std::string makeHelp(void) {
     helpStr << opt(CmdlineOpt::Privilege) << std::endl;
     helpStr << std::endl;
 
+    helpStr << head("Policies list options", CmdlineOpt::ListPolicies) << std::endl;
+    helpStr << opt(CmdlineOpt::ListPolicies) << std::endl;
+    helpStr << opt(CmdlineOpt::Client) << std::endl;
+    helpStr << opt(CmdlineOpt::User) << std::endl;
+    helpStr << opt(CmdlineOpt::Privilege) << std::endl;
+    helpStr << std::endl;
+
     helpStr << head("Help options", CmdlineOpt::Help) << std::endl;
     helpStr << opt(CmdlineOpt::Help);
 
index 63d73b3..8c357f4 100644 (file)
@@ -39,6 +39,7 @@ enum CmdlineOpt {
     SetPolicy = 's',
     Erase = 'e',
     Check = 'a',
+    ListPolicies = 'l',
 
     Type = 't',
     Metadata = 'm',
index 165eb37..6d5f0ca 100644 (file)
@@ -62,4 +62,8 @@ int CheckCyadCommand::run(CommandsDispatcher &dispatcher) {
     return dispatcher.execute(*this);
 }
 
+int ListPoliciesCyadCommand::run(CommandsDispatcher &dispatcher) {
+    return dispatcher.execute(*this);
+}
+
 } /* namespace Cynara */
index 968cee7..9973b7c 100644 (file)
@@ -207,6 +207,28 @@ private:
     PolicyKey m_policyKey;
 };
 
+class ListPoliciesCyadCommand : public CyadCommand {
+public:
+    ListPoliciesCyadCommand(const PolicyBucketId &bucketId, const PolicyKey &policyKey)
+        : m_bucketId(bucketId), m_policyKey(policyKey) {}
+
+    virtual ~ListPoliciesCyadCommand() {}
+
+    virtual int run(CommandsDispatcher &dispatcher);
+
+    const PolicyBucketId &bucketId(void) const {
+        return m_bucketId;
+    }
+
+    const PolicyKey &policyKey(void) const {
+        return m_policyKey;
+    }
+
+private:
+    PolicyBucketId m_bucketId;
+    PolicyKey m_policyKey;
+};
+
 } /* namespace Cynara */
 
 #endif /* SRC_CYAD_COMMANDLINEPARSER_CYADCOMMAND_H_ */
index 8f66ce4..0ef406e 100644 (file)
@@ -58,7 +58,8 @@ std::shared_ptr<CyadCommand> CyadCommandlineParser::parseMain(void) {
         CmdlineOpt::DeleteBucket,
         CmdlineOpt::SetPolicy,
         CmdlineOpt::Erase,
-        CmdlineOpt::Check
+        CmdlineOpt::Check,
+        CmdlineOpt::ListPolicies
     };
 
     const auto longOpts = Opts::makeLongOptions(opts);
@@ -86,6 +87,9 @@ std::shared_ptr<CyadCommand> CyadCommandlineParser::parseMain(void) {
             case CmdlineOpt::Check:
                 return parseCheck();
 
+            case CmdlineOpt::ListPolicies:
+                return parseListPolicies(optarg);
+
             case '?': // Unknown option
                 return sharedError(Err::unknownOption());
 
@@ -94,6 +98,7 @@ std::shared_ptr<CyadCommand> CyadCommandlineParser::parseMain(void) {
                     case CmdlineOpt::SetBucket:
                     case CmdlineOpt::DeleteBucket:
                     case CmdlineOpt::Erase:
+                    case CmdlineOpt::ListPolicies:
                         return sharedError(Err::noBucket());
                 }
                 // Shall never happen, but let's just make compiler happy.
@@ -348,4 +353,51 @@ std::shared_ptr<CyadCommand> CyadCommandlineParser::parseCheck(void) {
                                                         values[CmdlineOpt::Privilege]));
 }
 
+std::shared_ptr<CyadCommand> CyadCommandlineParser::parseListPolicies(const std::string &bucketId) {
+    namespace Opts = CmdlineOpts;
+    namespace Err = CmdlineErrors;
+    using CmdlineOpts::CmdlineOpt;
+
+    std::vector<CmdlineOpt> opts = {
+        CmdlineOpt::Client,
+        CmdlineOpt::User,
+        CmdlineOpt::Privilege
+    };
+
+    const auto longOpts = Opts::makeLongOptions(opts);
+    const auto shortOpts = Opts::makeShortOptions(opts);
+
+    typedef std::unordered_map<char, std::string> OptionsValues;
+    OptionsValues values = { { CmdlineOpt::Client,    std::string() },
+                             { CmdlineOpt::User,      std::string() },
+                             { CmdlineOpt::Privilege, std::string() } };
+
+    int opt;
+    while ((opt = getopt_long(m_argc, m_argv, shortOpts.data(), longOpts.data(), nullptr)) != -1) {
+        switch (opt) {
+            case CmdlineOpt::Client:
+            case CmdlineOpt::User:
+            case CmdlineOpt::Privilege:
+                values[opt] = optarg;
+                break;
+            case ':': // Missing argument
+                return sharedError(Err::argumentMissing(CmdlineOpt::ListPolicies));
+            default:
+                return sharedError(Err::unknownOption(CmdlineOpt::ListPolicies));
+        }
+    }
+
+    for (const auto &val : values) {
+        if (val.second.empty()) {
+            // TODO: Identify actual option
+            return sharedError(Err::optionMissing(CmdlineOpt::ListPolicies));
+        }
+    }
+
+    return std::make_shared<ListPoliciesCyadCommand>(bucketId,
+                                                     PolicyKey(values[CmdlineOpt::Client],
+                                                               values[CmdlineOpt::User],
+                                                               values[CmdlineOpt::Privilege]));
+}
+
 } /* namespace Cynara */
index b29e428..0b86e5d 100644 (file)
@@ -43,6 +43,7 @@ protected:
     std::shared_ptr<CyadCommand> parseSetPolicy(void);
     std::shared_ptr<CyadCommand> parseErase(const std::string &bucketId);
     std::shared_ptr<CyadCommand> parseCheck(void);
+    std::shared_ptr<CyadCommand> parseListPolicies(const std::string &bucketId);
 
 private:
     int m_argc;
index 43abd35..2be90c5 100644 (file)
@@ -20,6 +20,7 @@
  * @brief       CommandsDispatcher class (implementation)
  */
 
+#include <cynara-admin-types.h>
 #include <cynara-error.h>
 #include <cynara-policy-types.h>
 
@@ -137,4 +138,51 @@ int CommandsDispatcher::execute(CheckCyadCommand &command) {
     return ret;
 }
 
+int CommandsDispatcher::execute(ListPoliciesCyadCommand &command) {
+    const auto &key = command.policyKey();
+    auto client = key.client().toString().c_str();
+    auto user = key.user().toString().c_str();
+    auto privilege = key.privilege().toString().c_str();
+
+    // Initialization is needed to make compiler happy (-Werror=maybe-uninitialized, FTW)
+    cynara_admin_policy **policies = nullptr;
+
+    auto ret = m_adminApiWrapper.cynara_admin_list_policies(m_cynaraAdmin,
+                                                            command.bucketId().c_str(),
+                                                            client, user, privilege,
+                                                            &policies);
+
+    auto printPolicy = [this] (cynara_admin_policy *p) {
+        m_io.cout() << p->bucket << ";"
+                    << p->client << ";"
+                    << p->user << ";"
+                    << p->privilege << ";"
+                    << p->result << ";";
+        if (p->result_extra != nullptr) {
+            m_io.cout() << p->result_extra;
+        }
+        m_io.cout() << std::endl;
+    };
+
+    auto freePolicy = [] (cynara_admin_policy *p) {
+        free(p->bucket);
+        free(p->client);
+        free(p->user);
+        free(p->privilege);
+        free(p->result_extra);
+        free(p);
+    };
+
+    if (ret == CYNARA_API_SUCCESS) {
+        for (int i = 0; policies[i]; ++i) {
+            auto p = policies[i];
+            printPolicy(p);
+            freePolicy(p);
+        }
+        free(policies);
+    }
+
+    return ret;
+}
+
 } /* namespace Cynara */
index d680c1d..396bbe6 100644 (file)
@@ -46,6 +46,7 @@ public:
     virtual int execute(SetPolicyBulkCyadCommand &);
     virtual int execute(EraseCyadCommand &);
     virtual int execute(CheckCyadCommand &);
+    virtual int execute(ListPoliciesCyadCommand &);
 
 private:
     BaseDispatcherIO &m_io;
index 4d83014..cf564dc 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <algorithm>
 #include <cstring>
+#include <functional>
+#include <memory>
 #include <new>
 #include <stdexcept>
 #include <string>
@@ -94,4 +96,66 @@ cynara_admin_policy* const *CynaraAdminPolicies::data(void) const {
     return m_policies.data();
 }
 
+cynara_admin_policy **CynaraAdminPolicies::duplicate(void) const {
+    if (sealed() == false) {
+        throw std::logic_error("Collection is not sealed");
+    }
+
+    auto freePolicies = [this] (cynara_admin_policy **policies) {
+        for (auto i = 0u; i < m_policies.size() - 1; ++i) {
+            auto p = policies[i];
+            ::free(p->bucket);
+            ::free(p->client);
+            ::free(p->user);
+            ::free(p->privilege);
+            ::free(p->result_extra);
+            ::free(p);
+        }
+        free(policies);
+    };
+
+    auto dup = static_cast<cynara_admin_policy **>(calloc(m_policies.size(),
+                                                   sizeof(cynara_admin_policy *)));
+
+    if (dup == nullptr)
+        throw std::bad_alloc();
+
+    std::unique_ptr<cynara_admin_policy *, decltype(freePolicies)> dupPtr(dup, freePolicies);
+
+    for (auto i = 0u; i < m_policies.size() - 1; ++i) {
+        dup[i] = static_cast<cynara_admin_policy *>(calloc(1, sizeof(cynara_admin_policy)));
+
+        if (dup[i] == nullptr)
+            throw std::bad_alloc();
+
+        dup[i]->bucket = strdup(m_policies.at(i)->bucket);
+        if (dup[i]->bucket == nullptr)
+            throw std::bad_alloc();
+
+        dup[i]->client = strdup(m_policies.at(i)->client);
+        if (dup[i]->client == nullptr)
+            throw std::bad_alloc();
+
+        dup[i]->user = strdup(m_policies.at(i)->user);
+        if (dup[i]->user == nullptr)
+            throw std::bad_alloc();
+
+        dup[i]->privilege = strdup(m_policies.at(i)->privilege);
+        if (dup[i]->privilege == nullptr)
+            throw std::bad_alloc();
+
+        dup[i]->result = m_policies.at(i)->result;
+
+        if (m_policies.at(i)->result_extra) {
+            dup[i]->result_extra = strdup(m_policies.at(i)->result_extra);
+            if (dup[i]->result_extra == nullptr)
+                throw std::bad_alloc();
+        } else
+            dup[i]->result_extra = nullptr;
+    }
+
+    dup[m_policies.size() - 1] = nullptr;
+    return dupPtr.release();
+}
+
 } /* namespace Cynara */
index 8541783..dfb2956 100644 (file)
@@ -45,6 +45,7 @@ public:
     void seal(void);
 
     cynara_admin_policy* const *data(void) const;
+    cynara_admin_policy **duplicate(void) const;
 
     bool sealed(void) const {
         return m_sealed;
index 533b7a4..3dc3d4b 100644 (file)
@@ -46,6 +46,10 @@ public:
                  int(struct cynara_admin *p_cynara_admin, const char *start_bucket,
                      const int recursive, const char *client, const char *user,
                      const char *privilege, int *result, char **result_extra));
+    MOCK_METHOD6(cynara_admin_list_policies,
+                 int(struct cynara_admin *p_cynara_admin, const char *bucket, const char *client,
+                     const char *user, const char *privilege,
+                     struct cynara_admin_policy ***policies));
     MOCK_METHOD6(cynara_admin_erase,
                  int(struct cynara_admin *p_cynara_admin, const char *start_bucket, int recursive,
                      const char *client, const char *user, const char *privilege));
index 3a6b2fd..af503eb 100644 (file)
@@ -220,3 +220,25 @@ TEST_F(CyadCommandlineTest, checkDefaultRecursive) {
     ASSERT_FALSE(result->recursive());
     ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey());
 }
+
+TEST_F(CyadCommandlineTest, listPoliciesDefault) {
+    prepare_argv({ "./cyad", "--list-policies=",
+                   "--client=client", "--user=user", "--privilege=privilege" });
+    Cynara::CyadCommandlineParser parser(this->argc(), this->argv());
+
+    auto result = std::dynamic_pointer_cast<Cynara::ListPoliciesCyadCommand>(parser.parseMain());
+    ASSERT_NE(nullptr, result);
+    ASSERT_EQ(CYNARA_ADMIN_DEFAULT_BUCKET, result->bucketId());
+    ASSERT_EQ(Cynara::PolicyKey("client", "user", "privilege"), result->policyKey());
+}
+
+TEST_F(CyadCommandlineTest, listPoliciesOtherBucket) {
+    prepare_argv({ "./cyad", "--list-policies=some-bucket",
+                   "--client=c", "--user=u", "--privilege=p" });
+    Cynara::CyadCommandlineParser parser(this->argc(), this->argv());
+
+    auto result = std::dynamic_pointer_cast<Cynara::ListPoliciesCyadCommand>(parser.parseMain());
+    ASSERT_NE(nullptr, result);
+    ASSERT_EQ("some-bucket", result->bucketId());
+    ASSERT_EQ(Cynara::PolicyKey("c", "u", "p"), result->policyKey());
+}
index 049851a..7c56ab5 100644 (file)
@@ -128,3 +128,11 @@ TEST_F(CyadCommandlineTest, eraseNoRecursive) {
     Cynara::CyadCommandlineParser parser(this->argc(), this->argv());
     ASSERT_ERROR_MSG(Errors::optionMissing(CmdlineOpt::Erase), parser.parseMain());
 }
+
+// Error should be argument missing, but getopt acts weird
+TEST_F(CyadCommandlineTest, listPoliciesNoBucket) {
+    prepare_argv({ "./cyad", "--list-policies",
+                   "--client=client", "--user=user", "--privilege=privilege" });
+    Cynara::CyadCommandlineParser parser(this->argc(), this->argv());
+    ASSERT_ERROR_MSG(Errors::optionMissing(CmdlineOpt::ListPolicies), parser.parseMain());
+}
index 42f893a..0dca2f5 100644 (file)
@@ -30,13 +30,14 @@ TEST(CommandlineOptions, allOptionsPresent) {
     using Cynara::CmdlineOpts::commandlineOptions;
 
     // A cheap trick to make sure this test is updated, when new options are added
-    ASSERT_EQ(14, commandlineOptions.size());
+    ASSERT_EQ(15, commandlineOptions.size());
 
     ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::SetBucket));
     ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::DeleteBucket));
     ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::SetPolicy));
     ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::Erase));
     ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::Check));
+    ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::ListPolicies));
 
     ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::Type));
     ASSERT_NO_THROW(commandlineOptions.at(CmdlineOpt::Metadata));
index 6a8bcec..e962312 100644 (file)
@@ -27,6 +27,7 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <cynara-admin-types.h>
 #include <cynara-error.h>
 #include <cynara-policy-types.h>
 
@@ -331,3 +332,66 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithError) {
 
     ASSERT_TRUE(m_io.coutRaw().str().empty());
 }
+
+TEST_F(CyadCommandlineDispatcherTest, listPoliciesNone) {
+    using ::testing::_;
+    using ::testing::DoAll;
+    using ::testing::NotNull;
+    using ::testing::Return;
+    using ::testing::SetArgPointee;
+    using ::testing::StrEq;
+
+    FakeAdminApiWrapper adminApi;
+
+    EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
+    EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
+
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+
+    Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" });
+
+    Cynara::CynaraAdminPolicies resultPolicies;
+    resultPolicies.seal();
+    auto policies = resultPolicies.duplicate();
+
+    EXPECT_CALL(adminApi, cynara_admin_list_policies(_, StrEq(""), StrEq("client"), StrEq("user"),
+                                                     StrEq("privilege"), NotNull()))
+        .WillOnce(DoAll(SetArgPointee<5>(policies), Return(CYNARA_API_SUCCESS)));
+
+    dispatcher.execute(command);
+
+    ASSERT_EQ("", m_io.coutRaw().str());
+}
+
+TEST_F(CyadCommandlineDispatcherTest, listPoliciesTwo) {
+    using ::testing::_;
+    using ::testing::DoAll;
+    using ::testing::NotNull;
+    using ::testing::Return;
+    using ::testing::SetArgPointee;
+    using ::testing::StrEq;
+
+    FakeAdminApiWrapper adminApi;
+
+    EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
+    EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
+
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+
+    Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" });
+
+    Cynara::CynaraAdminPolicies resultPolicies;
+    resultPolicies.add("bucket", { CYNARA_ADMIN_DENY, "metadata" }, {"cli", "usr", "privilege"} );
+    resultPolicies.add("bucket-2", { CYNARA_ADMIN_ALLOW, "" }, {"cli", "usr", "privilege"} );
+    resultPolicies.seal();
+    auto policies = resultPolicies.duplicate();
+
+    EXPECT_CALL(adminApi, cynara_admin_list_policies(_, StrEq(""), StrEq("client"), StrEq("user"),
+                                                     StrEq("privilege"), NotNull()))
+        .WillOnce(DoAll(SetArgPointee<5>(policies), Return(CYNARA_API_SUCCESS)));
+
+    dispatcher.execute(command);
+
+    ASSERT_EQ("bucket;cli;usr;privilege;0;metadata\nbucket-2;cli;usr;privilege;65535;\n",
+              m_io.coutRaw().str());
+}