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"
}
],
15. Try to delete the role map when there was no role map entry and get the following error.
"RemoteRoleMapping/1@Message.ExtendedInfo": [
{
"@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
"Message": "The value null for the property RemoteRoleMapping/0 is of a different type than the property can accept.",
"MessageArgs": [
"null",
"RemoteRoleMapping/0"
],
"MessageId": "Base.1.4.0.PropertyValueTypeError",
"Resolution": "Correct the value for the property in the request body and resubmit the request if the operation failed.",
"Severity": "Warning"
}
Signed-off-by: Ratan Gupta <ratagupt@linux.vnet.ibm.com>
Change-Id: Iaa37221bd6fdc87dbf51755d9425ecd5b07eee6c
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index f1a83a9..9dac7e4 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -37,6 +37,8 @@
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,178 @@
}
/**
+ * @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, std::vector<nlohmann::json>& input)
+{
+ for (size_t index = 0; index < input.size(); index++)
+ {
+ nlohmann::json& thisJson = input[index];
+
+ if (thisJson.is_null())
+ {
+ // delete the existing object
+ if (index < roleMapObjData.size())
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, roleMapObjData, 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, roleMapObjData[index].first,
+ "xyz.openbmc_project.Object.Delete", "Delete");
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR << "Can't delete the object";
+ messages::propertyValueTypeError(
+ asyncResp->res, thisJson.dump(),
+ "RemoteRoleMapping/" + std::to_string(index));
+ return;
+ }
+ }
+ else if (thisJson.empty())
+ {
+ // Don't do anything for the empty objects,parse next json
+ // eg {"RemoteRoleMapping",[{}]}
+ }
+ else
+ {
+ // update/create the object
+ std::optional<std::string> remoteGroup;
+ std::optional<std::string> localRole;
+
+ if (!json_util::readJson(thisJson, asyncResp->res, "RemoteGroup",
+ remoteGroup, "LocalRole", localRole))
+ {
+ continue;
+ }
+
+ // Update existing RoleMapping Object
+ if (index < roleMapObjData.size())
+ {
+ BMCWEB_LOG_DEBUG << "Update Role Map Object";
+ // If "RemoteGroup" info is provided
+ if (remoteGroup)
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, roleMapObjData, serverType, index,
+ remoteGroup](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]["RemoteGroup"] = *remoteGroup;
+ },
+ ldapDbusService, roleMapObjData[index].first,
+ propertyInterface, "Set",
+ "xyz.openbmc_project.User.PrivilegeMapperEntry",
+ "GroupName",
+ std::variant<std::string>(std::move(*remoteGroup)));
+ }
+
+ // If "LocalRole" info is provided
+ if (localRole)
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, roleMapObjData, serverType, index,
+ localRole](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]["LocalRole"] = *localRole;
+ },
+ ldapDbusService, roleMapObjData[index].first,
+ propertyInterface, "Set",
+ "xyz.openbmc_project.User.PrivilegeMapperEntry",
+ "Privilege",
+ std::variant<std::string>(
+ getPrivilegeFromRoleId(std::move(*localRole))));
+ }
+ }
+ // Create a new RoleMapping Object.
+ else
+ {
+ BMCWEB_LOG_DEBUG
+ << "setRoleMappingProperties: Creating new Object";
+ std::string pathString =
+ "RemoteRoleMapping/" + std::to_string(index);
+
+ if (!localRole)
+ {
+ messages::propertyMissing(asyncResp->res,
+ pathString + "/LocalRole");
+ continue;
+ }
+ if (!remoteGroup)
+ {
+ messages::propertyMissing(asyncResp->res,
+ pathString + "/RemoteGroup");
+ continue;
+ }
+
+ std::string dbusObjectPath;
+ if (serverType == "ActiveDirectory")
+ {
+ dbusObjectPath = ADConfigObject;
+ }
+ else if (serverType == "LDAP")
+ {
+ dbusObjectPath = ldapConfigObject;
+ }
+
+ BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
+ << ",LocalRole=" << *localRole;
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, serverType, index, localRole,
+ remoteGroup](const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ nlohmann::json& remoteRoleJson =
+ asyncResp->res
+ .jsonValue[serverType]["RemoteRoleMapping"];
+ remoteRoleJson.push_back(
+ {{"LocalRole", *localRole},
+ {"RemoteGroup", *remoteGroup}});
+ },
+ ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
+ "Create", std::move(*remoteGroup),
+ getPrivilegeFromRoleId(std::move(*localRole)));
+ }
+ }
+ }
+}
+
+/**
* Function that retrieves all properties for LDAP config object
* into JSON
*/
@@ -699,12 +873,14 @@
std::optional<std::string> groupsAttribute;
std::optional<std::string> userName;
std::optional<std::string> password;
+ std::optional<std::vector<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 +921,8 @@
// nothing to update, then return
if (!userName && !password && !serviceAddressList && !baseDNList &&
- !userNameAttribute && !groupsAttribute && !serviceEnabled)
+ !userNameAttribute && !groupsAttribute && !serviceEnabled &&
+ !remoteRoleMapData)
{
return;
}
@@ -756,7 +933,7 @@
baseDNList, userNameAttribute,
groupsAttribute, accountProviderType,
serviceAddressList, serviceEnabled,
- dbusObjectPath](
+ dbusObjectPath, remoteRoleMapData](
bool success, LDAPConfigData confData,
const std::string& serverType) {
if (!success)
@@ -823,6 +1000,15 @@
handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
serverType, dbusObjectPath);
}
+
+ if (remoteRoleMapData)
+ {
+ std::vector<nlohmann::json> remoteRoleMap =
+ std::move(*remoteRoleMapData);
+
+ handleRoleMapPatch(asyncResp, confData.groupRoleList,
+ serverType, remoteRoleMap);
+ }
});
}