Add activation property to policy-admin
authorSangwan Kwon <sangwan.kwon@samsung.com>
Mon, 2 Dec 2019 08:53:23 +0000 (17:53 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Thu, 12 Dec 2019 10:16:10 +0000 (19:16 +0900)
vist-policy has activated state when any of policy-admins are activated.

Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
13 files changed:
data/script/create-schema.sql
src/vist/common/archive.cpp
src/vist/event/mainloop.cpp
src/vist/event/mainloop.hpp
src/vist/policy/api.cpp
src/vist/policy/api.hpp
src/vist/policy/db-schema.hpp
src/vist/policy/policy-manager.cpp
src/vist/policy/policy-manager.hpp
src/vist/policy/policy-storage.cpp
src/vist/policy/policy-storage.hpp
src/vist/policy/tests/core.cpp
src/vist/policy/tests/storage.cpp

index 010eaff6d342664b3b6751e59b2181c73321df3a..69344a49883fd6d513327693f45a9ad289dbf407 100644 (file)
@@ -16,6 +16,7 @@
 
 CREATE TABLE IF NOT EXISTS ADMIN (
        name TEXT NOT NULL,
+       activated INTEGER NOT NULL,
 
        PRIMARY KEY(name)
 );
@@ -27,7 +28,7 @@ CREATE TABLE IF NOT EXISTS POLICY_DEFINITION (
        PRIMARY KEY(name)
 );
 
-CREATE TABLE IF NOT EXISTS POLICY_ACTIVATED (
+CREATE TABLE IF NOT EXISTS POLICY_MANAGED (
        admin TEXT NOT NULL,
        policy TEXT NOT NULL,
        value TEXT NOT NULL,
@@ -40,7 +41,7 @@ CREATE TABLE IF NOT EXISTS POLICY_ACTIVATED (
 CREATE TRIGGER IF NOT EXISTS ACTIVATE AFTER INSERT ON ADMIN
 FOR EACH ROW
 BEGIN
-       INSERT INTO POLICY_ACTIVATED(admin, policy, value)
+       INSERT INTO POLICY_MANAGED(admin, policy, value)
                SELECT NEW.name, POLICY_DEFINITION.name, POLICY_DEFINITION.ivalue
                FROM POLICY_DEFINITION;
 END;
@@ -48,5 +49,5 @@ END;
 CREATE TRIGGER IF NOT EXISTS DEACTIVATE AFTER DELETE ON ADMIN
 FOR EACH ROW
 BEGIN
-       DELETE FROM POLICY_ACTIVATED WHERE POLICY_ACTIVATED.admin = OLD.name;
+       DELETE FROM POLICY_MANAGED WHERE POLICY_MANAGED.admin = OLD.name;
 END;
index 23b98e9b1179a9bcc93fda080645cac932e2be28..f7e7e5ce975f35a6ac027607b7034e90ee254436 100644 (file)
@@ -27,6 +27,8 @@ Archive& Archive::operator<<(const Archive& archive)
        auto data = archive.buffer;
        auto index = archive.current;
        std::copy(data.begin() + index, data.end(), std::back_inserter(this->buffer));
+
+       return *this;
 }
 
 Archive& Archive::operator<<(const std::string& value)
@@ -43,6 +45,8 @@ Archive& Archive::operator>>(Archive& archive)
        auto data = this->buffer;
        auto index = this->current;
        std::copy(data.begin() + index, data.end(), std::back_inserter(archive.buffer));
+
+       return *this;
 }
 
 Archive& Archive::operator>>(std::string& value)
index 4e721045cb50f26991db31ef91c92c3691d5cb34..f7e335b5755d50441f95af18fac6e03f50446900 100644 (file)
@@ -82,7 +82,7 @@ void Mainloop::removeHandler(const int fd)
        ::epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, NULL);
 }
 
