Mutual TLS parsing change at runtime

Redfish AccountService[1] defines methods for selecting how to map a
certificate CommonName attribute to a user.  These are intended to be a
patch parameter.

This commit implements the Redfish defined schemas;  The parsing mode is
stored in the bmcweb persistent configuration file as an integer enum,
with Mapping to the Redfish schema.

To handle OEM specific parsing modes, an enum value of 100+ is defined
to allow the additional OEM parameters.  Unfortunately, Redfish doesn't
have a way to represent these today, so those modes are currently not
selectable at runtime.

Now that things are runtime selectable, this obsoletes the option
mutual-tls-common-name-parsing, as it is not longer required at compile
time.

Tested:
GET /redfish/v1/AccountService

returns MultiFactorAuth/ClientCertificate/CertificateMappingAttribute

PATCH /redfish/v1/AccountService
```
{"MultiFactorAuth": {"ClientCertificate": {"CertificateMappingAttribute":"CommonName"}}}
```

Returns 200

[1] https://github.com/DMTF/Redfish-Publications/blob/5b217908b5378b24e4f390c063427d7a707cd308/csdl/AccountService_v1.xml#L1631

Change-Id: I67db0dfa5245a9da973320aab666d12dbd9229e4
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index 05cfbe7..b3b848f 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -1257,6 +1257,45 @@
     getClientCertificates(asyncResp, "/Members"_json_pointer);
 }
 
+using account_service::CertificateMappingAttribute;
+using persistent_data::MTLSCommonNameParseMode;
+inline CertificateMappingAttribute
+    getCertificateMapping(MTLSCommonNameParseMode parse)
+{
+    switch (parse)
+    {
+        case MTLSCommonNameParseMode::CommonName:
+        {
+            return CertificateMappingAttribute::CommonName;
+        }
+        break;
+        case MTLSCommonNameParseMode::Whole:
+        {
+            return CertificateMappingAttribute::Whole;
+        }
+        break;
+        case MTLSCommonNameParseMode::UserPrincipalName:
+        {
+            return CertificateMappingAttribute::UserPrincipalName;
+        }
+        break;
+
+        case MTLSCommonNameParseMode::Meta:
+        {
+            if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING)
+            {
+                return CertificateMappingAttribute::CommonName;
+            }
+        }
+        break;
+        default:
+        {
+            return CertificateMappingAttribute::Invalid;
+        }
+        break;
+    }
+}
+
 inline void
     handleAccountServiceGet(App& app, const crow::Request& req,
                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
@@ -1301,8 +1340,19 @@
     nlohmann::json::object_t clientCertificate;
     clientCertificate["Enabled"] = authMethodsConfig.tls;
     clientCertificate["RespondToUnauthenticatedClients"] = true;
-    clientCertificate["CertificateMappingAttribute"] =
-        account_service::CertificateMappingAttribute::CommonName;
+
+    using account_service::CertificateMappingAttribute;
+
+    CertificateMappingAttribute mapping =
+        getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode);
+    if (mapping == CertificateMappingAttribute::Invalid)
+    {
+        messages::internalError(asyncResp->res);
+    }
+    else
+    {
+        clientCertificate["CertificateMappingAttribute"] = mapping;
+    }
     nlohmann::json::object_t certificates;
     certificates["@odata.id"] =
         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates";
@@ -1400,6 +1450,24 @@
     getLDAPConfigData("ActiveDirectory", callback);
 }
 
+inline void
+    handleCertificateMappingAttributePatch(crow::Response& res,
+                                           const std::string& certMapAttribute)
+{
+    MTLSCommonNameParseMode parseMode =
+        persistent_data::getMTLSCommonNameParseMode(certMapAttribute);
+    if (parseMode == MTLSCommonNameParseMode::Invalid)
+    {
+        messages::propertyValueNotInList(res, "CertificateMappingAttribute",
+                                         certMapAttribute);
+        return;
+    }
+
+    persistent_data::AuthConfigMethods& authMethodsConfig =
+        persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
+    authMethodsConfig.mTLSCommonNameParsingMode = parseMode;
+}
+
 inline void handleAccountServicePatch(
     App& app, const crow::Request& req,
     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
@@ -1413,9 +1481,11 @@
     std::optional<uint8_t> minPasswordLength;
     std::optional<uint16_t> maxPasswordLength;
     LdapPatchParams ldapObject;
+    std::optional<std::string> certificateMappingAttribute;
     LdapPatchParams activeDirectoryObject;
     AuthMethods auth;
     std::optional<std::string> httpBasicAuth;
+
     // clang-format off
     if (!json_util::readJsonPatch(
             req, asyncResp->res,
@@ -1430,6 +1500,7 @@
             "ActiveDirectory/RemoteRoleMapping", activeDirectoryObject.remoteRoleMapData,
             "ActiveDirectory/ServiceAddresses", activeDirectoryObject.serviceAddressList,
             "ActiveDirectory/ServiceEnabled", activeDirectoryObject.serviceEnabled,
+            "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute", certificateMappingAttribute,
             "LDAP/Authentication/AuthenticationType", ldapObject.authType,
             "LDAP/Authentication/Password", ldapObject.password,
             "LDAP/Authentication/Username", ldapObject.userName,
@@ -1469,6 +1540,12 @@
         }
     }
 
+    if (certificateMappingAttribute)
+    {
+        handleCertificateMappingAttributePatch(asyncResp->res,
+                                               *certificateMappingAttribute);
+    }
+
     if (minPasswordLength)
     {
         setDbusProperty(