Create role mapping under ldap config object

Each ldap config object should be have its own
mapping object.

This is to align with the redfish.
https://redfish.dmtf.org/schemas/AccountService.v1_4_0.json

As per redfish, Each config will have it's own
"RemoteRoleMapping".

Mapping object should be persisted and restores
when the phosphor-ldap-conf restarts.

TestedBy:
          Unit Tested.
          Creation of privilege mapping.
          Persist the priv-mapping.
          Restores the priv-mapping.

Signed-off-by: Ratan Gupta <ratagupt@linux.vnet.ibm.com>
Change-Id: I5ab4aeffae61f9cc57c1338f94784d0fe5607cd3
diff --git a/phosphor-ldap-config/ldap_config.cpp b/phosphor-ldap-config/ldap_config.cpp
index 03c6ffc..b22d684 100644
--- a/phosphor-ldap-config/ldap_config.cpp
+++ b/phosphor-ldap-config/ldap_config.cpp
@@ -5,6 +5,10 @@
 #include <cereal/types/string.hpp>
 #include <cereal/types/vector.hpp>
 #include <cereal/archives/binary.hpp>
+#include "ldap_mapper_serialize.hpp"
+
+#include <xyz/openbmc_project/Common/error.hpp>
+#include <xyz/openbmc_project/User/Common/error.hpp>
 #include <filesystem>
 #include <fstream>
 #include <sstream>
@@ -27,9 +31,12 @@
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 namespace fs = std::filesystem;
+
 using Argument = xyz::openbmc_project::Common::InvalidArgument;
 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
 using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
+using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
+    Error::PrivilegeMappingExists;
 
 using Line = std::string;
 using Key = std::string;
@@ -625,5 +632,114 @@
     }
 }
 
+ObjectPath Config::create(std::string groupName, std::string privilege)
+{
+    checkPrivilegeMapper(groupName);
+    checkPrivilegeLevel(privilege);
+
+    entryId++;
+
+    // Object path for the LDAP group privilege mapper entry
+    fs::path mapperObjectPath = objectPath;
+    mapperObjectPath /= "role_map";
+    mapperObjectPath /= std::to_string(entryId);
+
+    fs::path persistPath = parent.dbusPersistentPath;
+    persistPath += mapperObjectPath;
+
+    // Create mapping for LDAP privilege mapper entry
+    auto entry = std::make_unique<LDAPMapperEntry>(
+        bus, mapperObjectPath.string().c_str(), persistPath.string().c_str(),
+        groupName, privilege, *this);
+
+    phosphor::ldap::serialize(*entry, std::move(persistPath));
+
+    PrivilegeMapperList.emplace(entryId, std::move(entry));
+    return mapperObjectPath.string();
+}
+
+void Config::deletePrivilegeMapper(Id id)
+{
+    fs::path mapperObjectPath = objectPath;
+    mapperObjectPath /= "role_map";
+    mapperObjectPath /= std::to_string(id);
+
+    fs::path persistPath = parent.dbusPersistentPath;
+    persistPath += std::move(mapperObjectPath);
+
+    // Delete the persistent representation of the privilege mapper.
+    fs::remove(std::move(persistPath));
+
+    PrivilegeMapperList.erase(id);
+}
+void Config::checkPrivilegeMapper(const std::string& groupName)
+{
+    if (groupName.empty())
+    {
+        log<level::ERR>("Group name is empty");
+        elog<InvalidArgument>(Argument::ARGUMENT_NAME("Group name"),
+                              Argument::ARGUMENT_VALUE("Null"));
+    }
+
+    for (const auto& val : PrivilegeMapperList)
+    {
+        if (val.second.get()->groupName() == groupName)
+        {
+            log<level::ERR>("Group name already exists");
+            elog<PrivilegeMappingExists>();
+        }
+    }
+}
+
+void Config::checkPrivilegeLevel(const std::string& privilege)
+{
+    if (privilege.empty())
+    {
+        log<level::ERR>("Privilege level is empty");
+        elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
+                              Argument::ARGUMENT_VALUE("Null"));
+    }
+
+    if (std::find(privMgr.begin(), privMgr.end(), privilege) == privMgr.end())
+    {
+        log<level::ERR>("Invalid privilege");
+        elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
+                              Argument::ARGUMENT_VALUE(privilege.c_str()));
+    }
+}
+
+void Config::restoreRoleMapping()
+{
+    namespace fs = std::filesystem;
+    fs::path dir = parent.dbusPersistentPath;
+    dir += objectPath;
+    dir /= "role_map";
+
+    if (!fs::exists(dir) || fs::is_empty(dir))
+    {
+        return;
+    }
+
+    for (auto& file : fs::directory_iterator(dir))
+    {
+        std::string id = file.path().filename().c_str();
+        size_t idNum = std::stol(id);
+
+        auto entryPath = objectPath + '/' + "role_map" + '/' + id;
+        auto persistPath = parent.dbusPersistentPath + entryPath;
+        auto entry = std::make_unique<LDAPMapperEntry>(
+            bus, entryPath.c_str(), persistPath.c_str(), *this);
+        if (phosphor::ldap::deserialize(file.path(), *entry))
+        {
+            entry->Interfaces::emit_object_added();
+            PrivilegeMapperList.emplace(idNum, std::move(entry));
+            if (idNum > entryId)
+            {
+                entryId = idNum;
+            }
+        }
+    }
+}
+
 } // namespace ldap
 } // namespace phosphor