diff options
author | Nagaraju Goruganti <ngorugan@in.ibm.com> | 2019-01-31 14:24:27 +0300 |
---|---|---|
committer | Ed Tanous <ed.tanous@intel.com> | 2019-07-18 01:50:38 +0300 |
commit | 2a21b9db6fcfe477f9ef31453df93e3f6c442a44 (patch) | |
tree | 93f081a255f952526f1adcd3fc27afea24050e40 | |
parent | 54fc587a29317216a3b6660839a3dae6d21cbc1f (diff) | |
download | bmcweb-2a21b9db6fcfe477f9ef31453df93e3f6c442a44.tar.xz |
Redfish: Add PATCH operation support for RemoteRoleMapping
Added PATCH operation support for RemoteRoleMapping property under
LDAP/ActiveDirectory property in AccountService schema.
1. How to add the Role Mapping?
PATCH {"ActiveDirectory":{"RemoteRoleMapping": [{"RemoteGroup":
"Admingroup15","LocalRole": "User"},{"RemoteGroup": "Admingroup13",
"LocalRole": "Administrator"},{"RemoteGroup": "Admingroup14",
"LocalRole": "Operator"}]}}
With the above PATCH request, all the above role mapping gets added.
2. How to delete a specific role mapping?
After adding the above roles mapping, if user want to delete the second mapping
which is ({"RemoteGroup": "Admingroup13", "LocalRole": "Administrator"})
Following PATCH request would be used.
PATCH {"ActiveDirectory":{"RemoteRoleMapping": [{},null,{}]}}
3. How to update specific role mapping ?
Let's take a case where user want to update the second role mapping
PATCH {"ActiveDirectory":{"RemoteRoleMapping": [{},{"RemoteGroup":"Admingroup25","LocalRole": "User"},{}]}}
or
PATCH {"ActiveDirectory":{"RemoteRoleMapping": [{},{"RemoteGroup":"Admingroup25"},{}]}} and \
PATCH {"ActiveDirectory":{"RemoteRoleMapping": [{},{"LocalRole": "User"},{}]}}
Tested:
1. Did a PATCH operation with below given Data:
' {"ActiveDirectory":{"RemoteRoleMapping": [{"RemoteGroup": "Admingroup215","LocalRole": "User"}, \
{"RemoteGroup": "Admingroup213","LocalRole":"Administrator"},{"RemoteGroup":"Admingroup214","LocalRole":"Operator"}]}}'
2. With GET got below given data:
"RemoteRoleMapping": [
{
"LocalRole": "Operator",
"RemoteGroup": "Admingroup214"
},
{
"LocalRole": "Administrator",
"RemoteGroup": "Admingroup213"
},
{
"LocalRole": "User",
"RemoteGroup": "Admingroup215"
}
],
3. Did a PATCH operation with below given Data:
'{"ActiveDirectory":{"RemoteRoleMapping": [{},null,{}]}}'
4. With GET got below given data:
"RemoteRoleMapping": [
{
"LocalRole": "Operator",
"RemoteGroup": "Admingroup214"
},
{
"LocalRole": "User",
"RemoteGroup": "Admingroup215"
}
],
5. Did a PATCH operation with below given Data:
'{"ActiveDirectory":{"RemoteRoleMapping": [null,null]}}'
6. With GET got below given data:
"RemoteRoleMapping": []
7. Did a PATCH operation with below given Data:
'{"ActiveDirectory":{"RemoteRoleMapping": [{"RemoteGroup": "Admingroup215","LocalRole": "User"}, \
{"RemoteGroup": "Admingroup213","LocalRole":"Administrator"},{"RemoteGroup":"Admingroup214","LocalRole":"Operator"}]}}'
8. With GET got below given data:
"RemoteRoleMapping": [
{
"LocalRole": "Administrator",
"RemoteGroup": "Admingroup213"
},
{
"LocalRole": "Operator",
"RemoteGroup": "Admingroup214"
},
{
"LocalRole": "User",
"RemoteGroup": "Admingroup215"
}
],
9. Did a PATCH operation with below given Data:
'{"ActiveDirectory":{"RemoteRoleMapping": [{"RemoteGroup": "Admingroup25"},{},{}]}}'
10.With GET got below given data:
"RemoteRoleMapping": [
{
"LocalRole": "Administrator",
"RemoteGroup": "Admingroup25"
},
{
"LocalRole": "Operator",
"RemoteGroup": "Admingroup214"
},
{
"LocalRole": "User",
"RemoteGroup": "Admingroup215"
}
],
11. Did a PATCH operation with below given Data:
'{"ActiveDirectory":{"RemoteRoleMapping": [{"LocalRole": "User"},{},{}]}}'
12.With GET got below given data:
"RemoteRoleMapping": [
{
"LocalRole": "User",
"RemoteGroup": "Admingroup25"
},
{
"LocalRole": "Operator",
"RemoteGroup": "Admingroup214"
},
{
"LocalRole": "User",
"RemoteGroup": "Admingroup215"
}
],
13. Did a PATCH operation with below given Data:
'{"ActiveDirectory":{"RemoteRoleMapping": [{},{"RemoteGroup": "Admingroup26","LocalRole": "User"},{}]}}'
14.With GET got below given data:
"RemoteRoleMapping": [
{
"LocalRole": "User",
"RemoteGroup": "Admingroup25"
},
{
"LocalRole": "User",
"RemoteGroup": "Admingroup26"
},
{
"LocalRole": "User",
"RemoteGroup": "Admingroup215"
}
],
Change-Id: Idc80cee94b8b55d036c2514d50c147a72ed4c7f2
Signed-off-by: Ratan Gupta <ratagupt@linux.vnet.ibm.com>
Signed-off-by: Nagaraju Goruganti <ngorugan@in.ibm.com>
-rw-r--r-- | redfish-core/lib/account_service.hpp | 256 |
1 files changed, 252 insertions, 4 deletions
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp index 6cbbdce524..d4e1b38ea7 100644 --- a/redfish-core/lib/account_service.hpp +++ b/redfish-core/lib/account_service.hpp @@ -37,6 +37,8 @@ constexpr const char* ldapConfigInterface = constexpr const char* ldapCreateInterface = "xyz.openbmc_project.User.Ldap.Create"; constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; +constexpr const char* ldapPrivMapperInterface = + "xyz.openbmc_project.User.PrivilegeMapper"; constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties"; constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper"; @@ -149,6 +151,243 @@ void parseLDAPConfigData(nlohmann::json& json_response, } /** + * @brief deletes given RoleMapping Object. + */ +static void deleteRoleMappingObject(const std::shared_ptr<AsyncResp>& asyncResp, + const std::string& objPath, + const std::string& serverType, + unsigned int index) +{ + + BMCWEB_LOG_DEBUG << "deleteRoleMappingObject objPath =" << objPath; + + crow::connections::systemBus->async_method_call( + [asyncResp, serverType, index](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + messages::internalError(asyncResp->res); + return; + } + asyncResp->res.jsonValue[serverType]["RemoteRoleMapping"][index] = + nullptr; + }, + ldapDbusService, objPath, "xyz.openbmc_project.Object.Delete", + "Delete"); +} + +/** + * @brief sets RoleMapping Object's property with given value. + */ +static void setRoleMappingProperty( + const std::shared_ptr<AsyncResp>& asyncResp, const std::string& objPath, + const std::string& redfishProperty, const std::string& dbusProperty, + const std::string& value, const std::string& serverType, unsigned int index) +{ + BMCWEB_LOG_DEBUG << "setRoleMappingProperty objPath: " << objPath + << "value: " << value; + + // need to get the dbus privilege from the given refish role + std::string dbusVal = value; + if (redfishProperty == "LocalRole") + { + dbusVal = getPrivilegeFromRoleId(value); + } + + crow::connections::systemBus->async_method_call( + [asyncResp, serverType, index, redfishProperty, + value](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + messages::internalError(asyncResp->res); + return; + } + asyncResp->res.jsonValue[serverType]["RemoteRoleMapping"][index] + [redfishProperty] = value; + }, + ldapDbusService, objPath, "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.User.PrivilegeMapperEntry", + std::move(dbusProperty), std::variant<std::string>(std::move(dbusVal))); +} + +/** + * @brief validates given JSON input and then calls appropriate method to + * create, to delete or to set Rolemapping object based on the given input. + * + */ +static void handleRoleMapPatch( + const std::shared_ptr<AsyncResp>& asyncResp, + const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData, + const std::string& serverType, const nlohmann::json& input) +{ + if (!input.is_array()) + { + messages::propertyValueTypeError(asyncResp->res, input.dump(), + "RemoteRoleMapping"); + return; + } + + size_t index = 0; + for (const nlohmann::json& thisJson : input) + { + // Check that entry is not of some unexpected type + if (!thisJson.is_object() && !thisJson.is_null()) + { + messages::propertyValueTypeError(asyncResp->res, thisJson.dump(), + "RemoteGroup or LocalRole"); + index++; + continue; + } + BMCWEB_LOG_DEBUG << "JSON=" << thisJson << "\n"; + // delete the existing object + if (thisJson.is_null()) + { + if (input.size() <= roleMapObjData.size()) + { + deleteRoleMappingObject(asyncResp, + roleMapObjData.at(index).first, + serverType, index); + } + else + { + BMCWEB_LOG_ERROR << "Can't delete the object"; + messages::propertyValueTypeError( + asyncResp->res, thisJson.dump(), "RemoteRoleMapping"); + return; + } + + index++; + continue; + } + + if (thisJson.empty()) + { + if ((input.size() > roleMapObjData.size()) && + (index > roleMapObjData.size())) + { + BMCWEB_LOG_ERROR << "Empty object can't be inserted"; + messages::propertyValueTypeError( + asyncResp->res, thisJson.dump(), "RemoteRoleMapping"); + return; + } + + index++; + continue; + } + + const std::string* remoteGroup = nullptr; + nlohmann::json::const_iterator remoteGroupIt = + thisJson.find("RemoteGroup"); + + // extract "RemoteGroup" and "LocalRole" form JSON + if (remoteGroupIt != thisJson.end()) + { + remoteGroup = remoteGroupIt->get_ptr<const std::string*>(); + } + + const std::string* localRole = nullptr; + nlohmann::json::const_iterator localRoleIt = thisJson.find("LocalRole"); + if (localRoleIt != thisJson.end()) + { + localRole = localRoleIt->get_ptr<const std::string*>(); + } + + // Update existing RoleMapping Object + if (roleMapObjData.size() >= input.size()) + { + BMCWEB_LOG_DEBUG << "setRoleMappingProperties: Updating Object"; + // If "RemoteGroup" info is provided + if (remoteGroup != nullptr) + { + if (remoteGroup->empty()) + { + messages::propertyValueTypeError( + asyncResp->res, thisJson.dump(), "RemoteGroup"); + return; + } + // check if the given data is not equal to already existing one + else if (roleMapObjData.at(index).second.groupName.compare( + *remoteGroup) != 0) + { + setRoleMappingProperty(asyncResp, + roleMapObjData.at(index).first, + "RemoteGroup", "GroupName", + *remoteGroup, serverType, index); + } + } + + // If "LocalRole" info is provided + if (localRole != nullptr) + { + if (localRole->empty()) + { + messages::propertyValueTypeError( + asyncResp->res, thisJson.dump(), "LocalRole"); + return; + } + // check if the given data is not equal to already existing one + else if (roleMapObjData.at(index).second.privilege.compare( + *localRole) != 0) + { + setRoleMappingProperty( + asyncResp, roleMapObjData.at(index).first, "LocalRole", + "Privilege", *localRole, serverType, index); + } + } + index++; + } + // Create a new RoleMapping Object. + else + { + BMCWEB_LOG_DEBUG << "setRoleMappingProperties: Creating new Object"; + if (localRole == nullptr || remoteGroup == nullptr) + { + messages::propertyValueTypeError(asyncResp->res, + thisJson.dump(), + "RemoteGroup or LocalRole"); + return; + } + else if (remoteGroup->empty() || localRole->empty()) + { + messages::propertyValueTypeError( + asyncResp->res, thisJson.dump(), "RemoteGroup LocalRole"); + return; + } + + std::string dbusObjectPath; + if (serverType == "ActiveDirectory") + { + dbusObjectPath = ADConfigObject; + } + else if (serverType == "LDAP") + { + dbusObjectPath = ldapConfigObject; + } + + crow::connections::systemBus->async_method_call( + [asyncResp, serverType, index, localRole{std::move(*localRole)}, + remoteGroup{std::move(*remoteGroup)}]( + const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "DBUS response error: " << ec; + messages::internalError(asyncResp->res); + } + nlohmann::json& remoteRoleJson = + asyncResp->res + .jsonValue[serverType]["RemoteRoleMapping"][index]; + remoteRoleJson["LocalRole"] = localRole; + remoteRoleJson["RemoteGroup"] = remoteGroup; + }, + ldapDbusService, dbusObjectPath, ldapPrivMapperInterface, + "Create", *remoteGroup, getPrivilegeFromRoleId(*localRole)); + index++; + } + } +} + +/** * Function that retrieves all properties for LDAP config object * into JSON */ @@ -699,12 +938,14 @@ class AccountService : public Node std::optional<std::string> groupsAttribute; std::optional<std::string> userName; std::optional<std::string> password; + std::optional<nlohmann::json> remoteRoleMapData; if (!json_util::readJson(input, asyncResp->res, "Authentication", authentication, "LDAPService", ldapService, "ServiceAddresses", serviceAddressList, "AccountProviderType", accountProviderType, - "ServiceEnabled", serviceEnabled)) + "ServiceEnabled", serviceEnabled, + "RemoteRoleMapping", remoteRoleMapData)) { return; } @@ -745,7 +986,8 @@ class AccountService : public Node // nothing to update, then return if (!userName && !password && !serviceAddressList && !baseDNList && - !userNameAttribute && !groupsAttribute && !serviceEnabled) + !userNameAttribute && !groupsAttribute && !serviceEnabled && + !remoteRoleMapData) { return; } @@ -756,7 +998,7 @@ class AccountService : public Node baseDNList, userNameAttribute, groupsAttribute, accountProviderType, serviceAddressList, serviceEnabled, - dbusObjectPath]( + dbusObjectPath, remoteRoleMapData]( bool success, LDAPConfigData confData, const std::string& serverType) { if (!success) @@ -823,9 +1065,15 @@ class AccountService : public Node handleServiceEnablePatch(confData.serviceEnabled, asyncResp, serverType, dbusObjectPath); } + + if (remoteRoleMapData) + { + + handleRoleMapPatch(asyncResp, confData.groupRoleList, + serverType, *remoteRoleMapData); + } }); } - void doGet(crow::Response& res, const crow::Request& req, const std::vector<std::string>& params) override { |