-bool Mainloop::prepare(void)
+void Mainloop::prepare(void)
 {
        auto wakeup = [this]() {
                this->wakeupSignal.receive();
index 6e2f1cab47cf72146cb4a00c79a7f89c2a8c4ac5..c42ab242a5f815b071d398d18860de536c48818e 100644 (file)
@@ -64,7 +64,7 @@ private:
        using Handler = std::pair<std::shared_ptr<OnEvent>, std::shared_ptr<OnError>>;
        using Listener = std::unordered_map<int, Handler>;
 
-       bool prepare(void);
+       void prepare(void);
 
        bool dispatch(const int timeout) noexcept;
 
index 0a38eb5213eb530d58c172b34d26463ec8bf65e7..3c99d067a033158d5dadd56284f26e7cf6f87b8e 100644 (file)
@@ -47,6 +47,11 @@ void API::Admin::Disenroll(const std::string& admin)
        PolicyManager::Instance().disenroll(admin);
 }
 
+void API::Admin::Activate(const std::string& admin, bool state)
+{
+       PolicyManager::Instance().activate(admin, state);
+}
+
 std::vector<std::string> API::Admin::GetAll()
 {
        return PolicyManager::Instance().getAdmins();
index 6c15af82cf5e57eb1e3983fa1c2daf59ec926319..d5059bb4d7f2208016c25b9cfcec7e3196f41cae 100644 (file)
@@ -35,6 +35,8 @@ struct API {
                static void Enroll(const std::string& admin);
                static void Disenroll(const std::string& admin);
 
+               static void Activate(const std::string& admin, bool state = true);
+
                static std::vector<std::string> GetAll();
        };
 };
index 2ae1eaf3ee6010d33c649a13e0afc00ff667a953..77fa84dae4747f76eb9059e26dd9417f2f923cb5 100644 (file)
@@ -24,9 +24,10 @@ namespace schema {
 
 struct Admin {
        std::string name;
+       int activated = -1;
 };
 
-struct PolicyActivated {
+struct PolicyManaged {
        std::string admin;
        std::string policy;
        std::string value;
index 9d25929c0cadafc98f314be68bf332176264708d..06d7b7454ae97d93818c157f33591d0339ab22f3 100644 (file)
@@ -103,6 +103,11 @@ void PolicyManager::disenroll(const std::string& admin)
        this->storage.disenroll(admin);
 }
 
+void PolicyManager::activate(const std::string& admin, bool state)
+{
+       this->storage.activate(admin, state);
+}
+
 void PolicyManager::set(const std::string& policy,
                                                const PolicyValue& value,
                                                const std::string& admin)
index b0bacc2ef29dbfb25b09e10974f6fd440ec4b4a8..c93ba7374bd144f7c05bbebf790ae87b0e3b1100 100644 (file)
@@ -48,6 +48,8 @@ public:
        void enroll(const std::string& admin);
        void disenroll(const std::string& admin);
 
+       void activate(const std::string& admin, bool state);
+
        void set(const std::string& policy,
                         const PolicyValue& value,
                         const std::string& admin);
index 28b4c55f26ae4d2b1b47131a533dfc51dc165cfe..a0131d56dd3f21fe18f54c58b6a378aeb085e179 100644 (file)
@@ -30,12 +30,13 @@ using namespace vist::policy::schema;
 
 namespace {
 
-auto adminTable = make_table("ADMIN", make_column("name", &Admin::name));
+auto adminTable = make_table("ADMIN", make_column("name", &Admin::name),
+                                                                         make_column("activated", &Admin::activated));
 
-auto polActivatedTable = make_table("POLICY_ACTIVATED",
-                                                                       make_column("admin", &PolicyActivated::admin),
-                                                                       make_column("policy", &PolicyActivated::policy),
-                                                                       make_column("value", &PolicyActivated::value));
+auto polManagedTable = make_table("POLICY_MANAGED",
+                                                                       make_column("admin", &PolicyManaged::admin),
+                                                                       make_column("policy", &PolicyManaged::policy),
+                                                                       make_column("value", &PolicyManaged::value));
 
 auto polDefinitionTable = make_table("POLICY_DEFINITION",
                                                                         make_column("name", &PolicyDefinition::name),
@@ -62,7 +63,7 @@ void PolicyStorage::sync()
 {
        DEBUG(VIST) << "Sync policy storage to cache object.";
        syncAdmin();
-       syncPolicyActivated();
+       syncPolicyManaged();
        syncPolicyDefinition();
 }
 
@@ -73,9 +74,7 @@ void PolicyStorage::syncPolicyDefinition()
        database::Statement stmt(*database, query);
 
        while (stmt.step()) {
-               PolicyDefinition pd;
-               pd.name = std::string(stmt.getColumn(0));
-               pd.ivalue = std::string(stmt.getColumn(1));
+               PolicyDefinition pd = { std::string(stmt.getColumn(0)), std::string(stmt.getColumn(1)) };
                DEBUG(VIST) << "Defined policy:" << pd.name;
                this->definitions.emplace(pd.name, std::move(pd));
        }
@@ -89,27 +88,29 @@ void PolicyStorage::syncAdmin()
        std::string query = adminTable.selectAll();
        database::Statement stmt(*database, query);
 
-       while (stmt.step())
-               this->admins.emplace_back(std::string(stmt.getColumn(0)));
+       while (stmt.step()) {
+               Admin admin = { std::string(stmt.getColumn(0)), stmt.getColumn(1).getInt() };
+               this->admins.emplace(admin.name, std::move(admin));
+       }
 
        DEBUG(VIST) << admins.size() << "-admins synced.";
 }
 
-void PolicyStorage::syncPolicyActivated()
+void PolicyStorage::syncPolicyManaged()
 {
-       this->activatedPolicies.clear();
-       std::string query = polActivatedTable.selectAll();
+       this->managedPolicies.clear();
+       std::string query = polManagedTable.selectAll();
        database::Statement stmt(*database, query);
 
        while (stmt.step()) {
-               PolicyActivated pa;
+               PolicyManaged pa;
                pa.admin = std::string(stmt.getColumn(0));
                pa.policy = std::string(stmt.getColumn(1));
                pa.value = std::string(stmt.getColumn(2));
-               this->activatedPolicies.emplace(pa.policy, std::move(pa));
+               this->managedPolicies.emplace(pa.policy, std::move(pa));
        }
 
-       DEBUG(VIST) << activatedPolicies.size() << "-activated-policies synced.";
+       DEBUG(VIST) << managedPolicies.size() << "-managed-policies synced.";
 }
 
 std::string PolicyStorage::getScript(const std::string& name)
@@ -134,9 +135,7 @@ void PolicyStorage::define(const std::string& policy, const PolicyValue& ivalue)
                return;
        }
 
-       PolicyDefinition pd;
-       pd.name = policy;
-       pd.ivalue = ivalue.dump();
+       PolicyDefinition pd = { policy, ivalue.dump() };
 
        std::string query = polDefinitionTable.insert(&PolicyDefinition::name,
                                                                                                  &PolicyDefinition::ivalue);
@@ -153,22 +152,27 @@ void PolicyStorage::define(const std::string& policy, const PolicyValue& ivalue)
 void PolicyStorage::enroll(const std::string& name)
 {
        INFO(VIST) << "Enroll admin: " << name;
-       if (std::find(admins.begin(), admins.end(), name) != admins.end()) {
-               ERROR(VIST) << "Admin is aleady enrolled.: " << name;
+       if (this->admins.find(name) != this->admins.end()) {
+               WARN(VIST) << "Admin is already enrolled.: " << name;
                return;
        }
 
-       std::string query = adminTable.insert(&Admin::name);
+       /// Make admin deactivated as default.
+       Admin admin = {name , 0};
+
+       std::string query = adminTable.insert(&Admin::name, &Admin::activated);
        database::Statement stmt(*database, query);
-       stmt.bind(1, name);
+       stmt.bind(1, admin.name);
+       stmt.bind(2, admin.activated);
        if (!stmt.exec())
                THROW(ErrCode::RuntimeError) << "Failed to enroll admin: " << name;
 
-       admins.push_back(name);
-       /// PolicyActivated is triggered by enrolling admin.
-       syncPolicyActivated();
+       this->admins.emplace(admin.name, std::move(admin));
+
+       /// PolicyManaged is triggered by enrolling admin.
+       syncPolicyManaged();
 
-       int count = activatedPolicies.size() / admins.size();
+       int count = this->managedPolicies.size() / this->admins.size();
        INFO(VIST) << "Admin[" << name << "] manages "
                           << std::to_string(count) << "-policies.";
 }
@@ -179,12 +183,11 @@ void PolicyStorage::disenroll(const std::string& name)
                THROW(ErrCode::RuntimeError) << "Cannot disenroll default admin.";
 
        INFO(VIST) << "Disenroll admin: " << name;
-       auto iter = std::find(admins.begin(), admins.end(), name);
-       if (iter == admins.end()) {
+       if (this->admins.find(name) == this->admins.end()) {
                ERROR(VIST) << "Not exist admin: " << name;
                return;
        } else {
-               admins.erase(iter);
+               this->admins.erase(name);
        }
 
        std::string query = adminTable.remove().where(expr(&Admin::name) == name);
@@ -192,6 +195,33 @@ void PolicyStorage::disenroll(const std::string& name)
        stmt.bind(1, name);
        if (!stmt.exec())
                THROW(ErrCode::RuntimeError) << "Failed to disenroll admin: " << name;
+
+       /// TODO: add TC
+       this->syncPolicyManaged();
+}
+
+void PolicyStorage::activate(const std::string& admin, bool state)
+{
+       if (this->admins.find(admin) == this->admins.end())
+               THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
+
+       std::string query = adminTable.update(&Admin::activated)
+                                                                                .where(expr(&Admin::name) == admin);
+       database::Statement stmt(*this->database, query);
+       stmt.bind(1, static_cast<int>(state));
+       stmt.bind(2, admin);
+       if (!stmt.exec())
+               THROW(ErrCode::RuntimeError) << "Failed to activate admin: " << admin;
+
+       this->admins[admin].activated = state;
+}
+
+bool PolicyStorage::isActivated(const std::string& admin)
+{
+       if (this->admins.find(admin) == this->admins.end())
+               THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
+
+       return this->admins[admin].activated;
 }
 
 void PolicyStorage::update(const std::string& admin,
@@ -201,15 +231,15 @@ void PolicyStorage::update(const std::string& admin,
        DEBUG(VIST) << "Policy-update is called by admin: " << admin
                                << ", about: " << policy << ", value: " << value.dump();
 
-       if (std::find(this->admins.begin(), this->admins.end(), admin) == this->admins.end())
+       if (this->admins.find(admin) == this->admins.end())
                THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
 
        if (this->definitions.find(policy) == this->definitions.end())
                THROW(ErrCode::LogicError) << "Not exist policy: " << policy;
 
-       std::string query = polActivatedTable.update(&PolicyActivated::value)
-                                                                                .where(expr(&PolicyActivated::admin) == admin &&
-                                                                                 expr(&PolicyActivated::policy) == policy);
+       std::string query = polManagedTable.update(&PolicyManaged::value)
+                                                                          .where(expr(&PolicyManaged::admin) == admin &&
+                                                                           expr(&PolicyManaged::policy) == policy);
        database::Statement stmt(*this->database, query);
        stmt.bind(1, value.dump());
        stmt.bind(2, admin);
@@ -218,7 +248,7 @@ void PolicyStorage::update(const std::string& admin,
                THROW(ErrCode::RuntimeError) << "Failed to update policy:" << policy;
 
        /// TODO: Fix to sync without db i/o
-       this->syncPolicyActivated();
+       this->syncPolicyManaged();
 }
 
 PolicyValue PolicyStorage::strictest(const std::shared_ptr<PolicyModel>& policy)
@@ -226,13 +256,13 @@ PolicyValue PolicyStorage::strictest(const std::shared_ptr<PolicyModel>& policy)
        if (this->definitions.find(policy->getName()) == this->definitions.end())
                THROW(ErrCode::LogicError) << "Not exist policy: " << policy->getName();
 
-       if (this->activatedPolicies.size() == 0) {
+       if (this->managedPolicies.size() == 0) {
                INFO(VIST) << "There is no enrolled admin. Return policy initial value.";
                return policy->getInitial();
        }
 
        std::shared_ptr<PolicyValue> strictestPtr = nullptr;
-       auto range = activatedPolicies.equal_range(policy->getName());
+       auto range = managedPolicies.equal_range(policy->getName());
        for (auto iter = range.first; iter != range.second; iter++) {
                DEBUG(VIST) << "Admin: " << iter->second.admin << ", "
                                        << "Policy: " << iter->second.policy  << ", "
@@ -255,9 +285,13 @@ PolicyValue PolicyStorage::strictest(const std::shared_ptr<PolicyModel>& policy)
        return std::move(*strictestPtr);
 }
 
-const std::vector<std::string>& PolicyStorage::getAdmins() const noexcept
+std::vector<std::string> PolicyStorage::getAdmins() const noexcept
 {
-       return admins;
+       std::vector<std::string> tmp;
+       for (const auto& admin : this->admins)
+               tmp.push_back(admin.first);
+
+       return tmp;
 }
 
 } // namespace policy
index 9022f11e1d0520d11a8490e40669101c9dfc6a1b..540694a45f1e4dcc6d58edc051a70ea9bea4a29f 100644 (file)
@@ -40,7 +40,7 @@ public:
        void sync();
 
        void syncAdmin();
-       void syncPolicyActivated();
+       void syncPolicyManaged();
        void syncPolicyDefinition();
 
        inline bool exists(const std::string& policy) const noexcept
@@ -48,13 +48,10 @@ public:
                return definitions.find(policy) != definitions.end();
        }
 
-       inline bool isActivated() const noexcept
-       {
-               return admins.size() > 0 && activatedPolicies.size() > 0;
-       }
-
        void enroll(const std::string& admin);
        void disenroll(const std::string& admin);
+       void activate(const std::string& admin, bool state = true);
+       bool isActivated(const std::string& admin);
 
        void define(const std::string& policy, const PolicyValue& ivalue);
        void update(const std::string& admin,
@@ -63,7 +60,7 @@ public:
 
        PolicyValue strictest(const std::shared_ptr<PolicyModel>& policy);
 
-       const std::vector<std::string>& getAdmins() const noexcept;
+       std::vector<std::string> getAdmins() const noexcept;
 
 private:
        std::string getScript(const std::string& name);
@@ -72,8 +69,8 @@ private:
 
        /// DB Cache objects
        /// TODO(Sangwan): add locking mechanism
-       std::vector<std::string> admins;
-       std::unordered_multimap<std::string, PolicyActivated> activatedPolicies;
+       std::unordered_map<std::string, Admin> admins;
+       std::unordered_multimap<std::string, PolicyManaged> managedPolicies;
        std::unordered_map<std::string, PolicyDefinition> definitions;
 };
 
index de0840e4da906f4307ff504c165e0e7bbbfb8781..e8a2c373164b3a709d35f15444f2b4dabde3456a 100644 (file)
@@ -87,5 +87,27 @@ TEST(PolicyCoreTests, policy_get_policy) {
        EXPECT_TRUE(raised);
 }
 
+TEST(PolicyCoreTests, admin) {
+       auto& manager = PolicyManager::Instance();
+       manager.enroll("testAdmin");
+
+       try {
+               manager.activate("testAdmin", true);
+               manager.activate("testAdmin", false);
+       } catch (const vist::Exception<ErrCode>& e) {
+               EXPECT_TRUE(false) << e.what();
+       }
+
+       bool raised = false;
+       try {
+               manager.activate("fakeAdmin", true);
+       } catch (const vist::Exception<ErrCode>&) {
+               raised = true;
+       }
+       EXPECT_TRUE(raised);
+
+       manager.disenroll("testAdmin");
+}
+
 } // namespace policy
 } // namespace vist
index 100c006f7ec395a278fdb4b0004d19c823248d5b..793c11213922e66389999e7da6b21fbac470bd80 100644 (file)
@@ -52,23 +52,6 @@ TEST_F(PolicyStorageTests, initialize)
        EXPECT_FALSE(isRaised);
 }
 
-TEST_F(PolicyStorageTests, enrollment)
-{
-       auto storage = getStorage();
-       /// Since default admin exists, storage is always activated.
-       EXPECT_TRUE(storage->isActivated());
-
-       storage->enroll("testAdmin0");
-       storage->enroll("testAdmin1");
-       EXPECT_TRUE(storage->isActivated());
-
-       storage->disenroll("testAdmin0");
-       EXPECT_TRUE(storage->isActivated());
-
-       storage->disenroll("testAdmin1");
-       EXPECT_TRUE(storage->isActivated());
-}
-
 TEST_F(PolicyStorageTests, update)
 {
        auto storage = getStorage();
@@ -138,3 +121,38 @@ TEST_F(PolicyStorageTests, default_admin)
 
        EXPECT_TRUE(isRaised);
 }
+
+TEST_F(PolicyStorageTests, activate)
+{
+       auto storage = getStorage();
+       EXPECT_FALSE(storage->isActivated(DEFAULT_ADMIN_PATH));
+
+       storage->activate(DEFAULT_ADMIN_PATH);
+       EXPECT_TRUE(storage->isActivated(DEFAULT_ADMIN_PATH));
+
+       storage->activate(DEFAULT_ADMIN_PATH, true);
+       EXPECT_TRUE(storage->isActivated(DEFAULT_ADMIN_PATH));
+
+       storage->activate(DEFAULT_ADMIN_PATH, false);
+       EXPECT_FALSE(storage->isActivated(DEFAULT_ADMIN_PATH));
+
+       storage->activate(DEFAULT_ADMIN_PATH);
+       EXPECT_TRUE(storage->isActivated(DEFAULT_ADMIN_PATH));
+
+       storage->activate(DEFAULT_ADMIN_PATH, false);
+}
+
+TEST_F(PolicyStorageTests, activate_failed)
+{
+       auto storage = getStorage();
+       bool isRaised = false;
+
+       try {
+               storage->activate("NOT_EXIST");
+       } catch (const std::exception& e) {
+               isRaised = true;
+       }
+
+       EXPECT_TRUE(isRaised);
+}
+